From a838dd63c6a79df2d8a8431a46d03d2d848fc43b Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Sun, 6 Sep 2009 11:04:09 +0200 Subject: [PATCH] working with new invoke system --- alloc.ccp | 28 +- boot-programs/crt0.ccp | 101 ++--- boot-programs/devices.hhp | 108 ++--- boot-programs/gpio.ccp | 87 ++-- boot-programs/init.ccp | 56 ++- boot-programs/lcd.ccp | 52 +-- invoke.ccp | 514 ++++++++++++++---------- iris.hhp | 824 ++++++++++++++++++-------------------- kernel.hhp | 43 +- memory.ccp | 1 - mips/arch.ccp | 12 +- mips/init.ccp | 22 +- mips/interrupts.ccp | 64 ++- mips/jz4730.hhp | 12 +- panic.ccp | 6 +- schedule.ccp | 17 +- 16 files changed, 982 insertions(+), 965 deletions(-) diff --git a/alloc.ccp b/alloc.ccp index 5e5f209..f9841b0 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -195,9 +195,10 @@ kThread *kMemory::alloc_thread (unsigned size): return ret kMessage *kMemory::alloc_message (kReceiver *target): - kMessage *ret = (kMessage *)search_free (sizeof (kMessage), (void **)&target->messages) + kMessage *ret = (kMessage *)search_free (sizeof (kMessage) + sizeof (kCapability), (void **)&target->messages) if !ret: return NULL + ret->caps.size = 2 if !ret->next: target->last_message = ret return ret @@ -243,9 +244,9 @@ kMemory *kMemory::alloc_memory (): kMemory_arch_init (ret) return ret -void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr): +void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr): caps[index].target = target - caps[index].cap_protected = pdata + caps[index].protected_data = pdata caps[index].parent = parent caps[index].children.reset () caps[index].sibling_prev.reset () @@ -262,18 +263,21 @@ void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, k caps[index].sibling_next->sibling_prev = kCapRef (this, index) void kCaps::clone (unsigned index, kCapRef source, bool copy): + cap (index)->invalidate () + if !source.valid (): + return if copy: if source->parent.valid (): - set (index, source->target, source->cap_protected, source->parent) + set (index, source->target, source->protected_data, source->parent) else if (unsigned)source->target & ~KERNEL_MASK: - set (index, source->target, source->cap_protected, kCapRef (), &source->target->capabilities) + set (index, source->target, source->protected_data, kCapRef (), &source->target->capabilities) else: - set (index, source->target, source->cap_protected, kCapRef (), &((kObject *)source->cap_protected.l)->refs) + set (index, source->target, source->protected_data, kCapRef (), &((kObject *)source->protected_data.l)->refs) else: - set (index, source->target, source->cap_protected, source) + set (index, source->target, source->protected_data, source) void kMemory::free_page (kPage *page): - if page->flags & Page::PAYING: + if page->flags & Kernel::Page::PAYING: unuse () if page->frame: pfree (page->frame) @@ -324,7 +328,7 @@ void kCapability::invalidate (): else if (unsigned)target & ~KERNEL_MASK: target->capabilities = sibling_next else: - ((kObject *)cap_protected.l)->refs = sibling_next + ((kObject *)protected_data.l)->refs = sibling_next if sibling_next.valid (): sibling_next->sibling_prev = sibling_prev parent.reset () @@ -342,7 +346,7 @@ void kCapability::invalidate (): c->children.reset () c->sibling_prev.reset () c->sibling_next.reset () - c->cap_protected = 0 + c->protected_data = 0 c = next void kMemory::free_caps (kCaps *c): @@ -376,8 +380,8 @@ void kPage::forget (): share_next = NULL else: // If the page has a frame and should be freed, free it. - if !((flags ^ Page::FRAME) & (Page::PHYSICAL | Page::FRAME)): + if !((flags ^ Kernel::Page::FRAME) & (Kernel::Page::PHYSICAL | Kernel::Page::FRAME)): raw_pfree (frame) frame = 0 - flags &= ~(Page::FRAME | Page::SHARED | Page::PHYSICAL | Page::UNCACHED) + flags &= ~(Kernel::Page::FRAME | Kernel::Page::SHARED | Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED) kPage_arch_update_mapping (this) diff --git a/boot-programs/crt0.ccp b/boot-programs/crt0.ccp index ddc33ea..2d71f6e 100644 --- a/boot-programs/crt0.ccp +++ b/boot-programs/crt0.ccp @@ -28,46 +28,53 @@ static unsigned __slots, __caps static list *__slot_admin, *__cap_admin static list *__first_free_slot, *__first_free_cap -Receiver __my_receiver -Thread __my_thread -Memory __my_memory -Cap __my_call -Cap __my_parent +namespace Kernel: + Receiver my_receiver + Thread my_thread + Memory my_memory + Cap my_call + Cap my_parent + __recv_data_t recv -void free_slot (unsigned slot): - __slot_admin[slot].prev = NULL - __slot_admin[slot].next = __first_free_slot - if __slot_admin[slot].next: - __slot_admin[slot].next->prev = &__slot_admin[slot] - __first_free_slot = &__slot_admin[slot] + void free_slot (unsigned slot): + __slot_admin[slot].prev = NULL + __slot_admin[slot].next = __first_free_slot + if __slot_admin[slot].next: + __slot_admin[slot].next->prev = &__slot_admin[slot] + __first_free_slot = &__slot_admin[slot] -void free_cap (Cap cap): - list *l = &__cap_admin[cap.idx ()] - l->prev = NULL - l->next = __first_free_cap - if l->next: - l->next->prev = l - __first_free_cap = l + void free_cap (Cap cap): + if cap.slot () != 0: + kdebug ("trying to free capability from non-0 slot\n") + return + list *l = &__cap_admin[cap.idx ()] + l->prev = NULL + l->next = __first_free_cap + if l->next: + l->next->prev = l + __first_free_cap = l -unsigned alloc_slot (): - if !__first_free_slot: - // Out of slots... Probably best to raise an exception. For now, just return NO_SLOT. - return ~0 - list *ret = __first_free_slot - __first_free_slot = ret->next - if ret->next: - ret->next->prev = NULL - return ret - __slot_admin + unsigned alloc_slot (): + if !__first_free_slot: + // Out of slots... Probably best to raise an exception. For now, just return NO_SLOT. + kdebug ("out of slots!\n") + return ~0 + list *ret = __first_free_slot + __first_free_slot = ret->next + if ret->next: + ret->next->prev = NULL + return ret - __slot_admin -unsigned alloc_cap (): - if !__first_free_cap: - // Out of caps... Probably best to raise an exception. For now, just return NO_CAPABILITY. - return ~0 - list *ret = __first_free_cap - __first_free_cap = ret->next - if ret->next: - ret->next->prev = NULL - return ret - __cap_admin + Cap alloc_cap (): + if !__first_free_cap: + // Out of caps... Probably best to raise an exception. For now, just return CAP_NONE + kdebug ("out of capabilities!\n") + return Cap (0, CAP_NONE) + list *ret = __first_free_cap + __first_free_cap = ret->next + if ret->next: + ret->next->prev = NULL + return Cap (0, ret - __cap_admin) extern "C": void __main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin): @@ -77,18 +84,20 @@ extern "C": __cap_admin = cap_admin __first_free_slot = NULL for unsigned i = 2; i < __slots; ++i: - free_slot (i) + Kernel::free_slot (i) __first_free_cap = NULL for unsigned i = 7; i < __caps; ++i: - free_cap (Cap (0, i)) - __my_receiver = Cap (0, __receiver_num) - __my_thread = Cap (0, __thread_num) - __my_memory = Cap (0, __memory_num) - __my_call = Cap (0, __call_num) - __my_parent = Cap (0, __parent_num) - Num ret = start () - __my_parent.invoke (~0, ret) - __my_memory.destroy (__my_thread) + Kernel::free_cap (Kernel::Cap (0, i)) + Kernel::my_receiver = Kernel::Cap (0, __receiver_num) + Kernel::my_thread = Kernel::Cap (0, __thread_num) + Kernel::my_memory = Kernel::Cap (0, __memory_num) + Kernel::my_call = Kernel::Cap (0, __call_num) + Kernel::my_parent = Kernel::Cap (0, __parent_num) + Kernel::recv.reply = Kernel::alloc_cap () + Kernel::recv.arg = Kernel::alloc_cap () + Kernel::Num ret = start () + Kernel::my_parent.invoke (~0, ret) + Kernel::my_memory.destroy (Kernel::my_thread) // The program no longer exists. If it somehow does, generate an address fault. while true: *(volatile unsigned *)~0 diff --git a/boot-programs/devices.hhp b/boot-programs/devices.hhp index 4dc2ec8..879bb47 100644 --- a/boot-programs/devices.hhp +++ b/boot-programs/devices.hhp @@ -24,59 +24,59 @@ // This shouldn't really be here. But where should it be? // Requests made by initial threads to tell init about themselves. enum init_requests: - INIT_SET_GPIO + INIT_SET_GPIO = 1 INIT_SET_LCD // List interface. template // -struct List : public Cap: - List (Cap c = Cap ()) : Cap (c): +struct List : public Kernel::Cap: + List (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): // TODO -struct String : public Cap: - String (Cap c = Cap ()) : Cap (c): +struct String : public Kernel::Cap: + String (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): // TODO // Keyboard interface. -struct Keyboard : public Cap: - Keyboard (Cap c = Cap ()) : Cap (c): +struct Keyboard : public Kernel::Cap: + Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): enum request: - SET_CB + SET_CB = 1 GET_KEYS // At event: the callback is called with a keycode. One bit defines if it's a press or release event. enum constant: RELEASE = 1 << 31 // Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events. - void set_cb (Cap cb): + void set_cb (Kernel::Cap cb): ocall (cb, CAP_MASTER_DIRECT | SET_CB) // Get a list of keys on this keyboard. The key codes start at zero with no gaps. - List get_keys (List ret = Cap (0, alloc_cap ())): - icall (ret, CAP_MASTER_DIRECT | GET_KEYS) - return ret + List get_keys (): + icall (CAP_MASTER_DIRECT | GET_KEYS) + return Kernel::get_arg () // Display interface. -struct Display : public Cap: - Display (Cap c = Cap ()) : Cap (c): +struct Display : public Kernel::Cap: + Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): enum request: - EOF_CB + EOF_CB = 1 CREATE_FB USE_FB GET_INFO // Register an end-of-frame callback. // At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events. - void set_eof_cb (Cap cb): + void set_eof_cb (Kernel::Cap cb): ocall (cb, CAP_MASTER_DIRECT | EOF_CB) // Create a framebuffer for the display. When not in use, it can be freed by the user. // The pages must be cappages holding Page capabilities. They are filled by the display. // The passed numbers must be 0 or match a mode that the device can use. // The returned number is the physical address of the framebuffer. It can be used with display_use_framebuffer. - unsigned create_framebuffer (Caps pages, unsigned w = 0, unsigned h = 0, unsigned mode = 0): - return icall (pages, Num (CAP_MASTER_DIRECT | CREATE_FB, 0), Num ((w << 16) | h, mode)).l + unsigned create_framebuffer (unsigned w = 0, unsigned h = 0, unsigned mode = 0): + return icall (Kernel::Num (CAP_MASTER_DIRECT | CREATE_FB, 0), Kernel::Num ((w << 16) | h, mode)).l // Use a framebuffer. The address must have been returned from display_create_framebuffer. // w, h and mode must match the values given at creation time. // unuse_cb is called the next time this operation is requested for this display. - void use_framebuffer (unsigned addr, Cap unuse_cb = Cap (), unsigned w = 0, unsigned h = 0, unsigned mode = 0): - ocall (unuse_cb, Num (CAP_MASTER_DIRECT | USE_FB, addr), Num ((w << 16) | h, mode)) + void use_framebuffer (unsigned addr, Kernel::Cap unuse_cb = Kernel::Cap (), unsigned w = 0, unsigned h = 0, unsigned mode = 0): + ocall (unuse_cb, Kernel::Num (CAP_MASTER_DIRECT | USE_FB, addr), Kernel::Num ((w << 16) | h, mode)) // Get information about the display. void get_info (): // TODO: Interface is to be designed. @@ -86,91 +86,95 @@ struct Display : public Cap: // File system interface. // filesystem-related interfaces: file, directory, stream, seekable, mappable. // Normal files implement at least stream or seekable file. Directories implement directory. -struct File : public Cap: - File (Cap c = Cap ()) : Cap (c): +struct File : public Kernel::Cap: + File (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): enum request: - INFO + INFO = 1 CLOSE MAP_HANDLE // Get information about the file. - Num get_info (unsigned type, Caps ret = Cap ()): - return icall (ret, Num (CAP_MASTER_DIRECT | INFO, type)) + Kernel::Num get_info (unsigned type): + return icall (Kernel::Num (CAP_MASTER_DIRECT | INFO, type)) // Close a file. If this is a directory, it implicitly closes all files opened from it. void close (): call (CAP_MASTER_DIRECT | CLOSE) // Map a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle. - File map_handle (File ret): - icall (ret, CAP_MASTER_DIRECT | MAP_HANDLE) + File map_handle (): + icall (CAP_MASTER_DIRECT | MAP_HANDLE) + return Kernel::get_arg () // Directory interface. struct Directory : public File: - Directory (Cap c = Cap ()) : File (c): + Directory (Kernel::Cap c = Kernel::Cap ()) : File (c): enum request: - GET_SIZE + GET_SIZE = 1 GET_NAME GET_FILE GET_FILE_INFO CREATE_FILE DELETE_FILE // Get the number of entries in this directory. - Num get_size (): + Kernel::Num get_size (): return call (CAP_MASTER_DIRECT | GET_SIZE) // Get the filename. The return value is the size of the string, the page is filled with the string itself. - void get_name (Num idx, String target): - icall (target, CAP_MASTER_DIRECT | GET_NAME, idx) + String get_name (Kernel::Num idx): + icall (CAP_MASTER_DIRECT | GET_NAME, idx) + return Kernel::get_arg () // Get the file. - void get_file (Num idx, File ret): - icall (ret, CAP_MASTER_DIRECT | GET_FILE, idx) + File get_file (Kernel::Num idx): + icall (CAP_MASTER_DIRECT | GET_FILE, idx) + return Kernel::get_arg () // Get file info. This returns the same information as file_get_info, without opening the file. - Num get_file_info (Num idx, unsigned type, Caps ret = Cap ()): - return icall (ret, Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx) + Kernel::Num get_file_info (Kernel::Num idx, unsigned type): + return icall (Kernel::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx) // Create a new file. After this, any index may map to a different file. - void create_file (String name, File ret): - icall (ret, CAP_MASTER_DIRECT | CREATE_FILE) + File create_file (String name): + icall (CAP_MASTER_DIRECT | CREATE_FILE) + return Kernel::get_arg () // Delete a file. After this, any index may map to a different file. - void delete_file (Num idx): + void delete_file (Kernel::Num idx): call (CAP_MASTER_DIRECT | DELETE_FILE, idx) // Stream interface. struct Stream : public File: - Stream (Cap c = Cap ()) : File (c): + Stream (Kernel::Cap c = Kernel::Cap ()) : File (c): enum request: - READ + READ = 1 WRITE // Try to read size bytes. Returns the number of bytes successfully read. - Num read (Num size, String ret): - return icall (ret, CAP_MASTER_DIRECT | READ, size) + Kernel::Num read (Kernel::Num size): + return icall (CAP_MASTER_DIRECT | READ, size) // Try to write size bytes. Returns the number of bytes successfully written. - Num write (String s, Num size): + Kernel::Num write (String s, Kernel::Num size): return ocall (s, CAP_MASTER_DIRECT | WRITE, size) // Seekable file interface. struct Seekable : public File: - Seekable (Cap c = Cap ()) : File (c): + Seekable (Kernel::Cap c = Kernel::Cap ()) : File (c): enum request: - READ + READ = 1 WRITE TRUNCATE // Try to read size bytes from position idx. Returns the number of bytes successfully read. - Num read (Num idx, unsigned size, String ret): - return icall (ret, Num (CAP_MASTER_DIRECT | READ, size), idx) + Kernel::Num read (Kernel::Num idx, unsigned size): + return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, size), idx) // Try to write size bytes at position idx; the file is extended with zeroes if the write is past the end. Returns the number of bytes successfully written. - Num write (Num idx, String s): + Kernel::Num write (Kernel::Num idx, String s): return ocall (s, CAP_MASTER_DIRECT | WRITE, idx) // Truncate file to size idx. The file is extended with zeroes if it gets longer. - void truncate (Num idx): + void truncate (Kernel::Num idx): call (CAP_MASTER_DIRECT | TRUNCATE, idx) // Mappable file interface. struct Mappable : public Seekable: - Mappable (Cap c = Cap ()) : Seekable (c): + Mappable (Kernel::Cap c = Kernel::Cap ()) : Seekable (c): // TODO: to be designed. // Block device interface. struct Block_device : public Mappable: - Block_device (Cap c = Cap ()) : Mappable (c): + Block_device (Kernel::Cap c = Kernel::Cap ()) : Mappable (c): // TODO: to be designed. diff --git a/boot-programs/gpio.ccp b/boot-programs/gpio.ccp index 1b38028..5a52f29 100644 --- a/boot-programs/gpio.ccp +++ b/boot-programs/gpio.ccp @@ -59,29 +59,14 @@ enum cap_type: CAP_LOCKLEDS CAP_PWM -static unsigned events -static Caps event_caps +static Kernel::Cap events[NUM_EVENTS] static void event (event_type type, unsigned data): - kdebug ("event t/d/e=") - kdebug_num (type) - kdebug_char ('/') - kdebug_num (data) - kdebug_char ('/') - kdebug_num (events) - kdebug_char ('\n') - Cap (events, type).invoke (data) + events[type].invoke (data) -static void set_cb (Cap cap, event_type type): - kdebug ("gpio set cb ") - kdebug_num (type) - kdebug_char ('\n') - for unsigned i = 0; i < NUM_EVENTS; ++i: - event_caps.print (i) - cap.clone (Cap (events, type)) - kdebug ("after:\n") - for unsigned i = 0; i < NUM_EVENTS; ++i: - event_caps.print (i) +static void set_cb (event_type type): + Kernel::free_cap (events[type]) + events[type] = Kernel::get_arg () class DevKeyboard: static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] @@ -159,7 +144,6 @@ class DevKeyboard: for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col: keys[col] = 0xff scan () - event (KEYBOARD_EVENT, ~0) enum Keys: N0, N1, N2, N3, N4, N5, N6, N7, N8, N9 @@ -225,7 +209,6 @@ class Touchpad: void send_initial (): old_state = 0 check_events () - event (TOUCHPAD_EVENT, ~0) class Lockleds: // Note that num lock is in port 2. The others are in port 0. @@ -269,49 +252,50 @@ class Pwm: GPIO_GPDR (GPIO_PWM_ENABLE_PORT) &= ~(1 << GPIO_PWM_ENABLE) // TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything. -Num start (): +Kernel::Num start (): Kernel::schedule () map_gpio () map_pwm0 () - event_caps = __my_memory.create_caps (NUM_EVENTS) - events = event_caps.use () + for unsigned i = 0; i < NUM_EVENTS; ++i: + events[i] = Kernel::alloc_cap () DevKeyboard kbd Touchpad tp Lockleds leds Pwm pwm - Caps c = __my_memory.create_caps (4) + Kernel::Caps c = Kernel::my_memory.create_caps (4) unsigned init_slot = c.use () - __my_receiver.create_capability (CAP_KEYBOARD, Cap (init_slot, 0)) - __my_receiver.create_capability (CAP_TOUCHPAD, Cap (init_slot, 1)) - __my_receiver.create_capability (CAP_LOCKLEDS, Cap (init_slot, 2)) - __my_receiver.create_capability (CAP_PWM, Cap (init_slot, 3)) + Kernel::set_recv_arg (Kernel::Cap (init_slot, 0)) + Kernel::my_receiver.create_capability (CAP_KEYBOARD) + Kernel::set_recv_arg (Kernel::Cap (init_slot, 1)) + Kernel::my_receiver.create_capability (CAP_TOUCHPAD) + Kernel::set_recv_arg (Kernel::Cap (init_slot, 2)) + Kernel::my_receiver.create_capability (CAP_LOCKLEDS) + Kernel::set_recv_arg (Kernel::Cap (init_slot, 3)) + Kernel::my_receiver.create_capability (CAP_PWM) - __my_parent.ocall (c, INIT_SET_GPIO) + Kernel::my_parent.ocall (c, INIT_SET_GPIO) free_cap (c) - free_slot (init_slot) + Kernel::free_slot (init_slot) if kbd.is_scanning (): - __my_receiver.set_alarm (ALARM_INTERVAL) + Kernel::my_receiver.set_alarm (ALARM_INTERVAL) // Enable interrupts. All are in port 0. GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK Kernel::register_interrupt (IRQ_GPIO0) - kdebug ("gpio ready\n") - unsigned slot = alloc_slot () while true: Kernel::schedule () - Cap::OMessage msg - Kernel::wait (&msg, slot) - switch (unsigned)msg.cap_protected.value (): + Kernel::wait () + switch Kernel::recv.protected_data.l: case ~0: // Alarm. kbd.scan () if kbd.is_scanning (): - __my_receiver.set_alarm (ALARM_INTERVAL) + Kernel::my_receiver.set_alarm (ALARM_INTERVAL) break case IRQ_GPIO0: // Always scan keyboard and touchpad on any interrupt. @@ -321,20 +305,29 @@ Num start (): Kernel::register_interrupt (IRQ_GPIO0) break case CAP_KEYBOARD: - set_cb (Cap (slot, 1), KEYBOARD_EVENT) - Cap (slot, 0).invoke () + kdebug ("gpio: keyboard callback registered.\n") + set_cb (KEYBOARD_EVENT) + Kernel::recv.reply.invoke () kbd.send_initial () + event (KEYBOARD_EVENT, ~0) break case CAP_TOUCHPAD: - set_cb (Cap (slot, 1), TOUCHPAD_EVENT) - Cap (slot, 0).invoke () + kdebug ("gpio: touchpad callback registered.\n") + set_cb (TOUCHPAD_EVENT) + Kernel::recv.reply.invoke () tp.send_initial () + event (TOUCHPAD_EVENT, ~0) break case CAP_LOCKLEDS: - leds.set (msg.data[0].l) - Cap (slot, 0).invoke () + leds.set (Kernel::recv.data[0].l) + Kernel::recv.reply.invoke () break case CAP_PWM: - pwm.set_backlight (msg.data[0].l) - Cap (slot, 0).invoke () + pwm.set_backlight (Kernel::recv.data[0].l) + Kernel::recv.reply.invoke () + break + default: + kdebug ("invalid gpio operation ") + kdebug_num (Kernel::recv.protected_data.l) + kdebug ("\n") break diff --git a/boot-programs/init.ccp b/boot-programs/init.ccp index f0e19c6..880f32b 100644 --- a/boot-programs/init.ccp +++ b/boot-programs/init.ccp @@ -21,7 +21,7 @@ static Keyboard kbd, tp static Display lcd -static Cap lockleds, pwm +static Kernel::Cap lockleds, pwm // Event types. enum type: @@ -30,71 +30,63 @@ enum type: static void setup (): unsigned state = 0 - unsigned slot = alloc_slot () + Kernel::recv.arg = Kernel::alloc_cap () while true: - Cap::OMessage msg - Kernel::wait (&msg, slot) - switch msg.data[0].value (): + Kernel::wait () + switch Kernel::recv.data[0].value (): case INIT_SET_GPIO: kdebug ("gpio\n") - Caps caps = Cap (slot, 1) + Kernel::Caps caps = Kernel::get_arg () + Kernel::Cap reply = Kernel::get_reply () unsigned gpio_slot = caps.use () - Cap (slot, 0).invoke () - kbd = Cap (gpio_slot, 0) - tp = Cap (gpio_slot, 1) - lockleds = Cap (gpio_slot, 2) - pwm = Cap (gpio_slot, 3) + kbd = Kernel::Cap (gpio_slot, 0) + tp = Kernel::Cap (gpio_slot, 1) + lockleds = Kernel::Cap (gpio_slot, 2) + pwm = Kernel::Cap (gpio_slot, 3) + reply.invoke () + Kernel::free_cap (reply) ++state break case INIT_SET_LCD: kdebug ("lcd\n") - lcd = Cap (slot, 1).clone () - Cap (slot, 0).invoke () + lcd = Kernel::get_arg () + Kernel::recv.reply.invoke () ++state break if state == 2: break - Caps caps = __my_memory.create_caps (2) - Cap kc = __my_receiver.create_capability (KBD, Cap (slot, 0)) - kdebug ("init0: ") - caps.print (0) + Kernel::schedule () + kdebug ("init registering keyboard\n") + Kernel::Cap kc = Kernel::my_receiver.create_capability (KBD) kbd.set_cb (kc) - kdebug ("init1: ") - caps.print (0) - Cap tc = __my_receiver.create_capability (TP, Cap (slot, 1)) - kdebug ("init2: ") - caps.print (1) + Kernel::Cap tc = Kernel::my_receiver.create_capability (TP) tp.set_cb (tc) - kdebug ("init3: ") - caps.print (1) pwm.call (1) - free_slot (slot) char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":" -Num start (): +Kernel::Num start (): // Set up lcd first Kernel::schedule () kdebug ("start init\n") setup () kdebug ("run init\n") while true: - Cap::OMessage msg - Kernel::wait (&msg) - switch msg.cap_protected.value (): + Kernel::wait () + switch Kernel::recv.protected_data.value (): case KBD: - unsigned code = msg.data[0].l + unsigned code = Kernel::recv.data[0].l if code & Keyboard::RELEASE: break kdebug_char (decode_kbd[code]) break case TP: unsigned leds = 0 - if msg.data[0].l & 1: + if Kernel::recv.data[0].l & 1: leds |= 0x1 else: leds |= 0x4 - if !(msg.data[0].l & Keyboard::RELEASE): + if !(Kernel::recv.data[0].l & Keyboard::RELEASE): leds |= 0x2 lockleds.call (leds) break diff --git a/boot-programs/lcd.ccp b/boot-programs/lcd.ccp index cb9c9e7..de2d394 100644 --- a/boot-programs/lcd.ccp +++ b/boot-programs/lcd.ccp @@ -103,7 +103,7 @@ static void log_str (char const *str): while *str: log_char (*str++) -static void log_num (Num n): +static void log_num (Kernel::Num n): char const *encode = "0123456789abcdef" log_char ('[') for unsigned i = 0; i < 8; ++i: @@ -113,27 +113,27 @@ static void log_num (Num n): log_char (encode[(n.l >> (4 * (7 - i))) & 0xf]) log_char (']') -static void log_msg (Cap::OMessage *msg): - log_str ("cap_prot:") - log_num (msg->cap_protected) +static void log_msg (): + log_str ("prot:") + log_num (Kernel::recv.protected_data) log_str ("data:") for unsigned i = 0; i < 2; ++i: - log_num (msg->data[i]) + log_num (Kernel::recv.data[i]) log_char ('\n') -Num start (): +Kernel::Num start (): map_lcd () map_cpm () Descriptor descriptor __attribute__ ((aligned (16))) unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS - unsigned physical = __my_memory.alloc_range (pages) + unsigned physical = Kernel::my_memory.alloc_range (pages) assert (physical & PAGE_MASK && ~physical) for unsigned i = 0; i < pages; ++i: - Page p = __my_memory.create_page () + Kernel::Page p = Kernel::my_memory.create_page () p.alloc_physical (physical + i * PAGE_SIZE, false, true) - __my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE) - free_cap (p) + Kernel::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE) + Kernel::free_cap (p) for unsigned y = 0; y < 480; ++y: unsigned g = (y << 6) / 480 unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480) @@ -150,9 +150,9 @@ Num start (): ob = b b = 0x1f LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b) - Page p = __my_memory.mapping (&descriptor) + Kernel::Page p = Kernel::my_memory.mapping (&descriptor) physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK) - free_cap (p) + Kernel::free_cap (p) descriptor.next = physical_descriptor descriptor.frame = physical descriptor.id = 0xdeadbeef @@ -161,28 +161,32 @@ Num start (): __asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0") reset () - Cap logcap = __my_receiver.create_capability (LCD_LOG) + Kernel::Cap logcap = Kernel::my_receiver.create_capability (LCD_LOG) __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory") - Cap set_eof_cb = __my_receiver.create_capability (LCD_EOF_CB) - __my_parent.ocall (set_eof_cb, INIT_SET_LCD) + Kernel::Cap set_eof_cb = Kernel::my_receiver.create_capability (LCD_EOF_CB) + Kernel::my_parent.ocall (set_eof_cb, INIT_SET_LCD) - unsigned slot = alloc_slot () - Cap eof_cb (0, alloc_cap ()) + unsigned slot = Kernel::alloc_slot () + Kernel::Cap eof_cb = Kernel::alloc_cap () while true: - Cap::OMessage msg - Kernel::wait (&msg, slot) - //log_msg (&msg) - switch msg.cap_protected.value (): + Kernel::wait () + //log_msg () + switch Kernel::recv.protected_data.l: case IRQ_LCD: lcd_clr_eof () eof_cb.invoke () break case LCD_EOF_CB: - Cap (slot, 1).clone (eof_cb) - Cap (slot, 0).invoke () + Kernel::free_cap (eof_cb) + eof_cb = Kernel::recv.arg + Kernel::recv.arg = Kernel::alloc_cap () + Kernel::recv.reply.invoke () Kernel::register_interrupt (IRQ_LCD) break case LCD_LOG: - log_char (msg.data[0].l) + log_char (Kernel::recv.data[0].l) + break + default: + log_char ('~') break diff --git a/invoke.ccp b/invoke.ccp index e485c12..7a3e153 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -18,13 +18,44 @@ #include "kernel.hh" +static void log_message (char const *prefix, unsigned target, unsigned pdata, kCapability::Context *c): + if !dbg_code.l: + dbg_log (prefix) + dbg_log (": ") + dbg_log_num ((unsigned)old_current) + dbg_log (" > ") + dbg_log_num (target) + dbg_log (":") + dbg_log_num (pdata) + dbg_log ("/") + dbg_log_num (c->data[0].l) + dbg_log (" ") + dbg_log_num (c->data[0].h) + dbg_log (",") + dbg_log_num (c->data[1].l) + dbg_log (" ") + dbg_log_num (c->data[1].h) + dbg_log (",") + dbg_log_num (pdata) + dbg_log (";") + if c->reply.valid (): + dbg_log_num ((unsigned)c->reply->target) + dbg_log (":") + dbg_log_num (c->reply->protected_data.l) + dbg_log (",") + if c->arg.valid (): + dbg_log_num ((unsigned)c->arg->target) + dbg_log (":") + dbg_log_num (c->arg->protected_data.l) + dbg_log ("\n") + void kThread::raise (unsigned code, unsigned data): dpanic (code, "raise") dbg_log ("raise ") dbg_log_num ((unsigned)current) dbg_log_char ('/') - if code < NUM_EXCEPTION_CODES: - dbg_log (exception_name[code]) + if code < Kernel::NUM_EXCEPTION_CODES: + dbg_log (Kernel::exception_name[code]) else: dbg_log ("invalid code:") dbg_log_num (code) @@ -35,9 +66,7 @@ void kThread::raise (unsigned code, unsigned data): if slots < 1 || !caps[0] || !caps[0]->cap (0)->target: return kCapability::Context c - c.caps = NULL - c.data[0] = Num (code, data) - c.data[1] = 0 + c.data[0] = Kernel::Num (code, data) caps[0]->cap (0)->invoke (&c) // From user-provided, thus untrusted, data, find a capability. @@ -65,17 +94,6 @@ kCapRef kThread::find_capability (unsigned code, bool *copy): return kCapRef () return kCapRef (caps[slot], num) -void kThread::fill_slot (unsigned slot, kCaps *new_caps): - if slot >= slots: - if slot != ~0: - dpanic (0, "waiting with invalid slot") - return - if caps[slot]: - // TODO: invalidate slot. - caps[slot] = new_caps - if new_caps: - // TODO: link it into a list. - // Try to deliver a message. bool kReceiver::try_deliver (): if !messages: @@ -85,24 +103,37 @@ bool kReceiver::try_deliver (): kMessage *m = last_message if protected_only: for ; m; m = (kMessage *)m->prev: - if m->cap_protected.value () == reply_protected_data.value (): + if m->protected_data.value () == reply_protected_data.value (): protected_only = false break if !m: return false - owner->fill_slot (owner->recv_slot, m->caps) - kThread_arch_receive (owner, m->cap_protected, recv_protected, m->data) + bool dummy + kCapRef c = owner->find_capability (owner->recv_reply, &dummy) + if c.valid (): + c.clone (kCapRef (&m->caps, 0), true) + c = owner->find_capability (owner->recv_arg, &dummy) + if c.valid (): + c.clone (kCapRef (&m->caps, 1), true) + kThread_arch_receive (owner, m->protected_data, m->data) address_space->free_message (this, m) owner->unwait () return true // Send a message to a receiver; try to deliver it immediately. -bool kReceiver::send_message (Num cap_protected, kCapability::Context *c): - if owner && owner->is_waiting () && (cap_protected.value () == reply_protected_data.value () || !protected_only): +bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *c): + //log_message ("send_message", (unsigned)this, protected_data.l, c) + if owner && owner->is_waiting () && (protected_data.value () == reply_protected_data.value () || !protected_only): if protected_only: protected_only = false - owner->fill_slot (owner->recv_slot, c->caps) - kThread_arch_receive (owner, cap_protected, recv_protected, c->data) + bool dummy + kCapRef cap = owner->find_capability (owner->recv_reply, &dummy) + if cap.valid (): + cap.clone (c->reply, c->copy[0]) + cap = owner->find_capability (owner->recv_arg, &dummy) + if cap.valid (): + cap.clone (c->arg, c->copy[1]) + kThread_arch_receive (owner, protected_data, c->data) owner->unwait () return true // The owner was not waiting, or it was not possible to deliver the message. Put it in the queue. @@ -115,8 +146,8 @@ bool kReceiver::send_message (Num cap_protected, kCapability::Context *c): // TODO: use sender-provided storage. if !msg: return false - msg->cap_protected = cap_protected - if protected_only && cap_protected.value () == reply_protected_data.value (): + msg->protected_data = protected_data + if protected_only && protected_data.value () == reply_protected_data.value (): // Put this message in the end (where it will be first seen). Clear the protected_only flag. protected_only = false if msg->next: @@ -128,59 +159,69 @@ bool kReceiver::send_message (Num cap_protected, kCapability::Context *c): last_message = msg for unsigned i = 0; i < 2; ++i: msg->data[i] = c->data[i] - msg->caps = c->caps + msg->caps.clone (0, c->reply, c->copy[0]) + msg->caps.clone (1, c->arg, c->copy[1]) return true -static kCapRef reply +static kCapability::Context *context +// reply_caps is the source of a receiver-generated reply capability. +// replied_caps is the source of kernel-generated capabilities which are used as arguments in a reply. +static kCaps reply_caps, replied_caps static kReceiver *reply_target -static Num reply_protected +static Kernel::Num reply_protected static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0): kCapability::Context c - c.data[0] = Num (num1, num2) + c.data[0] = Kernel::Num (num1, num2) c.data[1] = num3 - c.caps = NULL - invoke (reply_target, reply_protected, &c, NULL) - -static void reply_cap (unsigned target, Num cap_protected, kCapRef *ref): - if reply.valid (): - reply.set ((kReceiver *)target, cap_protected, kCapRef (), ref) + if reply_target: + reply_target->send_message (reply_protected, &c) else: - dpanic (0x87677654, "no target to reply capability to") - reply_num (0) + dpanic (0, "nothing to reply to") -static void receiver_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): - kReceiver *receiver = (kReceiver *)cap_protected.l +static void reply_cap (unsigned target, Kernel::Num protected_data, kCapRef *ref): + replied_caps.set (0, (kReceiver *)target, protected_data, kCapRef (), ref) + kCapability::Context c + c.arg = kCapRef (&replied_caps, 0) + c.copy[1] = true + if reply_target: + reply_target->send_message (reply_protected, &c) + else: + dpanic (0, "nothing to reply to") + c.arg->invalidate () + +static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c): + kReceiver *receiver = (kReceiver *)protected_data.l switch cmd: - case Receiver::SET_OWNER: - if c->caps->size < 2: + case Kernel::Receiver::SET_OWNER: + if !c->arg.valid (): reply_num (~0) return - unsigned cap = (unsigned)c->caps->cap (1)->target - if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Thread::SET_OWNER): + unsigned cap = (unsigned)c->arg->target + if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Kernel::Thread::SET_OWNER): // FIXME: This makes it impossible to use a fake kThread capability. return - receiver->own ((kThread *)c->caps->cap (1)->cap_protected.l) + receiver->own ((kThread *)c->arg->protected_data.l) break - case Receiver::CREATE_CAPABILITY: + case Kernel::Receiver::CREATE_CAPABILITY: reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities) return - case Receiver::CREATE_CALL_CAPABILITY: - reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Receiver::CALL_ASYNC : Receiver::CALL), cap_protected, &((kObject *)cap_protected.l)->refs) + case Kernel::Receiver::CREATE_CALL_CAPABILITY: + reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs) return - case Receiver::GET_REPLY_PROTECTED_DATA: + case Kernel::Receiver::GET_REPLY_PROTECTED_DATA: reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0) return - case Receiver::SET_REPLY_PROTECTED_DATA: + case Kernel::Receiver::SET_REPLY_PROTECTED_DATA: receiver->reply_protected_data = c->data[1] break - case Receiver::GET_ALARM: + case Kernel::Receiver::GET_ALARM: reply_num (receiver->alarm_count) return - case Receiver::SET_ALARM: - case Receiver::ADD_ALARM: + case Kernel::Receiver::SET_ALARM: + case Kernel::Receiver::ADD_ALARM: unsigned old = receiver->alarm_count - if cmd == Receiver::SET_ALARM: + if cmd == Kernel::Receiver::SET_ALARM: receiver->alarm_count = c->data[1].l else: receiver->alarm_count += c->data[1].l @@ -204,14 +245,15 @@ static void receiver_invoke (unsigned cmd, unsigned target, Num cap_protected, k reply_num (receiver->alarm_count) return default: - reply_num (ERR_INVALID_OPERATION) + dpanic (0, "invalid receiver operation") + reply_num (Kernel::ERR_INVALID_OPERATION) return reply_num (0) -static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): - kMemory *mem = (kMemory *)cap_protected.l +static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c): + kMemory *mem = (kMemory *)protected_data.l switch cmd: - case Memory::CREATE: + case Kernel::Memory::CREATE: switch c->data[0].h: case CAPTYPE_RECEIVER: kReceiver *ret = mem->alloc_receiver () @@ -219,7 +261,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs) else: dpanic (0x03311992, "out of memory creating receiver") - reply_num (ERR_OUT_OF_MEMORY) + reply_num (Kernel::ERR_OUT_OF_MEMORY) return case CAPTYPE_MEMORY: kMemory *ret = mem->alloc_memory () @@ -227,7 +269,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs) else: dpanic (0x13311992, "out of memory creating memory") - reply_num (ERR_OUT_OF_MEMORY) + reply_num (Kernel::ERR_OUT_OF_MEMORY) return case CAPTYPE_THREAD: kThread *ret = mem->alloc_thread (c->data[1].l) @@ -235,7 +277,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa reply_cap (CAPTYPE_THREAD | CAP_MASTER, (unsigned)ret, &ret->refs) else: dpanic (0x23311992, "out of memory creating thread") - reply_num (ERR_OUT_OF_MEMORY) + reply_num (Kernel::ERR_OUT_OF_MEMORY) return case CAPTYPE_PAGE: kPage *ret = mem->alloc_page () @@ -243,7 +285,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs) else: dpanic (0x33311992, "out of memory creating page") - reply_num (ERR_OUT_OF_MEMORY) + reply_num (Kernel::ERR_OUT_OF_MEMORY) return case CAPTYPE_CAPS: kCaps *ret = mem->alloc_caps (c->data[1].l) @@ -251,112 +293,114 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs) else: dpanic (0x43311992, "out of memory creating caps") - reply_num (ERR_OUT_OF_MEMORY) + reply_num (Kernel::ERR_OUT_OF_MEMORY) return default: + dpanic (0, "invalid create type") reply_num (~0) return break - case Memory::DESTROY: - if c->caps->size < 2 || (unsigned)c->caps->cap (1)->target & ~KERNEL_MASK || !c->caps->cap (1)->target || ((kObject *)c->caps->cap (1)->cap_protected.l)->address_space != mem: + case Kernel::Memory::DESTROY: + if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || !c->arg->target || ((kObject *)c->arg->protected_data.l)->address_space != mem: reply_num (~0) return - switch (unsigned)c->caps->cap (1)->target & CAPTYPE_MASK: + switch (unsigned)c->arg->target & CAPTYPE_MASK: case CAPTYPE_RECEIVER: - mem->free_receiver ((kReceiver *)c->caps->cap (1)->cap_protected.l) + mem->free_receiver ((kReceiver *)c->arg->protected_data.l) break case CAPTYPE_MEMORY: - mem->free_memory ((kMemory *)c->caps->cap (1)->cap_protected.l) + mem->free_memory ((kMemory *)c->arg->protected_data.l) break case CAPTYPE_THREAD: - mem->free_thread ((kThread *)c->caps->cap (1)->cap_protected.l) + mem->free_thread ((kThread *)c->arg->protected_data.l) break case CAPTYPE_PAGE: - mem->free_page ((kPage *)c->caps->cap (1)->cap_protected.l) + mem->free_page ((kPage *)c->arg->protected_data.l) break case CAPTYPE_CAPS: - mem->free_caps ((kCaps *)c->caps->cap (1)->cap_protected.l) + mem->free_caps ((kCaps *)c->arg->protected_data.l) break default: panic (0x55228930, "invalid case") return break - case Memory::LIST: + case Kernel::Memory::LIST: // TODO break - case Memory::MAP: + case Kernel::Memory::MAP: // FIXME: this should work for fake pages as well. - if c->caps->size < 2 || (unsigned)c->caps->cap (1)->target & ~KERNEL_MASK || ((unsigned)c->caps->cap (1)->target & CAPTYPE_MASK) != CAPTYPE_PAGE: + if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || ((unsigned)c->arg->target & CAPTYPE_MASK) != CAPTYPE_PAGE: dpanic (0x22993341, "Trying to map non-page") reply_num (~0) return - kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l + kPage *page = (kPage *)c->arg->protected_data.l if page->address_space != mem: dpanic (0x52993341, "Trying to map foreign page") reply_num (~0) return - bool readonly = c->data[1].l & (unsigned)c->caps->cap (1)->target & Page::READONLY + bool readonly = c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY mem->map (page, c->data[1].l & PAGE_MASK, readonly) break - case Memory::MAPPING: + case Kernel::Memory::MAPPING: bool readonly kPage *page = mem->get_mapping (c->data[1].l, &readonly) unsigned t = CAPTYPE_PAGE | CAP_MASTER if readonly: - t |= Page::READONLY + t |= Kernel::Page::READONLY reply_cap (t, (unsigned)page, &page->refs) return - case Memory::GET_LIMIT: + case Kernel::Memory::GET_LIMIT: reply_num (mem->limit) return - case Memory::SET_LIMIT: + case Kernel::Memory::SET_LIMIT: mem->limit = c->data[1].l break default: - reply_num (ERR_INVALID_OPERATION) + dpanic (0, "invalid memory operation") + reply_num (Kernel::ERR_INVALID_OPERATION) return reply_num (0) -static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): - kThread *thread = (kThread *)cap_protected.l +static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c): + kThread *thread = (kThread *)protected_data.l switch cmd: - case Thread::GET_INFO: + case Kernel::Thread::GET_INFO: switch c->data[0].h: - case Thread::PC: + case Kernel::Thread::PC: reply_num (thread->pc) return - case Thread::SP: + case Kernel::Thread::SP: reply_num (thread->sp) return - case Thread::FLAGS: + case Kernel::Thread::FLAGS: reply_num (thread->flags) return default: reply_num (*kThread_arch_info (thread, c->data[0].h)) return - case Thread::SET_INFO: + case Kernel::Thread::SET_INFO: unsigned *value switch c->data[1].l: - case Thread::PC: + case Kernel::Thread::PC: value = &thread->pc break - case Thread::SP: + case Kernel::Thread::SP: value = &thread->sp break - case Thread::FLAGS: + case Kernel::Thread::FLAGS: // It is not possible to set the PRIV flag (but it can be reset). - if c->data[1].l & Thread::PRIV: - c->data[1].h &= ~Thread::PRIV + if c->data[1].l & Kernel::Thread::PRIV: + c->data[1].h &= ~Kernel::Thread::PRIV value = &thread->flags - if c->data[1].h & ~Thread::USER_FLAGS: + if c->data[1].h & ~Kernel::Thread::USER_FLAGS: unsigned v = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h) - if (v & Thread::WAITING) != (*value & Thread::WAITING): - if v & Thread::WAITING: + if (v & Kernel::Thread::WAITING) != (*value & Kernel::Thread::WAITING): + if v & Kernel::Thread::WAITING: thread->wait () else thread->unwait () - if (v & Thread::RUNNING) != (*value & Thread::RUNNING): - if v & Thread::RUNNING: + if (v & Kernel::Thread::RUNNING) != (*value & Kernel::Thread::RUNNING): + if v & Kernel::Thread::RUNNING: thread->run () else thread->unrun () @@ -367,93 +411,114 @@ static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa if value: *value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h) break - case Thread::USE_SLOT: - if c->data[1].l >= thread->slots || c->caps->size < 2: + case Kernel::Thread::USE_SLOT: + if c->data[1].l >= thread->slots || !c->arg.valid (): dbg_send (5, 3) dpanic (c->data[1].l, "no argument given for USE_SLOT") reply_num (~0) return // FIXME: This doesn't allow using a fake caps. - if (unsigned)c->caps->cap (1)->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->caps->cap (1)->target != (CAPTYPE_CAPS | Caps::USE): + if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Kernel::Caps::USE): dpanic (0, "argument for USE_SLOT is not a caps") reply_num (~0) return - thread->fill_slot (c->data[1].l, (kCaps *)c->caps->cap (1)->cap_protected.l) - reply_num (0) - return - case Thread::SCHEDULE: + unsigned slot = c->data[1].l + kCaps *new_caps = (kCaps *)c->arg->protected_data.l + if slot >= thread->slots: + dpanic (0, "using invalid slot") + return + if thread->caps[slot]: + // TODO: invalidate slot. + thread->caps[slot] = new_caps + if new_caps: + // TODO: link it into a list. + break + case Kernel::Thread::SCHEDULE: do_schedule = true return default: - if !(thread->flags & Thread::PRIV): - reply_num (ERR_INVALID_OPERATION) + if !(thread->flags & Kernel::Thread::PRIV): + dpanic (0, "invalid thread operation") + reply_num (Kernel::ERR_INVALID_OPERATION) return switch cmd: - case Thread::PRIV_REGISTER_INTERRUPT: - arch_register_interrupt (c->data[1].l, c->caps->size >= 2 && (((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK) == CAPTYPE_RECEIVER ? (kReceiver *)c->caps->cap (1)->cap_protected.l : NULL) + case Kernel::Thread::PRIV_REGISTER_INTERRUPT: + arch_register_interrupt (c->data[1].l, c->arg.valid () && (((unsigned)c->arg->target) & ~REQUEST_MASK) == CAPTYPE_RECEIVER ? (kReceiver *)c->arg->protected_data.l : NULL) break - case Thread::PRIV_GET_TOP_MEMORY: + case Kernel::Thread::PRIV_GET_TOP_MEMORY: reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)&top_memory, &top_memory.refs) return - case Thread::PRIV_MAKE_PRIV: - if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_THREAD: + case Kernel::Thread::PRIV_MAKE_PRIV: + if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD: reply_num (~0) return - ((kThread *)c->caps->cap (1)->cap_protected.l)->flags |= Thread::PRIV + ((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV break - case Thread::PRIV_ALLOC_RANGE: - if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_MEMORY: + case Kernel::Thread::PRIV_ALLOC_RANGE: + if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY: panic (0x54365435, "non-memory argument to alloc_range") reply_num (~0) return - kMemory *mem = (kMemory *)c->caps->cap (1)->cap_protected.l + kMemory *mem = (kMemory *)c->arg->protected_data.l if !mem->use (c->data[1].l): dpanic (0x34365435, "out of memory during alloc_range") - reply_num (ERR_OUT_OF_MEMORY) + reply_num (Kernel::ERR_OUT_OF_MEMORY) return unsigned data = phys_alloc (c->data[1].l) if !data: mem->unuse (c->data[1].l) dpanic (0x14365435, "out of memory during alloc_range") - reply_num (ERR_OUT_OF_MEMORY) + reply_num (Kernel::ERR_OUT_OF_MEMORY) return reply_num (data & ~0xc0000000) return - case Thread::PRIV_ALLOC_PHYSICAL: - if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target & ~REQUEST_MASK) != CAPTYPE_PAGE: + case Kernel::Thread::PRIV_ALLOC_PHYSICAL: + if !c->arg.valid (): + panic (0x71342134, "no argument provided for alloc physical") + reply_num (~0) + return + if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE: panic (0x21342134, "no page provided for alloc physical") reply_num (~0) return - kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l + kPage *page = (kPage *)c->arg->protected_data.l page->forget () if !(c->data[1].l & 2): - if page->flags & Page::PAYING: - page->flags &= ~Page::PAYING + if page->flags & Kernel::Page::PAYING: + page->flags &= ~Kernel::Page::PAYING page->address_space->unuse () else: // This is for mapping allocated ranges. They are already paid for. Record that. - if page->flags & Page::PAYING: + if page->flags & Kernel::Page::PAYING: page->address_space->unuse () else: - page->flags |= Page::PAYING + page->flags |= Kernel::Page::PAYING page->frame = c->data[1].l & PAGE_MASK - page->flags |= Page::FRAME + page->flags |= Kernel::Page::FRAME if !(c->data[1].l & 1): - page->flags |= Page::UNCACHED + page->flags |= Kernel::Page::UNCACHED if !(c->data[1].l & 2): - page->flags |= Page::PHYSICAL + page->flags |= Kernel::Page::PHYSICAL kPage_arch_update_mapping (page) break - case Thread::PRIV_PHYSICAL_ADDRESS: - if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_PAGE: + case Kernel::Thread::PRIV_PHYSICAL_ADDRESS: + if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE: dpanic (0x99049380, "invalid page for physical address") reply_num (~0) return - kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l + kPage *page = (kPage *)c->arg->protected_data.l reply_num (page->frame & ~0xc0000000) return + case Kernel::Thread::PRIV_PANIC: + panic (c->data[1].l, "panic requested by thread") + reply_num (~0) + return + case Kernel::Thread::DBG_SEND: + dbg_send (c->data[1].l, c->data[1].h) + break default: - reply_num (ERR_INVALID_OPERATION) + dpanic (0, "invalid priv thread operation") + reply_num (Kernel::ERR_INVALID_OPERATION) return reply_num (0) return @@ -461,10 +526,10 @@ static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa static bool page_check_payment (kPage *page): kPage *p for p = page->share_prev; p; p = p->share_prev: - if p->flags & Page::PAYING: + if p->flags & Kernel::Page::PAYING: return true for p = page->share_next; p; p = p->share_next: - if p->flags & Page::PAYING: + if p->flags & Kernel::Page::PAYING: return true // No kPage is paying for this frame anymore. raw_pfree (page->frame) @@ -473,38 +538,38 @@ static bool page_check_payment (kPage *page): p->frame = NULL p->share_prev = NULL p->share_next = NULL - p->flags &= ~(Page::SHARED | Page::FRAME) + p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME) kPage_arch_update_mapping (p) for p = page, next = p->share_next; p; p = next, next = p->share_next: p->frame = NULL p->share_prev = NULL p->share_next = NULL - p->flags &= ~(Page::SHARED | Page::FRAME) + p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME) kPage_arch_update_mapping (p) return false -static void page_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): - kPage *page = (kPage *)cap_protected.l - switch cmd & ~Page::READONLY: - case Page::SHARE: - if c->caps->size < 2: +static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c): + kPage *page = (kPage *)protected_data.l + switch cmd & ~Kernel::Page::READONLY: + case Kernel::Page::SHARE: + if !c->arg.valid (): // Cannot share without a target page. reply_num (~0) return - if ((unsigned)c->caps->cap (1)->target & ~REQUEST_MASK) != CAPTYPE_PAGE: + if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE: // FIXME: This makes it impossible to use a fake kPage capability. reply_num (~0) return - kPage *t = (kPage *)c->caps->cap (1)->cap_protected.l + kPage *t = (kPage *)c->arg->protected_data.l t->forget () - if c->data[0].h & Page::READONLY || cmd & Page::READONLY: - t->flags |= Page::READONLY - if !(page->flags & Page::FRAME): + if c->data[0].h & Kernel::Page::READONLY || cmd & Kernel::Page::READONLY: + t->flags |= Kernel::Page::READONLY + if !(page->flags & Kernel::Page::FRAME): break - if c->data[0].h & Page::COPY: - if ~t->flags & Page::PAYING: + if c->data[0].h & Kernel::Page::COPY: + if ~t->flags & Kernel::Page::PAYING: break - if !(c->data[0].h & Page::FORGET) || page->flags & Page::SHARED: + if !(c->data[0].h & Kernel::Page::FORGET) || page->flags & Kernel::Page::SHARED: unsigned *d = (unsigned *)page->frame if t == page: kPage *other = page->share_next ? page->share_next : page->share_prev @@ -519,28 +584,28 @@ static void page_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapa page->share_prev = NULL page_check_payment (other) else: - t->flags |= Page::FRAME + t->flags |= Kernel::Page::FRAME t->frame = raw_zalloc () for unsigned i = 0; i <= (c->data[0].h & ~PAGE_MASK); i += 4: ((unsigned *)t->frame)[i >> 2] = d[i >> 2] else: if t != page: t->frame = page->frame - t->flags |= Page::FRAME + t->flags |= Kernel::Page::FRAME page->frame = NULL - page->flags &= ~Page::FRAME + page->flags &= ~Kernel::Page::FRAME kPage_arch_update_mapping (page) kPage_arch_update_mapping (t) else: if t == page: break - if c->data[0].h & Page::FORGET: - if ~page->flags & Page::SHARED: - if t->flags & Page::PAYING: + if c->data[0].h & Kernel::Page::FORGET: + if ~page->flags & Kernel::Page::SHARED: + if t->flags & Kernel::Page::PAYING: t->frame = page->frame - t->flags |= Page::FRAME + t->flags |= Kernel::Page::FRAME page->frame = NULL - page->flags &= ~Page::FRAME + page->flags &= ~Kernel::Page::FRAME kPage_arch_update_mapping (page) else: t->share_prev = page->share_prev @@ -561,51 +626,52 @@ static void page_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapa t->share_prev->share_next = t kPage_arch_update_mapping (t) break - case Page::SET_FLAGS: - if cmd & Page::READONLY: + case Kernel::Page::SET_FLAGS: + if cmd & Kernel::Page::READONLY: reply_num (~0) return // Always refuse to set reserved flags. - c->data[1].h &= ~(Page::PHYSICAL | Page::UNCACHED) + c->data[1].h &= ~(Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED) // Remember the old flags. unsigned old = page->flags // Compute the new flags. unsigned new_flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h) // If we stop paying, see if the frame is still paid for. If not, free it. - if ~new_flags & old & Page::PAYING: + if ~new_flags & old & Kernel::Page::PAYING: // Decrease the use counter in any case. page->address_space->unuse () if !page_check_payment (page): - new_flags &= ~Page::FRAME + new_flags &= ~Kernel::Page::FRAME // If we start paying, increase the use counter. - if new_flags & ~old & Page::PAYING: + if new_flags & ~old & Kernel::Page::PAYING: if !page->address_space->use(): // If it doesn't work, refuse to set the flag, and refuse to allocate a frame. - new_flags &= ~(Page::PAYING | Page::FRAME) - if old & Page::FRAME: - new_flags |= Page::FRAME + new_flags &= ~(Kernel::Page::PAYING | Kernel::Page::FRAME) + if old & Kernel::Page::FRAME: + new_flags |= Kernel::Page::FRAME // If we want a frame, see if we can get it. - if ~old & new_flags & Page::FRAME: + if ~old & new_flags & Kernel::Page::FRAME: kPage *p for p = page; p; p = p->share_prev: - if p->flags & Page::PAYING: + if p->flags & Kernel::Page::PAYING: break if !p: for p = page->share_next; p; p = p->share_next: - if p->flags & Page::PAYING: + if p->flags & Kernel::Page::PAYING: break if !p: - new_flags &= ~Page::FRAME + new_flags &= ~Kernel::Page::FRAME // If we can get the new frame, get it. - if ~old & new_flags & Page::FRAME: + if ~old & new_flags & Kernel::Page::FRAME: page->frame = page->address_space->zalloc () kPage_arch_update_mapping (page) break default: - reply_num (ERR_INVALID_OPERATION) + dpanic (0, "invalid page operation") + reply_num (Kernel::ERR_INVALID_OPERATION) return reply_num (0) @@ -619,6 +685,9 @@ static void print_cap (kCapRef cap, kCapRef self): dbg_log_num (cap.index, 1) if !cap.valid (): dbg_log_char ('!') + else: + dbg_log_char ('=') + dbg_log_num (cap->protected_data.l) for kCapRef c = cap->children; c.valid (); c = c->sibling_next: print_cap (c, self) if cap.deref () == self.deref (): @@ -626,10 +695,17 @@ static void print_cap (kCapRef cap, kCapRef self): else: dbg_log_char (']') -static void caps_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): - kCaps *caps = (kCapsP)cap_protected.l +static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c): + kCaps *caps = (kCapsP)protected_data.l switch cmd: - case Caps::PRINT: + case Kernel::Caps::SET: + if c->data[1].l >= caps->size: + dpanic (0, "invalid index for set caps") + return + caps->clone (c->data[1].l, c->arg, c->copy[1]) + reply_num (0) + return + case Kernel::Caps::PRINT: if c->data[1].l >= caps->size: dpanic (0, "invalid caps for print") return @@ -662,66 +738,66 @@ static void caps_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapa dbg_log_char ('\n') return default: - reply_num (ERR_INVALID_OPERATION) + dpanic (0, "invalid caps operation") + reply_num (Kernel::ERR_INVALID_OPERATION) return -static void kill_reply (kCapability *self): - while self->parent.valid (): - self = self->parent.deref () - while self->sibling_prev.valid (): - self->sibling_prev->invalidate () - while self->sibling_next.valid (): - self->sibling_next->invalidate () - self->invalidate () +static void kill_reply (kReceiver *r): + kCapRef cap = r->refs + while cap.valid (): + kCapability *c = cap.deref () + cap = c->sibling_next + if (unsigned)c->target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY): + c->invalidate () -static void kernel_invoke (unsigned target, Num cap_protected, kCapability::Context *c, kCapability *self): +static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapability::Context *c): // Kernel calling convention: // data[0].l is the request. // caps[0] is the reply capability // other parameters' meanings depend on the operation. - if target == (CAPTYPE_RECEIVER | Receiver::CALL) || target == (CAPTYPE_RECEIVER | Receiver::CALL_ASYNC): - // This is a call capability. caps->cap (0) is the capability to call. It should be replaced by the reply capability. - reply_target = (kReceiver *)cap_protected.l - reply_target->protected_only = target == (CAPTYPE_RECEIVER | Receiver::CALL) + if target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL_ASYNC): + // This is a call capability. reply is the capability to call. It should be replaced by the reply capability. + ((kReceiver *)protected_data.l)->protected_only = target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL) if must_wait: old_current->wait () - if !c->caps || c->caps->size == 0: - // No caps, so no target to call. + if !reply_target: dpanic (0x54635675, "no target to call") return - kReceiver *call_target = c->caps->cap (0)->target - Num call_cap_protected = c->caps->cap (0)->cap_protected - if ((unsigned)call_target & ~KERNEL_MASK) != 0: + if ((unsigned)reply_target & ~KERNEL_MASK) != 0: // This is a user-implemented object. Create a real reply capability. - c->caps->cap (0)->invalidate () - c->caps->set (0, (kReceiver *)(CAPTYPE_RECEIVER | Receiver::REPLY), cap_protected, kCapRef (), &((kReceiver *)cap_protected.l)->refs) - call_target->send_message (call_cap_protected, c) - else if (unsigned)call_target == (CAPTYPE_RECEIVER | Receiver::REPLY): + kReceiver *call_target = reply_target + c->reply = kCapRef (&reply_caps, 0) + c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Kernel::Receiver::REPLY), protected_data, kCapRef (), &((kReceiver *)protected_data.l)->refs) + c->copy[0] = true + call_target->send_message (reply_protected, c) + c->reply->invalidate () + else if (unsigned)reply_target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY): // Reply capability: destroy all before invoke. - kill_reply (c->caps->cap (0)) - kReceiver *r = (kReceiver *)call_cap_protected.l + kReceiver *r = (kReceiver *)reply_protected.l + kill_reply (r) r->send_message (r->reply_protected_data, c) else: // Kernel call: don't create actual capablities. + kCapRef call_target = c->reply + c->reply.reset () + reply_target = (kReceiver *)protected_data.l reply_protected = reply_target->reply_protected_data - c->caps->cap (0)->invalidate () - kernel_invoke ((unsigned)call_target, call_cap_protected, c, NULL) + kernel_invoke ((unsigned)call_target->target, call_target->protected_data, c) return if must_wait: old_current->wait () - if target == (CAPTYPE_RECEIVER | Receiver::REPLY): + if target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY): // This is a reply capability. - kReceiver *r = (kReceiver *)cap_protected.l - kill_reply (self) + kReceiver *r = (kReceiver *)protected_data.l + kill_reply (r) r->send_message (r->reply_protected_data, c) return if !target: return - reply = kCapRef (c->caps, 0) unsigned cmd if (target & REQUEST_MASK) == CAP_MASTER: if c->data[0].l & CAP_MASTER_CREATE: - reply_cap (target | (c->data[0].l & REQUEST_MASK), cap_protected, &((kObject *)cap_protected.l)->refs) + reply_cap (target | (c->data[0].l & REQUEST_MASK), protected_data, &((kObject *)protected_data.l)->refs) return cmd = c->data[0].l c->data[0].l = 0 @@ -729,36 +805,38 @@ static void kernel_invoke (unsigned target, Num cap_protected, kCapability::Cont cmd = target & REQUEST_MASK switch target & CAPTYPE_MASK: case CAPTYPE_RECEIVER: - receiver_invoke (cmd, target, cap_protected, c) + receiver_invoke (cmd, target, protected_data, c) break case CAPTYPE_MEMORY: - memory_invoke (cmd, target, cap_protected, c) + memory_invoke (cmd, target, protected_data, c) break case CAPTYPE_THREAD: - thread_invoke (cmd, target, cap_protected, c) + thread_invoke (cmd, target, protected_data, c) break case CAPTYPE_PAGE: - page_invoke (cmd, target, cap_protected, c) + page_invoke (cmd, target, protected_data, c) break case CAPTYPE_CAPS: - caps_invoke (cmd, target, cap_protected, c) + caps_invoke (cmd, target, protected_data, c) break default: panic (0x99337744, "invalid capability type invoked") return return -void invoke (kReceiverP target, Num cap_protected, kCapability::Context *c, kCapability *self): +void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context *c): + //log_message ("invoke", (unsigned)target, protected_data.l, c) if (unsigned)target & ~KERNEL_MASK: // This is not a kernel capability: send a message to the receiver. if must_wait: old_current->wait () - target->send_message (cap_protected, c) + target->send_message (protected_data, c) return // This is a kernel capability. Use a function to allow optimized call capabilities. - if !c->caps || c->caps->size < 1: - reply_target = NULL + context = c + if c->reply.valid (): + reply_target = c->reply->target + reply_protected = c->reply->protected_data else: - reply_target = c->caps->cap (0)->target - reply_protected = c->caps->cap (0)->cap_protected - kernel_invoke ((unsigned)target, cap_protected, c, self) + reply_target = NULL + kernel_invoke ((unsigned)target, protected_data, c) diff --git a/iris.hhp b/iris.hhp index 9f51b91..63424cf 100644 --- a/iris.hhp +++ b/iris.hhp @@ -33,47 +33,6 @@ #define PAGE_SIZE (1 << PAGE_BITS) #define PAGE_MASK (~(PAGE_SIZE - 1)) -enum Exception_code: - NO_ERROR - ERR_WRITE_DENIED - ERR_UNMAPPED_READ - ERR_UNMAPPED_WRITE - ERR_INVALID_ADDRESS_READ - ERR_INVALID_ADDRESS_WRITE - ERR_RESERVED_INSTRUCTION - ERR_COPROCESSOR_UNUSABLE - ERR_OVERFLOW - ERR_TRAP - ERR_WATCHPOINT - ERR_BREAKPOINT - ERR_NO_PAGE_DIRECTORY - ERR_NO_PAGE_TABLE - ERR_OUT_OF_MEMORY - // The following are not raised, but returned. - ERR_INVALID_OPERATION - NUM_EXCEPTION_CODES - -#ifndef NDEBUG -static const char *exception_name[NUM_EXCEPTION_CODES] = { - "no error", - "write denied", - "unmapped read", - "unmapped write", - "invalid address read", - "invalid address write", - "reserved instruction", - "coprocessor unusable", - "overflow", - "trap", - "watchpoint", - "breakpoint", - "no page directory", - "no page table", - "out of memory", - "invalid operation" - } -#endif - #define KERNEL_MASK 0xfff #define CAPTYPE_MASK 0xe00 #define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK) @@ -94,425 +53,422 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = { // Master capabilities can create others. #define CAP_MASTER_CREATE (1 << 31) -struct Num: - unsigned l, h - Num (unsigned long long n = 0) : l (n), h (n >> 32): - Num (unsigned ll, unsigned hh) : l (ll), h (hh): - unsigned long long value () const: - return ((unsigned long long)h << 32) | l - unsigned &low (): - return l - unsigned &high (): - return h - unsigned const &low () const: - return l - unsigned const &high () const: - return h - -// The start function has this prototype (there is no main function). -Num start () - -struct Cap -struct Caps -struct Receiver -struct Thread -struct Page -struct Memory - #define __receiver_num 0 #define __thread_num 1 #define __memory_num 2 #define __call_num 3 #define __parent_num 4 -#define __tmp_slot 1 - // If this flag is set in a capability, it is copied instead of mapped. // If it is set in the target capability, the Thread waits after the request. #define CAP_COPY ((unsigned)0x80000000) // This constant signifies that no capability is passed. #define CAP_NONE (~CAP_COPY) -extern Receiver __my_receiver -extern Thread __my_thread -extern Memory __my_memory -extern Cap __my_call -extern Cap __my_parent -extern Caps __my_caps +namespace Kernel: + enum Exception_code: + NO_ERROR + ERR_WRITE_DENIED + ERR_UNMAPPED_READ + ERR_UNMAPPED_WRITE + ERR_INVALID_ADDRESS_READ + ERR_INVALID_ADDRESS_WRITE + ERR_RESERVED_INSTRUCTION + ERR_COPROCESSOR_UNUSABLE + ERR_OVERFLOW + ERR_TRAP + ERR_WATCHPOINT + ERR_BREAKPOINT + ERR_NO_PAGE_DIRECTORY + ERR_NO_PAGE_TABLE + ERR_OUT_OF_MEMORY + // The following are not raised, but returned. + ERR_INVALID_OPERATION + NUM_EXCEPTION_CODES -unsigned alloc_slot () -unsigned alloc_cap () -void free_slot (unsigned slot) -void free_cap (Cap cap) + #ifndef NDEBUG + static const char *exception_name[NUM_EXCEPTION_CODES] = { + "no error", + "write denied", + "unmapped read", + "unmapped write", + "invalid address read", + "invalid address write", + "reserved instruction", + "coprocessor unusable", + "overflow", + "trap", + "watchpoint", + "breakpoint", + "no page directory", + "no page table", + "out of memory", + "invalid operation" + } + #endif -struct Cap: - unsigned code - inline Cap copy () const - inline Cap () - explicit inline Cap (unsigned c) - inline Cap (unsigned slot, unsigned idx) - inline unsigned slot () const - inline unsigned idx () const - struct IMessage - struct OMessage - inline void invoke (IMessage const *i, OMessage *o) - inline void call (IMessage *i, OMessage *o) - inline void invoke (Num d0 = 0, Num d1 = 0) - inline Num call (Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0) - inline Num icall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0) - inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0) - inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0) - inline Cap clone (Cap target = Cap (0, alloc_cap ())) + struct Num: + unsigned l, h + Num (unsigned long long n = 0) : l (n), h (n >> 32): + Num (unsigned ll, unsigned hh) : l (ll), h (hh): + unsigned long long value () const: + return ((unsigned long long)h << 32) | l + unsigned &low (): + return l + unsigned &high (): + return h + unsigned const &low () const: + return l + unsigned const &high () const: + return h -struct Cap::IMessage: - Num data[2] - unsigned islot - unsigned oslot - unsigned num, first - Cap *set -struct Cap::OMessage: - Num data[2] - Num cap_protected - Num recv_protected -Cap Cap::copy () const: - return Cap (code | CAP_COPY) -Cap::Cap () : code (CAP_NONE): -Cap::Cap (unsigned c) : code (c): -Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)): -unsigned Cap::slot () const: - return (code >> 16) & 0x7fff -unsigned Cap::idx () const: - return code & 0xffff -void Cap::invoke (IMessage const *i, OMessage *o): - Cap *s = i->set - __asm__ volatile ("lw $v0, %3\n" - "\tlw $t0, 0($v0)\n" - "\tlw $t1, 4($v0)\n" - "\tlw $v0, %2\n" - "\tlw $a0, 0($v0)\n" - "\tlw $a1, 4($v0)\n" - "\tlw $a2, 8($v0)\n" - "\tlw $a3, 12($v0)\n" - "\tlw $s0, 16($v0)\n" - "\tlw $s1, 20($v0)\n" - "\tlw $s2, 24($v0)\n" - "\tlw $s3, 28($v0)\n" - "\tlw $v0, %1\n" - "\tsyscall\n" - "\tlw $v0, %0\n" - "\tsw $a0, 0($v0)\n" - "\tsw $a1, 4($v0)\n" - "\tsw $a2, 8($v0)\n" - "\tsw $a3, 12($v0)\n" - "\tsw $s0, 16($v0)\n" - "\tsw $s1, 20($v0)\n" - "\tsw $s2, 24($v0)\n" - "\tsw $s3, 28($v0)" - : "=m"(o) - : "m"(code), "m"(i), "m"(s) - : "memory", "v0", "s0", "s1", "s2", "s3", "a0", "a1", "a2", "a3", "t0", "t1") -void Cap::call (IMessage *i, OMessage *o): - i->set[0] = *this - __my_call.copy ().invoke (i, o) -void Cap::invoke (Num d0, Num d1): - IMessage i - OMessage o - i.oslot = ~0 - i.islot = ~0 - Cap cs[2] - i.set = cs - i.num = 0 - i.data[0] = d0 - i.data[1] = d1 - invoke (&i, &o) -Num Cap::call (Num d0, Num d1, unsigned oslot, unsigned islot): - IMessage i - OMessage o - Cap cs[2] - i.set = cs - i.oslot = oslot - i.islot = islot - i.num = 2 - i.first = 0 - i.data[0] = d0 - i.data[1] = d1 - call (&i, &o) - return o.data[0] -Num Cap::icall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot): - IMessage i - OMessage o - Cap cs[2] - i.set = cs - i.oslot = oslot - i.islot = islot - i.num = 2 - i.first = 0 - i.data[0] = d0 - i.data[1] = d1 - call (&i, &o) - Cap (oslot, 0).clone (c) - return o.data[0] -Num Cap::ocall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot): - IMessage i - OMessage o - Cap cs[2] - cs[1] = c - i.set = cs - i.oslot = oslot - i.islot = islot - i.num = 2 - i.first = 0 - i.data[0] = d0 - i.data[1] = d1 - call (&i, &o) - return o.data[0] -Num Cap::iocall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot): - IMessage i - OMessage o - Cap cs[2] - cs[1] = c - i.set = cs - i.oslot = oslot - i.islot = islot - i.num = 2 - i.first = 0 - i.data[0] = d0 - i.data[1] = d1 - call (&i, &o) - Cap (oslot, 0).clone (c) - return o.data[0] -Cap Cap::clone (Cap target): - IMessage i - OMessage o - Cap cs[2] - cs[0] = this->copy () - i.set = cs - i.oslot = target.slot () - i.first = target.idx () - i.num = 1 - i.islot = ~0 - i.data[0] = 0 - i.data[1] = 0 - Cap ().invoke (&i, &o) - return target + struct Cap + struct Caps + struct Receiver + struct Thread + struct Page + struct Memory -struct Receiver : public Cap: - Receiver (unsigned slot, unsigned idx) : Cap (slot, idx): - Receiver (Cap c = Cap ()) : Cap (c): - enum request: - // Operations - SET_OWNER = 1 - CREATE_CAPABILITY - CREATE_CALL_CAPABILITY - CREATE_ASYNC_CALL_CAPABILITY - GET_REPLY_PROTECTED_DATA - SET_REPLY_PROTECTED_DATA - GET_ALARM - SET_ALARM - ADD_ALARM - // Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability. - REPLY - // A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY. - CALL - // A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY. - CALL_ASYNC - void set_owner (Cap owner): - ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER) - Cap create_capability (unsigned protected_data, Cap ret = Cap (0, alloc_cap ())): - icall (ret, CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data) + unsigned alloc_slot () + Cap alloc_cap () + void free_slot (unsigned slot) + void free_cap (Cap cap) + + struct Cap: + unsigned code + inline Cap copy () const + inline Cap () + explicit inline Cap (unsigned c) + inline Cap (unsigned slot, unsigned idx) + inline unsigned slot () const + inline unsigned idx () const + struct IMessage + inline void invoke (Num d0 = 0, Num d1 = 0, Cap arg = Cap (CAP_NONE)) + inline Num call (Num d0 = 0, Num d1 = 0) + inline Num icall (Num d0 = 0, Num d1 = 0) + inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0) + inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0) + inline void _invoke (IMessage const *i) + inline void _call (IMessage *i) + + struct __recv_data_t: + Num data[2] + Num protected_data + Cap reply, arg + + extern Receiver my_receiver + extern Thread my_thread + extern Memory my_memory + extern Cap my_call + extern Cap my_parent + extern __recv_data_t recv + + inline Cap get_reply (): + Cap ret = recv.reply + recv.reply = alloc_cap () return ret - Num get_reply_protected_data (): - return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA) - void set_reply_protected_data (Num data): - call (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data) - unsigned get_alarm (): - return call (CAP_MASTER_DIRECT | GET_ALARM).l - unsigned add_alarm (unsigned data): - return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l - void set_alarm (unsigned data): - call (CAP_MASTER_DIRECT | SET_ALARM, data) - static inline void sleep (unsigned value, OMessage *ret, unsigned slot = __tmp_slot) - Cap create_call_capability (Cap ret = Cap (0, alloc_cap ())): - icall (ret, CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY) - return ret - Cap create_async_call_capability (Cap ret = Cap (0, alloc_cap ())): - icall (ret, CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY) + inline Cap get_arg (): + Cap ret = recv.arg + recv.arg = alloc_cap () return ret + inline void set_recv_arg (Cap c): + free_cap (recv.arg) + recv.arg = c -struct Thread : public Cap: - Thread (unsigned slot, unsigned idx) : Cap (slot, idx): - Thread (Cap c = Cap ()) : Cap (c): - enum request: - // Info details are arch-specific. - GET_INFO = 1 - SET_INFO - USE_SLOT - SCHEDULE - PRIV_ALLOC_RANGE - PRIV_PHYSICAL_ADDRESS - PRIV_ALLOC_PHYSICAL - PRIV_MAKE_PRIV - PRIV_GET_TOP_MEMORY - PRIV_REGISTER_INTERRUPT - // This is not an operation, but having this capability allows using the thread in Receiver::set_owner. - SET_OWNER - // These get/set_info are not arch-specific. - enum info_type: - PC = ~0 - SP = ~1 - FLAGS = ~2 - enum flags: - PRIV = 1 << 31 - WAITING = 1 << 30 - RUNNING = 1 << 29 - USER_FLAGS = ~(PRIV | WAITING | RUNNING) - void make_priv (): - __my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV) - unsigned get_info (unsigned info): - return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l - void set_info (unsigned info, unsigned value, unsigned mask = ~0): - call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask)) - void set_pc (unsigned pc): - set_info (PC, pc) - void set_sp (unsigned sp): - set_info (SP, sp) - void set_flags (unsigned value, unsigned mask): - set_info (FLAGS, value, mask) - unsigned get_pc (): - return get_info (PC) - unsigned get_sp (): - return get_info (SP) - unsigned get_flags (): - return get_info (FLAGS) - void run (bool run): - set_flags (run ? RUNNING : 0, RUNNING) - void wait (bool wait): - set_flags (wait ? WAITING : 0, WAITING) - inline unsigned use (Caps caps, unsigned slot = alloc_slot ()) + struct Cap::IMessage: + Num data[2] + Cap reply, arg + Cap Cap::copy () const: + return Cap (code | CAP_COPY) + Cap::Cap () : code (CAP_NONE): + Cap::Cap (unsigned c) : code (c): + Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)): + unsigned Cap::slot () const: + return (code >> 16) & 0x7fff + unsigned Cap::idx () const: + return code & 0xffff + void Cap::_invoke (IMessage const *i): + __recv_data_t *r = &recv + __asm__ volatile ("lw $v0, %1\n" + "\tlw $a0, 0($v0)\n" + "\tlw $a1, 4($v0)\n" + "\tlw $a2, 8($v0)\n" + "\tlw $a3, 12($v0)\n" + "\tlw $t0, 16($v0)\n" + "\tlw $t1, 20($v0)\n" + "\tlw $v0, %2\n" + "\tlw $t2, 24($v0)\n" + "\tlw $t3, 28($v0)\n" + "\tlw $v0, %0\n" + "\tsyscall\n" + "\tlw $v0, %2\n" + "\tsw $a0, 0($v0)\n" + "\tsw $a1, 4($v0)\n" + "\tsw $a2, 8($v0)\n" + "\tsw $a3, 12($v0)\n" + "\tsw $t0, 16($v0)\n" + "\tsw $t1, 20($v0)" + :: "m"(code), "m"(i), "m"(r) + : "memory", "v0", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3") + void Cap::_call (IMessage *i): + i->reply = *this + my_call.copy ()._invoke (i) + void Cap::invoke (Num d0, Num d1, Cap arg): + IMessage i + i.data[0] = d0 + i.data[1] = d1 + i.reply = Cap (CAP_NONE) + i.arg = arg + _invoke (&i) + Num Cap::call (Num d0, Num d1): + IMessage i + i.data[0] = d0 + i.data[1] = d1 + _call (&i) + return recv.data[0] + Num Cap::icall (Num d0, Num d1): + IMessage i + i.data[0] = d0 + i.data[1] = d1 + _call (&i) + return recv.data[0] + Num Cap::ocall (Cap c, Num d0, Num d1): + IMessage i + i.data[0] = d0 + i.data[1] = d1 + i.arg = c + _call (&i) + return recv.data[0] + Num Cap::iocall (Cap c, Num d0, Num d1): + IMessage i + i.data[0] = d0 + i.data[1] = d1 + i.arg = c + _call (&i) + return recv.data[0] -struct Caps : public Cap: - Caps (unsigned slot, unsigned idx) : Cap (slot, idx): - Caps (Cap c = Cap ()) : Cap (c): - enum request: - // Not an operation; this capability can be used in Thread::USE_SLOT. - USE = 1 - PRINT - unsigned use (unsigned slot = alloc_slot ()): - return __my_thread.use (*this, slot) - void print (unsigned idx): - invoke (CAP_MASTER_DIRECT | PRINT, idx) + struct Receiver : public Cap: + Receiver (unsigned slot, unsigned idx) : Cap (slot, idx): + Receiver (Cap c = Cap ()) : Cap (c): + enum request: + // Operations + SET_OWNER = 1 + CREATE_CAPABILITY + CREATE_CALL_CAPABILITY + CREATE_ASYNC_CALL_CAPABILITY + GET_REPLY_PROTECTED_DATA + SET_REPLY_PROTECTED_DATA + GET_ALARM + SET_ALARM + ADD_ALARM + // Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability. + REPLY + // A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY. + CALL + // A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY. + CALL_ASYNC + void set_owner (Cap owner): + ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER) + Cap create_capability (Num protected_data): + icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data) + return get_arg () + Num get_reply_protected_data (): + return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA) + void set_reply_protected_data (Num data): + call (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data) + unsigned get_alarm (): + return call (CAP_MASTER_DIRECT | GET_ALARM).l + unsigned add_alarm (unsigned data): + return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l + void set_alarm (unsigned data): + call (CAP_MASTER_DIRECT | SET_ALARM, data) + static inline void sleep (unsigned value) + Cap create_call_capability (): + icall (CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY) + return get_arg () + Cap create_async_call_capability (): + icall (CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY) + return get_arg () -unsigned Thread::use (Caps caps, unsigned slot): - ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot) - return slot + struct Thread : public Cap: + Thread (unsigned slot, unsigned idx) : Cap (slot, idx): + Thread (Cap c = Cap ()) : Cap (c): + enum request: + // Info details are arch-specific. + GET_INFO = 1 + SET_INFO + USE_SLOT + SCHEDULE + PRIV_ALLOC_RANGE + PRIV_PHYSICAL_ADDRESS + PRIV_ALLOC_PHYSICAL + PRIV_MAKE_PRIV + PRIV_GET_TOP_MEMORY + PRIV_REGISTER_INTERRUPT + // This is not an operation, but having this capability allows using the thread in Receiver::set_owner. + SET_OWNER + DBG_SEND + PRIV_PANIC + // These get/set_info are not arch-specific. + enum info_type: + PC = ~0 + SP = ~1 + FLAGS = ~2 + enum flags: + PRIV = 1 << 31 + WAITING = 1 << 30 + RUNNING = 1 << 29 + USER_FLAGS = ~(PRIV | WAITING | RUNNING) + void make_priv (): + my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV) + unsigned get_info (unsigned info): + return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l + void set_info (unsigned info, unsigned value, unsigned mask = ~0): + call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask)) + void set_pc (unsigned pc): + set_info (PC, pc) + void set_sp (unsigned sp): + set_info (SP, sp) + void set_flags (unsigned value, unsigned mask): + set_info (FLAGS, value, mask) + unsigned get_pc (): + return get_info (PC) + unsigned get_sp (): + return get_info (SP) + unsigned get_flags (): + return get_info (FLAGS) + void run (bool run): + set_flags (run ? RUNNING : 0, RUNNING) + void wait (bool wait): + set_flags (wait ? WAITING : 0, WAITING) + inline unsigned use (Caps caps, unsigned slot = alloc_slot ()) -struct Page : public Cap: - Page (unsigned slot, unsigned idx) : Cap (slot, idx): - Page (Cap c = Cap ()) : Cap (c): - enum request: - SHARE = 1 - GET_FLAGS - SET_FLAGS - // Not an operation; a capability with this bit cannot write to the page. - READONLY = 8 - enum share_detail: - // Operation details for PAGE_SHARE - // Forget the source page during the operation. This makes it a move. - FORGET - // Make the target independent of the source (make a copy if needed). - COPY - // Make the target unwritable. - //READONLY: use the value from request. - enum flag_values: - // This is a read-only flag, which is set if the Page is shared. - SHARED = 1 - // 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. - PAYING = 2 - // Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems. - FRAME = 4 - // 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. - //READONLY = 8 - // This is a read-only flag, saying if this is physical memory, which mustn't be freed. - PHYSICAL = 0x10 - // This is a read-only flag, saying if this is uncachable memory. - UNCACHED = 0x20 - void share (Cap target, unsigned flags): - ocall (target, CAP_MASTER_DIRECT | SHARE, flags) - unsigned get_flags (): - return call (CAP_MASTER_DIRECT | GET_FLAGS).l - void set_flags (unsigned new_flags, unsigned mask): - call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask)) - unsigned physical_address (): - return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l - void alloc_physical (unsigned address, bool cachable, bool freeable): - __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0)) + struct Caps : public Cap: + Caps (unsigned slot, unsigned idx) : Cap (slot, idx): + Caps (Cap c = Cap ()) : Cap (c): + enum request: + // Not an operation; this capability can be used in Thread::USE_SLOT. + USE = 1 + SET + PRINT + unsigned use (unsigned slot = alloc_slot ()): + return my_thread.use (*this, slot) + void set (unsigned idx, Cap cap): + ocall (cap, CAP_MASTER_DIRECT | SET, idx) + void print (unsigned idx): + invoke (CAP_MASTER_DIRECT | PRINT, idx) -struct Memory : public Cap: - Memory (unsigned slot, unsigned idx) : Cap (slot, idx): - Memory (Cap c = Cap ()) : Cap (c): - enum request: - CREATE = 1 - DESTROY - LIST - MAP - MAPPING - GET_LIMIT - SET_LIMIT - Page create_page (Page ret = Cap (0, alloc_cap ())): - icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE)) - return ret - Thread create_thread (unsigned slots, Thread ret = Cap (0, alloc_cap ())): - icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots) - return ret - Receiver create_receiver (Receiver ret = Cap (0, alloc_cap ())): - icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER)) - return ret - Memory create_memory (Memory ret = Cap (0, alloc_cap ())): - icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY)) - return ret - Caps create_caps (unsigned size, Caps ret = Cap (0, alloc_cap ())): - icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size) - return ret - void destroy (Cap target): - ocall (target, CAP_MASTER_DIRECT | DESTROY) - // TODO: LIST - void map (Cap page, unsigned address, bool readonly = false): - if readonly: - address |= Page::READONLY - ocall (page, CAP_MASTER_DIRECT | MAP, address) - Page mapping (void *address, Page ret = Cap (0, alloc_cap ())): - icall (ret, CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address)) - return ret - unsigned get_limit (unsigned limit): - return call (CAP_MASTER_DIRECT | GET_LIMIT).l - void set_limit (unsigned limit): - call (CAP_MASTER_DIRECT | SET_LIMIT, limit) - unsigned alloc_range (unsigned pages): - return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l + unsigned Thread::use (Caps caps, unsigned slot): + ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot) + return slot -struct Kernel: - static void wait (Cap::OMessage *o, unsigned islot = ~0): + struct Page : public Cap: + Page (unsigned slot, unsigned idx) : Cap (slot, idx): + Page (Cap c = Cap ()) : Cap (c): + enum request: + SHARE = 1 + GET_FLAGS + SET_FLAGS + // Not an operation; a capability with this bit cannot write to the page. + READONLY = 8 + enum share_detail: + // Operation details for PAGE_SHARE + // Forget the source page during the operation. This makes it a move. + FORGET + // Make the target independent of the source (make a copy if needed). + COPY + // Make the target unwritable. + //READONLY: use the value from request. + enum flag_values: + // This is a read-only flag, which is set if the Page is shared. + SHARED = 1 + // 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. + PAYING = 2 + // Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems. + FRAME = 4 + // 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. + //READONLY = 8 + // This is a read-only flag, saying if this is physical memory, which mustn't be freed. + PHYSICAL = 0x10 + // This is a read-only flag, saying if this is uncachable memory. + UNCACHED = 0x20 + void share (Cap target, unsigned flags): + ocall (target, CAP_MASTER_DIRECT | SHARE, flags) + unsigned get_flags (): + return call (CAP_MASTER_DIRECT | GET_FLAGS).l + void set_flags (unsigned new_flags, unsigned mask): + call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask)) + unsigned physical_address (): + return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l + void alloc_physical (unsigned address, bool cachable, bool freeable): + my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0)) + + struct Memory : public Cap: + Memory (unsigned slot, unsigned idx) : Cap (slot, idx): + Memory (Cap c = Cap ()) : Cap (c): + enum request: + CREATE = 1 + DESTROY + LIST + MAP + MAPPING + GET_LIMIT + SET_LIMIT + Page create_page (): + icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE)) + return get_arg () + Thread create_thread (unsigned slots): + icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots) + return get_arg () + Receiver create_receiver (): + icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER)) + return get_arg () + Memory create_memory (): + icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY)) + return get_arg () + Caps create_caps (unsigned size): + icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size) + return get_arg () + void destroy (Cap target): + ocall (target, CAP_MASTER_DIRECT | DESTROY) + // TODO: LIST + void map (Cap page, unsigned address, bool readonly = false): + if readonly: + address |= Page::READONLY + ocall (page, CAP_MASTER_DIRECT | MAP, address) + Page mapping (void *address): + icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address)) + return get_arg () + unsigned get_limit (unsigned limit): + return call (CAP_MASTER_DIRECT | GET_LIMIT).l + void set_limit (unsigned limit): + call (CAP_MASTER_DIRECT | SET_LIMIT, limit) + unsigned alloc_range (unsigned pages): + return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l + + inline void wait (): Cap::IMessage i - i.islot = islot - i.num = 0 - i.first = 0 - i.oslot = ~0 - Cap cs[2] - i.set = cs - Cap ().copy ().invoke (&i, o) - static void schedule (): - __my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE) - static void register_interrupt (unsigned num): - __my_thread.ocall (__my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num) - static void unregister_interrupt (unsigned num): - __my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num) - static Cap get_top_memory (Cap ret = Cap (0, alloc_cap ())): - __my_thread.icall (ret, CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY) - return ret + Cap ().copy ()._invoke (&i) + inline void schedule (): + my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE) + inline void register_interrupt (unsigned num): + my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num) + inline void unregister_interrupt (unsigned num): + my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num) + inline Cap get_top_memory (): + my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY) + return get_arg () + inline void dbg_send (unsigned code, unsigned bits = 32): + my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits)) + inline void panic (unsigned code): + my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code) -void Receiver::sleep (unsigned value, OMessage *ret, unsigned slot): - __my_receiver.set_alarm (value) - Kernel::wait (ret, slot) + void Receiver::sleep (unsigned value): + my_receiver.set_alarm (value) + wait () + +// The start function has this prototype (there is no main function). +Kernel::Num start () #if 1 // Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing. diff --git a/kernel.hhp b/kernel.hhp index 35f4e7c..825e0e8 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -60,7 +60,7 @@ struct kCapRef: kCapRef (kCapsP c, unsigned i) : caps (c), index (i): kCapRef () : caps (NULL), index (~0): inline void clone (kCapRef source, bool copy) - inline void set (kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL) + inline void set (kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL) struct kObject: kCapRef refs @@ -80,20 +80,17 @@ bool kObject::is_free (): // Include architecture-specific parts. #include "arch.hh" -struct kMessage : public kObject: - Num cap_protected - Num data[2] - kCapsP caps - struct kCapability : public kObject: struct Context: - Num data[2] - kCaps *caps + Kernel::Num data[2] + kCapRef reply + kCapRef arg + bool copy[2] kReceiverP target kCapRef parent kCapRef children kCapRef sibling_prev, sibling_next - Num cap_protected + Kernel::Num protected_data inline void invoke (kCapability::Context *c) void invalidate () @@ -103,7 +100,7 @@ struct kThread : public kObject: kThread_arch arch unsigned flags kThreadP schedule_prev, schedule_next - unsigned recv_slot + unsigned recv_reply, recv_arg // caps is an array of slots pointers to kCapses. unsigned slots // TODO: handle freeing of capses which are in use. @@ -114,9 +111,8 @@ struct kThread : public kObject: void wait () void unwait () bool is_waiting (): - return flags & Thread::WAITING + return flags & Kernel::Thread::WAITING kCapRef find_capability (unsigned code, bool *copy) - void fill_slot (unsigned slot, kCaps *new_caps) struct kReceiver : public kObject: kThreadP owner @@ -131,15 +127,14 @@ struct kReceiver : public kObject: // The message queue. kMessages are added at the tail, and removed at the front. kMessageP messages kMessageP last_message - Num recv_protected - Num reply_protected_data + Kernel::Num reply_protected_data bool protected_only // This limit is for messages stored in its address space. There is unlimited space if senders provide it. unsigned queue_limit void own (kThreadP o) void orphan () bool try_deliver () - bool send_message (Num cap_protected, kCapability::Context *c) + bool send_message (Kernel::Num protected_data, kCapability::Context *c) struct kPage : public kObject: unsigned frame @@ -154,9 +149,15 @@ struct kCaps : public kObject: kCapability caps[1] kCapability *cap (unsigned idx): return &caps[idx] - void set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL) + void set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL) void clone (unsigned index, kCapRef source, bool copy) +struct kMessage : public kObject: + Kernel::Num protected_data + Kernel::Num data[2] + // This is a real Caps of two elements, not a link. + kCaps caps + struct kMemory : public kObject: kFree *frees kPageP pages @@ -203,7 +204,7 @@ extern "C": #define panic(n, m) panic_impl ((n), __LINE__, __PRETTY_FUNCTION__, (m)) void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "") #ifndef NDEBUG - EXTERN Num dbg_code + EXTERN Kernel::Num dbg_code EXTERN kCapRef dbg_cap void dbg_log_char (unsigned ch) void dbg_log (char const *str) @@ -241,11 +242,11 @@ unsigned phys_alloc (unsigned num) void phys_free (unsigned page, unsigned num) // Defind in invoke.ccp -void invoke (kReceiverP target, Num cap_protected, kCapability::Context *c, kCapability *self) +void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context *c) // Defined by architecture-specific files. void kThread_arch_init (kThread *thread) -void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data) +void kThread_arch_receive (kThread *thread, Kernel::Num protected_data, Kernel::Num *data) unsigned *kThread_arch_info (kThread *thread, unsigned num) void kMemory_arch_init (kMemory *mem) void kMemory_arch_free (kMemory *mem) @@ -265,10 +266,10 @@ kCapability *kCapRef::deref (): return caps ? caps->cap (index) : NULL void kCapRef::clone (kCapRef source, bool copy): caps->clone (index, source, copy) -void kCapRef::set (kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr): +void kCapRef::set (kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr): caps->set (index, target, pdata, parent, parent_ptr) void kCapability::invoke (kCapability::Context *c): - ::invoke (target, cap_protected, c, this) + ::invoke (target, protected_data, c) #define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0) diff --git a/memory.ccp b/memory.ccp index 258e758..5c244f3 100644 --- a/memory.ccp +++ b/memory.ccp @@ -77,7 +77,6 @@ unsigned phys_alloc (unsigned num): return ret void phys_free (unsigned page, unsigned num): - return unsigned size = num << PAGE_BITS if !first_free || (unsigned)first_free > page: // This is the first free block. diff --git a/mips/arch.ccp b/mips/arch.ccp index f9f68df..c520501 100644 --- a/mips/arch.ccp +++ b/mips/arch.ccp @@ -34,15 +34,13 @@ void kThread_arch_init (kThread *thread): thread->arch.hi = 0 thread->arch.lo = 0 -void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data): +void kThread_arch_receive (kThread *thread, Kernel::Num protected_data, Kernel::Num *data): thread->arch.a[0] = data[0].l thread->arch.a[1] = data[0].h thread->arch.a[2] = data[1].l thread->arch.a[3] = data[1].h - thread->arch.s[0] = cap_protected.l - thread->arch.s[1] = cap_protected.h - thread->arch.s[2] = recv_protected.l - thread->arch.s[3] = recv_protected.h + thread->arch.t[0] = protected_data.l + thread->arch.t[1] = protected_data.h unsigned *kThread_arch_info (kThread *thread, unsigned num): switch num: @@ -184,7 +182,7 @@ static unsigned make_entry_lo (kPage *page, bool readonly): if !page->frame: return 0 unsigned flags - if page->flags & Page::UNCACHED: + if page->flags & Kernel::Page::UNCACHED: flags = 0x10 | 0x2 else: flags = 0x18 | 0x2 @@ -271,7 +269,7 @@ void kPage_arch_update_mapping (kPage *page): if !page->arch.first_mapped: return kMemory *as = page->address_space - unsigned target = make_entry_lo (page, page->flags & Page::READONLY) + unsigned target = make_entry_lo (page, page->flags & Kernel::Page::READONLY) for arch_page *p = page->arch.first_mapped; p; p = p->next_mapped: unsigned de = p->mapping >> 21 unsigned te = (p->mapping >> 12) & ((1 << 9) - 1) diff --git a/mips/init.ccp b/mips/init.ccp index 31b2699..9729372 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -24,7 +24,6 @@ #define NUM_SLOTS 4 #define NUM_CAPS 16 -#define NUM_TMP_CAPS 2 static void init_idle (): // initialize idle task as if it is currently running. @@ -34,7 +33,7 @@ static void init_idle (): idle.schedule_next = NULL idle.address_space = &idle_memory idle.refs.reset () - idle.flags = Thread::RUNNING | Thread::PRIV + idle.flags = Kernel::Thread::RUNNING | Kernel::Thread::PRIV // initialize idle_memory. idle_memory.prev = NULL idle_memory.next = NULL @@ -53,7 +52,7 @@ static void init_idle (): idle_page.prev = NULL idle_page.next = NULL idle_page.frame = 0x80000000 - idle_page.flags = Page::PAYING | Page::FRAME + idle_page.flags = Kernel::Page::PAYING | Kernel::Page::FRAME idle_page.refs.reset () idle_page.address_space = NULL current = &idle @@ -156,7 +155,7 @@ static void init_threads (): if !pages[idx]: pages[idx] = mem->alloc_page () pages[idx]->frame = thread_start[i] + (idx << PAGE_BITS) - pages[idx]->flags = Page::PAYING | Page::FRAME + pages[idx]->flags = Kernel::Page::PAYING | Kernel::Page::FRAME ++top_memory.limit mem->use () if !mem->map (pages[idx], p, readonly): @@ -177,7 +176,7 @@ static void init_threads (): if !page->frame: panic (0x02220022, "out of memory"); return - page->flags = Page::PAYING | Page::FRAME + page->flags = Kernel::Page::PAYING | Kernel::Page::FRAME if !mem->map (page, p): panic (0x33557799, "unable to map initial bss page") return @@ -198,22 +197,21 @@ static void init_threads (): top_memory.pfree (thread_start[i] + (p << PAGE_BITS)) kPage *stackpage = mem->alloc_page () stackpage->frame = mem->zalloc () - stackpage->flags = Page::PAYING | Page::FRAME + stackpage->flags = Kernel::Page::PAYING | Kernel::Page::FRAME if !stackpage || !mem->map (stackpage, 0x7ffff000): panic (0x13151719, "unable to map initial stack page") return thread->caps[0] = mem->alloc_caps (NUM_CAPS) - thread->caps[__tmp_slot] = mem->alloc_caps (NUM_TMP_CAPS) thread->arch.a[0] = NUM_SLOTS thread->arch.a[1] = NUM_CAPS kReceiver *recv = mem->alloc_receiver () recv->owner = thread thread->receivers = recv - thread->caps[0]->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Num ((unsigned)recv), kCapRef (), &recv->refs) - thread->caps[0]->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Num ((unsigned)thread), kCapRef (), &thread->refs) - thread->caps[0]->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Num ((unsigned)mem), kCapRef (), &mem->refs) - thread->caps[0]->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Receiver::CALL), Num ((unsigned)recv), kCapRef (), &recv->refs) - thread->flags = Thread::RUNNING | Thread::PRIV + thread->caps[0]->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs) + thread->caps[0]->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Kernel::Num ((unsigned)thread), kCapRef (), &thread->refs) + thread->caps[0]->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Kernel::Num ((unsigned)mem), kCapRef (), &mem->refs) + thread->caps[0]->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Kernel::Receiver::CALL), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs) + thread->flags = Kernel::Thread::RUNNING | Kernel::Thread::PRIV if !i: first_scheduled = thread init_receiver = recv diff --git a/mips/interrupts.ccp b/mips/interrupts.ccp index 48b5c94..dbde802 100644 --- a/mips/interrupts.ccp +++ b/mips/interrupts.ccp @@ -31,7 +31,7 @@ static void handle_exit (): schedule () if !current: current = &idle - if (current->flags & (Thread::RUNNING | Thread::WAITING)) != Thread::RUNNING: + if (current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) != Kernel::Thread::RUNNING: panic (current->flags, "non-scheduled thread running") if !current: current = &idle @@ -55,7 +55,7 @@ static void handle_exit (): asids[current->address_space->arch.asid] = (unsigned)current->address_space cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid) directory = current->address_space->arch.directory - if current->flags & Thread::PRIV: + if current->flags & Kernel::Thread::PRIV: cp0_set (CP0_STATUS, 0x1000ff13) else: cp0_set (CP0_STATUS, 0x0000ff13) @@ -68,7 +68,7 @@ kThread *tlb_refill (): if !directory: unsigned addr cp0_get (CP0_BAD_V_ADDR, addr) - current->raise (ERR_NO_PAGE_DIRECTORY, addr) + current->raise (Kernel::ERR_NO_PAGE_DIRECTORY, addr) handle_exit () return current unsigned EntryHi @@ -77,7 +77,7 @@ kThread *tlb_refill (): if !t: unsigned addr cp0_get (CP0_BAD_V_ADDR, addr) - current->raise (ERR_NO_PAGE_TABLE, addr) + current->raise (Kernel::ERR_NO_PAGE_TABLE, addr) else: // - 2 instead of - 1 means reset bit 0 unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2) @@ -104,7 +104,6 @@ kThread *interrupt (): kCapability::Context c for unsigned j = 0; j < 2; ++j: c.data[j] = 0 - c.caps = NULL arch_interrupt_receiver[i]->send_message (i, &c) arch_interrupt_receiver[i] = NULL if ipr & (1 << IRQ_OST0): @@ -130,40 +129,23 @@ static void arch_invoke (): target = old_current->find_capability (old_current->arch.v[0], &must_wait) do_schedule = false kCapability::Context msg - unsigned num = old_current->arch.s[2] - unsigned first = old_current->arch.s[3] - if num > 2: - dpanic (0x23451234, "too many capabilities") - num = 2 - if old_current->arch.s[1] < old_current->slots: - msg.caps = old_current->caps[old_current->arch.s[1]] - if msg.caps: - for unsigned i = 0; i < num && first + i < msg.caps->size; ++i: - unsigned code = old_current->arch.t[i] - msg.caps->cap (first + i)->invalidate () - bool copy - kCapRef t = old_current->find_capability (code, ©) - if t.valid (): - msg.caps->clone (first + i, t, copy) - else: - if num: - dpanic (0x34566244, "num without caps") - if old_current->arch.s[1] != ~0: - dpanic (0x28849932, "non-~0 slot too high") - msg.caps = NULL + msg.reply = old_current->find_capability (old_current->arch.t[0], &msg.copy[0]) + msg.arg = old_current->find_capability (old_current->arch.t[1], &msg.copy[1]) if must_wait: - old_current->recv_slot = old_current->arch.s[0] + bool dummy + old_current->recv_reply = old_current->arch.t[2] + old_current->recv_arg = old_current->arch.t[3] if !target.valid (): if must_wait: old_current->wait () return - msg.data[0] = Num (old_current->arch.a[0], old_current->arch.a[1]) - msg.data[1] = Num (old_current->arch.a[2], old_current->arch.a[3]) + msg.data[0] = Kernel::Num (old_current->arch.a[0], old_current->arch.a[1]) + msg.data[1] = Kernel::Num (old_current->arch.a[2], old_current->arch.a[3]) target->invoke (&msg) if do_schedule && !must_wait: // If the call was to schedule without wait, it isn't done yet. schedule () - else if old_current != current && (old_current->flags & (Thread::RUNNING | Thread::WAITING)) == Thread::RUNNING: + else if old_current != current && (old_current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) == Kernel::Thread::RUNNING: // If the caller received an immediate reply from the kernel, it is no longer set as current. Don't let it lose its timeslice. current = old_current @@ -181,31 +163,31 @@ kThread *exception (): // TLB modification. unsigned addr cp0_get (CP0_BAD_V_ADDR, addr) - current->raise (ERR_WRITE_DENIED, addr) + current->raise (Kernel::ERR_WRITE_DENIED, addr) break case 2: // TLB load or instruction fetch. unsigned addr cp0_get (CP0_BAD_V_ADDR, addr) - current->raise (ERR_UNMAPPED_READ, addr) + current->raise (Kernel::ERR_UNMAPPED_READ, addr) break case 3: // TLB store. unsigned addr cp0_get (CP0_BAD_V_ADDR, addr) - current->raise (ERR_UNMAPPED_WRITE, addr) + current->raise (Kernel::ERR_UNMAPPED_WRITE, addr) break case 4: // Address error load or instruction fetch. unsigned addr cp0_get (CP0_BAD_V_ADDR, addr) - current->raise (ERR_INVALID_ADDRESS_READ, addr) + current->raise (Kernel::ERR_INVALID_ADDRESS_READ, addr) break case 5: // Address error store. unsigned addr cp0_get (CP0_BAD_V_ADDR, addr) - current->raise (ERR_INVALID_ADDRESS_WRITE, addr) + current->raise (Kernel::ERR_INVALID_ADDRESS_WRITE, addr) break case 6: // Bus error instruction fetch. @@ -224,7 +206,7 @@ kThread *exception (): case 9: // Breakpoint. #if 0 || defined (NDEBUG) - //current->raise (ERR_BREAKPOINT, 0) + //current->raise (Kernel::ERR_BREAKPOINT, 0) #ifndef NDEBUG current->pc += 4 #endif @@ -250,19 +232,19 @@ kThread *exception (): break case 10: // Reserved instruction. - current->raise (ERR_RESERVED_INSTRUCTION, 0) + current->raise (Kernel::ERR_RESERVED_INSTRUCTION, 0) break case 11: // Coprocessor unusable. - current->raise (ERR_COPROCESSOR_UNUSABLE, 0) + current->raise (Kernel::ERR_COPROCESSOR_UNUSABLE, 0) break case 12: // Arithmetic overflow. - current->raise (ERR_OVERFLOW, 0) + current->raise (Kernel::ERR_OVERFLOW, 0) break case 13: // Trap. - current->raise (ERR_TRAP, 0) + current->raise (Kernel::ERR_TRAP, 0) break case 15: // Floating point exception. @@ -270,7 +252,7 @@ kThread *exception (): break case 23: // Reference to WatchHi/WatchLo address. - current->raise (ERR_WATCHPOINT, 0) + current->raise (Kernel::ERR_WATCHPOINT, 0) break case 24: // Machine check. diff --git a/mips/jz4730.hhp b/mips/jz4730.hhp index 2c2d190..dd69953 100644 --- a/mips/jz4730.hhp +++ b/mips/jz4730.hhp @@ -135,14 +135,14 @@ // Default lcd framebuffer mapping space. #define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000) -// Map IO memory (requires a priviledged __my_thread capability). +// Map IO memory (requires a priviledged Kernel::my_thread capability). #include static void __map_io (unsigned physical, unsigned mapping): - Page p = __my_memory.create_page () + Kernel::Page p = Kernel::my_memory.create_page () // false means not cachable; false means don't free when done. p.alloc_physical (physical, false, false) - __my_memory.map (p, mapping) - free_cap (p) + Kernel::my_memory.map (p, mapping) + Kernel::free_cap (p) #define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0) #define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0) @@ -2324,8 +2324,8 @@ static __inline__ void udelay (unsigned us): #ifndef __KERNEL static __inline__ void cdelay (unsigned ds): - __my_receiver.set_alarm (ds * (HZ / 100)) - Cap ().call (~0) + Kernel::my_receiver.set_alarm (ds * (HZ / 100)) + Kernel::Cap ().call (~0) #endif /*************************************************************************** diff --git a/panic.ccp b/panic.ccp index c46a0c1..6e3bcce 100644 --- a/panic.ccp +++ b/panic.ccp @@ -23,10 +23,10 @@ void dbg_log_char (unsigned ch): if !dbg_cap.valid (): return kCapability::Context c - c.caps = NULL c.data[0] = ch - c.data[1] = 0 + ++dbg_code.l dbg_cap->invoke (&c) + --dbg_code.l void dbg_log (char const *str): while *str: @@ -38,7 +38,7 @@ void dbg_log_num (unsigned num, unsigned digits): dbg_log_char (encode[(num >> (4 * ((digits - 1) - i))) & 0xf]) return -#if 0 || defined (NDEBUG) +#if 1 || defined (NDEBUG) void panic_impl (unsigned n, unsigned line, char const *name, char const *message): // Stop all threads. while first_scheduled: diff --git a/schedule.ccp b/schedule.ccp index 3a27c51..a1abd5d 100644 --- a/schedule.ccp +++ b/schedule.ccp @@ -36,31 +36,30 @@ static void unrun_thread (kThread *thread): thread->schedule_next->schedule_prev = thread->schedule_prev void kThread::run (): - if flags & Thread::RUNNING: + if flags & Kernel::Thread::RUNNING: return - flags |= Thread::RUNNING + flags |= Kernel::Thread::RUNNING if is_waiting (): return run_thread (this) void kThread::unrun (): - if !(flags & Thread::RUNNING): + if !(flags & Kernel::Thread::RUNNING): return - flags &= ~Thread::RUNNING + flags &= ~Kernel::Thread::RUNNING if is_waiting (): return unrun_thread (this) void kThread::unwait (): - flags &= ~Thread::WAITING - if flags & Thread::RUNNING: + flags &= ~Kernel::Thread::WAITING + if flags & Kernel::Thread::RUNNING: run_thread (this) static void alarm_tick (kReceiver *recv): if !recv->alarm_count: // Send message and stop counting. kCapability::Context c - c.caps = NULL for unsigned i = 0; i < 2; ++i: c.data[i] = 0 recv->send_message (~0, &c) @@ -74,9 +73,9 @@ static void alarm_tick (kReceiver *recv): --recv->alarm_count void kThread::wait (): - if flags & Thread::RUNNING: + if flags & Kernel::Thread::RUNNING: unrun_thread (this) - flags |= Thread::WAITING + flags |= Kernel::Thread::WAITING // Try to receive a message from a kReceiver immediately. for kReceiver *r = receivers; r; r = r->next_owned: if r->try_deliver ():