Root/include/iris.hhp

1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// iris.hhp: header file for userspace programs.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#ifndef __IRIS_HHP
20#define __IRIS_HHP
21
22// Without the standard library, we don't have this definition.
23// I preferred ((void*)0), but C++ has too strict type-checking to
24// make that work.
25#ifndef NULL
26#define NULL 0
27#endif
28
29// Number of clock interrupts per second.
30#define HZ 100
31
32#define PAGE_BITS (12)
33#define PAGE_SIZE (1 << PAGE_BITS)
34#define PAGE_MASK (~(PAGE_SIZE - 1))
35
36#define KERNEL_MASK 0xfff
37#define CAPTYPE_MASK 0xe00
38#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
39#define CAPTYPE_INVALID 0x000
40#define CAPTYPE_RECEIVER 0x200
41#define CAPTYPE_MEMORY 0x400
42#define CAPTYPE_THREAD 0x600
43#define CAPTYPE_PAGE 0x800
44#define CAPTYPE_CAPS 0xa00
45#define CAPTYPE_LIST 0xc00
46#define CAPTYPE_LISTITEM 0xe00
47
48// All kernel capabilities have a master capability, which can create others.
49#define CAP_MASTER 0
50
51// Create, invoke and forget, with masked data set to 0.
52#define CAP_MASTER_DIRECT 0
53// Master capabilities can create others.
54#define CAP_MASTER_CREATE (1 << 31)
55
56#define __caps_num 0
57#define __receiver_num 1
58#define __thread_num 2
59#define __memory_num 3
60#define __call_num 4
61#define __parent_num 5
62
63// If this flag is set in a capability, it is copied instead of mapped.
64// If it is set in the target capability, the Thread waits after the request.
65#define CAP_COPY ((unsigned)0x80000000)
66// This constant signifies that no capability is passed.
67#define CAP_NONE (~CAP_COPY)
68
69namespace Iris:
70    struct Parent
71    enum Exception_code:
72        NO_ERROR
73        ERR_WRITE_DENIED
74        ERR_UNMAPPED_READ
75        ERR_UNMAPPED_WRITE
76        ERR_INVALID_ADDRESS_READ
77        ERR_INVALID_ADDRESS_WRITE
78        ERR_RESERVED_INSTRUCTION
79        ERR_COPROCESSOR_UNUSABLE
80        ERR_OVERFLOW
81        ERR_TRAP
82        ERR_WATCHPOINT
83        ERR_BREAKPOINT
84        ERR_NO_PAGE_DIRECTORY
85        ERR_NO_PAGE_TABLE
86        ERR_OUT_OF_MEMORY
87        // The following are not raised, but returned.
88        ERR_INVALID_OPERATION
89        ERR_INVALID_ARGUMENT
90        NUM_EXCEPTION_CODES
91
92    #ifndef NDEBUG
93    static inline const char *exception_name(int code):
94        const char *names[] = {
95            "no error",
96            "write denied",
97            "unmapped read",
98            "unmapped write",
99            "invalid address read",
100            "invalid address write",
101            "reserved instruction",
102            "coprocessor unusable",
103            "overflow",
104            "trap",
105            "watchpoint",
106            "breakpoint",
107            "no page directory",
108            "no page table",
109            "out of memory",
110            "invalid operation"
111         }
112        return names[code]
113    #endif
114
115    struct Num:
116        unsigned l, h
117        inline Num (unsigned long long n = 0) : l (n), h (n >> 32):
118        inline Num (unsigned ll, unsigned hh) : l (ll), h (hh):
119        inline unsigned long long value () const:
120            return ((unsigned long long)h << 32) | l
121        inline unsigned &low ():
122            return l
123        inline unsigned &high ():
124            return h
125        inline unsigned const &low () const:
126            return l
127        inline unsigned const &high () const:
128            return h
129
130    struct Cap
131    struct Caps
132    struct Receiver
133    struct Thread
134    struct Page
135    struct Memory
136    struct List
137
138    void print_caps ()
139    unsigned alloc_slot ()
140    Cap alloc_cap ()
141    void free_slot (unsigned slot)
142    void free_cap (Cap cap)
143    extern bool enable_debug
144
145    struct Cap:
146        unsigned code
147        inline Cap copy () const
148        inline Cap ()
149        explicit inline Cap (unsigned c)
150        inline Cap (unsigned slot, unsigned idx)
151        inline unsigned slot () const
152        inline unsigned idx () const
153        struct IMessage
154        inline void invoke (Num d0 = 0, Num d1 = 0, Cap arg = Cap (CAP_NONE))
155        inline Num call (Num d0 = 0, Num d1 = 0)
156        inline Num icall (Num d0 = 0, Num d1 = 0)
157        inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0)
158        inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0)
159        inline void _invoke (IMessage const *i)
160        inline void _call (IMessage *i)
161
162    struct __recv_data_t:
163        Num data[2]
164        Num protected_data
165        Cap reply, arg
166
167    extern Caps my_caps
168    extern Receiver my_receiver
169    extern Thread my_thread
170    extern Memory my_memory
171    extern Cap my_call
172    extern Parent my_parent
173    extern __recv_data_t recv
174
175    inline Cap get_reply ():
176        Cap ret = recv.reply
177        recv.reply = alloc_cap ()
178        return ret
179    inline Cap get_arg ():
180        Cap ret = recv.arg
181        recv.arg = alloc_cap ()
182        return ret
183    inline void set_recv_arg (Cap c):
184        free_cap (recv.arg)
185        recv.arg = c
186
187    struct Cap::IMessage:
188        Num data[2]
189        Cap reply, arg
190    Cap Cap::copy () const:
191        return Cap (code | CAP_COPY)
192    Cap::Cap () : code (CAP_NONE):
193    Cap::Cap (unsigned c) : code (c):
194    Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)):
195    unsigned Cap::slot () const:
196        return (code >> 16) & 0x7fff
197    unsigned Cap::idx () const:
198        return code & 0xffff
199    void Cap::_invoke (IMessage const *i):
200        __recv_data_t *r = &recv
201        __asm__ volatile ("lw $v0, %1\n"
202                "\tlw $a0, 0($v0)\n"
203                "\tlw $a1, 4($v0)\n"
204                "\tlw $a2, 8($v0)\n"
205                "\tlw $a3, 12($v0)\n"
206                "\tlw $t0, 16($v0)\n"
207                "\tlw $t1, 20($v0)\n"
208                "\tlw $v0, %2\n"
209                "\tlw $t2, 24($v0)\n"
210                "\tlw $t3, 28($v0)\n"
211                "\tlw $v0, %0\n"
212                "\tsyscall\n"
213                "\tlw $v0, %2\n"
214                "\tsw $a0, 0($v0)\n"
215                "\tsw $a1, 4($v0)\n"
216                "\tsw $a2, 8($v0)\n"
217                "\tsw $a3, 12($v0)\n"
218                "\tsw $t0, 16($v0)\n"
219                "\tsw $t1, 20($v0)"
220                :: "m"(code), "m"(i), "m"(r)
221                : "memory", "v0", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3")
222    void Cap::_call (IMessage *i):
223        i->reply = *this
224        my_call.copy ()._invoke (i)
225    void Cap::invoke (Num d0, Num d1, Cap arg):
226        IMessage i
227        i.data[0] = d0
228        i.data[1] = d1
229        i.reply = Cap (CAP_NONE)
230        i.arg = arg
231        _invoke (&i)
232    Num Cap::call (Num d0, Num d1):
233        IMessage i
234        i.data[0] = d0
235        i.data[1] = d1
236        i.arg = Cap (CAP_NONE)
237        _call (&i)
238        return recv.data[0]
239    Num Cap::icall (Num d0, Num d1):
240        IMessage i
241        i.data[0] = d0
242        i.data[1] = d1
243        i.arg = Cap (CAP_NONE)
244        _call (&i)
245        return recv.data[0]
246    Num Cap::ocall (Cap c, Num d0, Num d1):
247        IMessage i
248        i.data[0] = d0
249        i.data[1] = d1
250        i.arg = c
251        _call (&i)
252        return recv.data[0]
253    Num Cap::iocall (Cap c, Num d0, Num d1):
254        IMessage i
255        i.data[0] = d0
256        i.data[1] = d1
257        i.arg = c
258        _call (&i)
259        return recv.data[0]
260
261    struct Receiver : public Cap:
262        Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
263        Receiver (Cap c = Cap ()) : Cap (c):
264        enum request:
265            // Operations
266            SET_OWNER = CAPTYPE_RECEIVER + 1
267            CREATE_CAPABILITY
268            CREATE_CALL_CAPABILITY
269            CREATE_ASYNC_CALL_CAPABILITY
270            GET_PROTECTED
271            GET_REPLY_PROTECTED_DATA
272            SET_REPLY_PROTECTED_DATA
273            GET_ALARM
274            SET_ALARM
275            ADD_ALARM
276            // Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability.
277            REPLY
278            // A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY.
279            CALL
280            // A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY.
281            CALL_ASYNC
282        void set_owner (Cap owner):
283            ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
284        Cap create_capability (Num protected_data):
285            icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
286            return get_arg ()
287        Num get_protected (Cap target):
288            return ocall (target, CAP_MASTER_DIRECT | GET_PROTECTED)
289        Num get_reply_protected_data ():
290            return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
291        void set_reply_protected_data (Num data):
292            call (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data)
293        unsigned get_alarm ():
294            return call (CAP_MASTER_DIRECT | GET_ALARM).l
295        unsigned add_alarm (unsigned data):
296            return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
297        void set_alarm (unsigned data):
298            call (CAP_MASTER_DIRECT | SET_ALARM, data)
299        inline void sleep (unsigned value)
300        Cap create_call_capability ():
301            icall (CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
302            return get_arg ()
303        Cap create_async_call_capability ():
304            icall (CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
305            return get_arg ()
306
307    struct Thread : public Cap:
308        Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
309        Thread (Cap c = Cap ()) : Cap (c):
310        enum request:
311            // Info details are arch-specific.
312            GET_INFO = CAPTYPE_THREAD + 1
313            SET_INFO
314            USE_SLOT
315            GET_CAPS
316            SCHEDULE
317            PRIV_ALLOC_RANGE
318            PRIV_PHYSICAL_ADDRESS
319            PRIV_ALLOC_PHYSICAL
320            PRIV_MAKE_PRIV
321            PRIV_GET_TOP_MEMORY
322            PRIV_REGISTER_INTERRUPT
323            // This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
324            SET_OWNER
325            DBG_SEND
326            PRIV_REBOOT
327            PRIV_POWEROFF
328            PRIV_SUSPEND
329            PRIV_BOOT
330            PRIV_PANIC
331        // These get/set_info are not arch-specific.
332        enum info_type:
333            PC = ~0
334            SP = ~1
335            FLAGS = ~2
336            // These are arch-specific.
337            AT = 1
338            V0
339            V1
340            A0
341            A1
342            A2
343            A3
344            T0
345            T1
346            T2
347            T3
348            T4
349            T5
350            T6
351            T7
352            S0
353            S1
354            S2
355            S3
356            S4
357            S5
358            S6
359            S7
360            T8
361            T9
362            K0
363            K1
364            GP
365            SP_
366            FP
367            RA
368        enum flags:
369            PRIV = 1 << 31
370            WAITING = 1 << 30
371            RUNNING = 1 << 29
372            USER_FLAGS = ~(PRIV | WAITING | RUNNING)
373        void make_priv ():
374            my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV)
375        unsigned get_info (unsigned info):
376            return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l
377        void set_info (unsigned info, unsigned value, unsigned mask = ~0):
378            call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask))
379        void set_pc (unsigned pc):
380            set_info (PC, pc)
381        void set_sp (unsigned sp):
382            set_info (SP, sp)
383        void set_flags (unsigned set, unsigned reset = 0):
384            set_info (FLAGS, set, set | reset)
385        unsigned get_pc ():
386            return get_info (PC)
387        unsigned get_sp ():
388            return get_info (SP)
389        unsigned get_flags ():
390            return get_info (FLAGS)
391        void run (bool run = true):
392            set_flags (run ? RUNNING : 0, run ? 0 : RUNNING)
393        void wait (bool wait):
394            set_flags (wait ? WAITING : 0, wait ? 0 : WAITING)
395        inline unsigned use (Caps caps, unsigned slot = alloc_slot ())
396        inline Caps get_caps (unsigned slot)
397        unsigned get_num_caps ():
398            return call (CAP_MASTER_DIRECT | GET_CAPS, ~0).l
399
400    struct Caps : public Cap:
401        Caps (unsigned slot, unsigned idx) : Cap (slot, idx):
402        Caps (Cap c = Cap ()) : Cap (c):
403        enum request:
404            // Not an operation; this capability can be used in Thread::USE_SLOT.
405            USE = CAPTYPE_CAPS + 1
406            GET
407            GET_SIZE
408            SET
409            TRUNCATE
410            PRINT
411        unsigned use (unsigned slot = alloc_slot ()):
412            return my_thread.use (*this, slot)
413        Cap get (unsigned idx):
414            call (CAP_MASTER_DIRECT | GET, idx)
415            return get_arg ()
416        unsigned get_size ():
417            return call (CAP_MASTER_DIRECT | GET_SIZE).l
418        void set (unsigned idx, Cap cap):
419            ocall (cap, CAP_MASTER_DIRECT | SET, idx)
420        void truncate (unsigned new_size):
421            call (CAP_MASTER_DIRECT | TRUNCATE, new_size)
422        void print (unsigned idx):
423            invoke (CAP_MASTER_DIRECT | PRINT, idx)
424
425    Caps Thread::get_caps (unsigned slot):
426        call (CAP_MASTER_DIRECT | GET_CAPS, slot)
427        return get_arg ()
428
429    unsigned Thread::use (Caps caps, unsigned slot):
430        ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot)
431        return slot
432
433    struct Page : public Cap:
434        Page (unsigned slot, unsigned idx) : Cap (slot, idx):
435        Page (Cap c = Cap ()) : Cap (c):
436        enum request:
437            SHARE = CAPTYPE_PAGE + 1
438            GET_FLAGS
439            SET_FLAGS
440            // Not an operation; a capability with this bit cannot write to the page.
441            READONLY = 8
442        enum share_detail:
443            // Operation details for PAGE_SHARE
444            // Forget the source page during the operation. This makes it a move.
445            FORGET = 1
446            // Make the target independent of the source (make a copy if needed).
447            COPY = 2
448            // Make the target unwritable.
449            //READONLY: use the value from request.
450        enum flag_values:
451            // This is a read-only flag, which is set if the Page is shared.
452            SHARED = 1
453            // When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them.
454            PAYING = 2
455            // Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems.
456            FRAME = 4
457            // A readonly page cannot be written to. This flag can not be reset while the frame is shared. The flag is already defined in request.
458            //READONLY = 8
459            // If this flag is set, the page is or will be mapped read-only.
460            MAPPED_READONLY = 0x10
461            // This is a read-only flag, saying if this is physical memory, which mustn't be freed.
462            PHYSICAL = 0x20
463            // This is a read-only flag, saying if this is uncachable memory.
464            UNCACHED = 0x40
465        void share (Cap target, unsigned flags = 0):
466            ocall (target, Num (CAP_MASTER_DIRECT | SHARE, flags))
467        unsigned get_flags ():
468            return call (CAP_MASTER_DIRECT | GET_FLAGS).l
469        bool set_flags (unsigned set, unsigned reset = 0):
470            call (CAP_MASTER_DIRECT | SET_FLAGS, Num (set, set | reset))
471            return recv.data[0].l == NO_ERROR
472        unsigned long physical_address ():
473            return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
474        void alloc_physical (unsigned long address, bool cachable, bool freeable):
475            my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
476
477    struct Listitem : public Cap:
478        Listitem (Cap c = Cap ()) : Cap (c):
479        enum request:
480            CLEAR = CAPTYPE_LISTITEM + 1
481            SET_CAP
482            ADD
483            LIST
484        // Remove the listitem from its list.
485        void clear ():
486            call (CAP_MASTER_DIRECT | CLEAR)
487        // Set the capability of an item.
488        void set_cap (Cap c):
489            call (CAP_MASTER_DIRECT | SET_CAP, c.code)
490        // To add a listitem to a list, the listitem capability must be of type ADD or MASTER.
491        // A list iterator must be of type LIST or MASTER
492
493    struct List : public Cap:
494        List (Cap c = Cap ()) : Cap (c):
495        enum request:
496            GET_NEXT = CAPTYPE_LIST + 1
497            SET_CB
498            ADD_ITEM
499            GET_INFO
500            SET_INFO
501            GET_CAP
502        // Get the next listitem from the given one. Use this to loop over all listitems.
503        Listitem get_next (Listitem current = Listitem ()):
504            iocall (current, CAP_MASTER_DIRECT | GET_NEXT)
505            if recv.data[0].l:
506                return Cap ()
507            return get_arg ()
508        // Set the callback. This is called when an item is removed from the list.
509        // When called, data[0] is 0 when the list is now empty; 1 otherwise. data[1] is the removed item's info.
510        void set_cb (Cap cb):
511            ocall (cb, CAP_MASTER_DIRECT | SET_CB)
512        // Add an item to the front of the list.
513        void add_item (Listitem item):
514            ocall (item, CAP_MASTER_DIRECT | ADD_ITEM)
515        // Return item info.
516        Num get_info (Listitem item):
517            return ocall (item, CAP_MASTER_DIRECT | GET_INFO)
518        // Set item info.
519        void set_info (Listitem item, Num info):
520            ocall (item, CAP_MASTER_DIRECT | SET_INFO, info)
521        // Get item capability.
522        Cap get_cap (Listitem item):
523            iocall (item, CAP_MASTER_DIRECT | GET_CAP)
524            return get_arg ()
525
526    struct Memory : public Cap:
527        Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
528        Memory (Cap c = Cap ()) : Cap (c):
529        enum request:
530            CREATE = CAPTYPE_MEMORY + 1
531            DESTROY
532            LIST
533            MAP
534            MAPPING
535            GET_LIMIT
536            SET_LIMIT
537        Page create_page ():
538            icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
539            return get_arg ()
540        Thread create_thread (unsigned slots):
541            icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
542            return get_arg ()
543        Receiver create_receiver ():
544            icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
545            return get_arg ()
546        Memory create_memory ():
547            icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
548            return get_arg ()
549        Caps create_caps (unsigned size):
550            icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
551            return get_arg ()
552        List create_list ():
553            icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_LIST))
554            return get_arg ()
555        Listitem create_listitem ():
556            icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_LISTITEM))
557            return get_arg ()
558        void destroy (Cap target):
559            ocall (target, CAP_MASTER_DIRECT | DESTROY)
560        // TODO: LIST
561        bool map (Cap page, unsigned long address):
562            return ocall (page, CAP_MASTER_DIRECT | MAP, address).l == NO_ERROR
563        bool unmap (Cap page):
564            return map (page, ~0)
565        Page mapping (void *address):
566            icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned long)address))
567            return get_arg ()
568        unsigned get_limit ():
569            return call (CAP_MASTER_DIRECT | GET_LIMIT).l
570        void set_limit (unsigned limit):
571            call (CAP_MASTER_DIRECT | SET_LIMIT, limit)
572        unsigned alloc_range (unsigned pages):
573            return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l
574
575    inline void wait ():
576        Cap::IMessage i
577        Cap ().copy ()._invoke (&i)
578    inline void schedule ():
579        my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE)
580    inline void register_interrupt (unsigned num):
581        my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
582    inline void unregister_interrupt (unsigned num):
583        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
584    inline unsigned wait_for_interrupt ():
585        my_receiver.set_reply_protected_data (0)
586        Cap ().call ()
587        unsigned ret = recv.data[0].l
588        my_receiver.set_reply_protected_data (~0)
589        return ret
590    inline Cap get_top_memory ():
591        my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
592        return get_arg ()
593    inline void dbg_send (unsigned code, unsigned bits = 32):
594        my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits))
595    inline void reboot ():
596        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT)
597    inline void poweroff ():
598        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_POWEROFF)
599    inline void suspend ():
600        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_SUSPEND)
601    inline void boot (unsigned address, unsigned arg):
602        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_BOOT, Iris::Num (address, arg))
603
604    void Receiver::sleep (unsigned value):
605        set_alarm (value)
606        Cap ().call ()
607    inline void sleep (unsigned value):
608        my_receiver.sleep (value)
609
610// The start function has this prototype (there is no main function).
611Iris::Num start ()
612
613#ifndef __KERNEL__
614#ifndef __NATIVE__
615#if 1
616// Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing.
617#define kdebug_char(_c) do { unsigned _d = (_c); __asm__ volatile ("move $a0, $zero\nlw $a1, %0\nbreak" :: "m"(_d) : "a0", "a1", "memory"); } while (0)
618#else
619#define kdebug_char(_c) do {} while (0)
620#endif
621#define kdebug(str) do { const char *s = (str); while (*s) { kdebug_char (*s); ++s; } } while (0)
622#define __stringify2(x) #x
623#define __stringify(x) __stringify2 (x)
624#define kdebug_line() do { kdebug (__FILE__ ":"); kdebug (__PRETTY_FUNCTION__); kdebug (":"); kdebug (__stringify (__LINE__)); kdebug_char ('\n'); } while (0)
625
626static void kdebug_num (unsigned n, unsigned digits = 8):
627    unsigned i
628    char const *encode = "0123456789abcdef"
629    for i = 0; i < digits; ++i:
630        kdebug_char (encode[(n >> (4 * ((digits - 1) - i))) & 0xf])
631
632namespace Iris:
633    inline void panic (unsigned code, char const *message = NULL):
634        if message:
635            kdebug_num (code)
636            kdebug_char ('\n')
637            kdebug (message)
638            kdebug_char ('\n')
639        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code)
640        if code == 0xdeaddead:
641            return
642        while true:
643            wait ()
644
645    inline void debug_num (unsigned num, unsigned base):
646        char const *encode = "0123456789abcdef"
647        unsigned digits = 1
648        unsigned power = 1
649        while power <= num / base:
650            power *= base
651            ++digits
652        for unsigned i = 0; i < digits; ++i:
653            unsigned d = num / power
654            kdebug_char (encode[d])
655            num -= d * power
656            power /= base
657
658    inline void debug (const char *f, ...):
659        unsigned *last = (unsigned *)&f
660        while *f:
661            if *f == '%':
662                ++f
663                switch *f:
664                    case '%':
665                        kdebug_char ('%')
666                        break
667                    case 'd':
668                        ++last
669                        debug_num (*last, 10)
670                        break
671                    case 'x':
672                        ++last
673                        debug_num (*last, 0x10)
674                        break
675                    case 's':
676                        ++last
677                        kdebug ((char *)*last)
678                        break
679                    case 'c':
680                        ++last
681                        kdebug_char (*last)
682                        break
683                    default:
684                        panic (*f, "invalid character in dbg format string")
685            else:
686                kdebug_char (*f)
687            ++f
688#else
689namespace Iris:
690    inline void panic(unsigned code, char const *message = NULL):
691    inline void debug_num (unsigned num, unsigned base):
692    inline void debug (const char *f, ...):
693#endif // !defined(__NATIVE__)
694#endif // !defined(__KERNEL__)
695#endif
696

Archive Download this file

Branches:
master



interactive