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

Archive Download this file

Branches:
master



interactive