1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2025-01-17 11:51:05 +02:00

working with new invoke system

This commit is contained in:
Bas Wijnen 2009-09-06 11:04:09 +02:00
parent 4c73b034f8
commit a838dd63c6
16 changed files with 982 additions and 965 deletions

View File

@ -195,9 +195,10 @@ kThread *kMemory::alloc_thread (unsigned size):
return ret return ret
kMessage *kMemory::alloc_message (kReceiver *target): 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: if !ret:
return NULL return NULL
ret->caps.size = 2
if !ret->next: if !ret->next:
target->last_message = ret target->last_message = ret
return ret return ret
@ -243,9 +244,9 @@ kMemory *kMemory::alloc_memory ():
kMemory_arch_init (ret) kMemory_arch_init (ret)
return 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].target = target
caps[index].cap_protected = pdata caps[index].protected_data = pdata
caps[index].parent = parent caps[index].parent = parent
caps[index].children.reset () caps[index].children.reset ()
caps[index].sibling_prev.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) caps[index].sibling_next->sibling_prev = kCapRef (this, index)
void kCaps::clone (unsigned index, kCapRef source, bool copy): void kCaps::clone (unsigned index, kCapRef source, bool copy):
cap (index)->invalidate ()
if !source.valid ():
return
if copy: if copy:
if source->parent.valid (): 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: 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: 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: else:
set (index, source->target, source->cap_protected, source) set (index, source->target, source->protected_data, source)
void kMemory::free_page (kPage *page): void kMemory::free_page (kPage *page):
if page->flags & Page::PAYING: if page->flags & Kernel::Page::PAYING:
unuse () unuse ()
if page->frame: if page->frame:
pfree (page->frame) pfree (page->frame)
@ -324,7 +328,7 @@ void kCapability::invalidate ():
else if (unsigned)target & ~KERNEL_MASK: else if (unsigned)target & ~KERNEL_MASK:
target->capabilities = sibling_next target->capabilities = sibling_next
else: else:
((kObject *)cap_protected.l)->refs = sibling_next ((kObject *)protected_data.l)->refs = sibling_next
if sibling_next.valid (): if sibling_next.valid ():
sibling_next->sibling_prev = sibling_prev sibling_next->sibling_prev = sibling_prev
parent.reset () parent.reset ()
@ -342,7 +346,7 @@ void kCapability::invalidate ():
c->children.reset () c->children.reset ()
c->sibling_prev.reset () c->sibling_prev.reset ()
c->sibling_next.reset () c->sibling_next.reset ()
c->cap_protected = 0 c->protected_data = 0
c = next c = next
void kMemory::free_caps (kCaps *c): void kMemory::free_caps (kCaps *c):
@ -376,8 +380,8 @@ void kPage::forget ():
share_next = NULL share_next = NULL
else: else:
// If the page has a frame and should be freed, free it. // 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) raw_pfree (frame)
frame = 0 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) kPage_arch_update_mapping (this)

View File

@ -28,46 +28,53 @@ static unsigned __slots, __caps
static list *__slot_admin, *__cap_admin static list *__slot_admin, *__cap_admin
static list *__first_free_slot, *__first_free_cap static list *__first_free_slot, *__first_free_cap
Receiver __my_receiver namespace Kernel:
Thread __my_thread Receiver my_receiver
Memory __my_memory Thread my_thread
Cap __my_call Memory my_memory
Cap __my_parent Cap my_call
Cap my_parent
__recv_data_t recv
void free_slot (unsigned slot): void free_slot (unsigned slot):
__slot_admin[slot].prev = NULL __slot_admin[slot].prev = NULL
__slot_admin[slot].next = __first_free_slot __slot_admin[slot].next = __first_free_slot
if __slot_admin[slot].next: if __slot_admin[slot].next:
__slot_admin[slot].next->prev = &__slot_admin[slot] __slot_admin[slot].next->prev = &__slot_admin[slot]
__first_free_slot = &__slot_admin[slot] __first_free_slot = &__slot_admin[slot]
void free_cap (Cap cap): void free_cap (Cap cap):
list *l = &__cap_admin[cap.idx ()] if cap.slot () != 0:
l->prev = NULL kdebug ("trying to free capability from non-0 slot\n")
l->next = __first_free_cap return
if l->next: list *l = &__cap_admin[cap.idx ()]
l->next->prev = l l->prev = NULL
__first_free_cap = l l->next = __first_free_cap
if l->next:
l->next->prev = l
__first_free_cap = l
unsigned alloc_slot (): unsigned alloc_slot ():
if !__first_free_slot: if !__first_free_slot:
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT. // Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
return ~0 kdebug ("out of slots!\n")
list *ret = __first_free_slot return ~0
__first_free_slot = ret->next list *ret = __first_free_slot
if ret->next: __first_free_slot = ret->next
ret->next->prev = NULL if ret->next:
return ret - __slot_admin ret->next->prev = NULL
return ret - __slot_admin
unsigned alloc_cap (): Cap alloc_cap ():
if !__first_free_cap: if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return NO_CAPABILITY. // Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
return ~0 kdebug ("out of capabilities!\n")
list *ret = __first_free_cap return Cap (0, CAP_NONE)
__first_free_cap = ret->next list *ret = __first_free_cap
if ret->next: __first_free_cap = ret->next
ret->next->prev = NULL if ret->next:
return ret - __cap_admin ret->next->prev = NULL
return Cap (0, ret - __cap_admin)
extern "C": extern "C":
void __main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin): void __main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
@ -77,18 +84,20 @@ extern "C":
__cap_admin = cap_admin __cap_admin = cap_admin
__first_free_slot = NULL __first_free_slot = NULL
for unsigned i = 2; i < __slots; ++i: for unsigned i = 2; i < __slots; ++i:
free_slot (i) Kernel::free_slot (i)
__first_free_cap = NULL __first_free_cap = NULL
for unsigned i = 7; i < __caps; ++i: for unsigned i = 7; i < __caps; ++i:
free_cap (Cap (0, i)) Kernel::free_cap (Kernel::Cap (0, i))
__my_receiver = Cap (0, __receiver_num) Kernel::my_receiver = Kernel::Cap (0, __receiver_num)
__my_thread = Cap (0, __thread_num) Kernel::my_thread = Kernel::Cap (0, __thread_num)
__my_memory = Cap (0, __memory_num) Kernel::my_memory = Kernel::Cap (0, __memory_num)
__my_call = Cap (0, __call_num) Kernel::my_call = Kernel::Cap (0, __call_num)
__my_parent = Cap (0, __parent_num) Kernel::my_parent = Kernel::Cap (0, __parent_num)
Num ret = start () Kernel::recv.reply = Kernel::alloc_cap ()
__my_parent.invoke (~0, ret) Kernel::recv.arg = Kernel::alloc_cap ()
__my_memory.destroy (__my_thread) 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. // The program no longer exists. If it somehow does, generate an address fault.
while true: while true:
*(volatile unsigned *)~0 *(volatile unsigned *)~0

View File

@ -24,59 +24,59 @@
// This shouldn't really be here. But where should it be? // This shouldn't really be here. But where should it be?
// Requests made by initial threads to tell init about themselves. // Requests made by initial threads to tell init about themselves.
enum init_requests: enum init_requests:
INIT_SET_GPIO INIT_SET_GPIO = 1
INIT_SET_LCD INIT_SET_LCD
// List interface. // List interface.
template <typename _T> // template <typename _T> //
struct List : public Cap: struct List : public Kernel::Cap:
List (Cap c = Cap ()) : Cap (c): List (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
// TODO // TODO
struct String : public Cap: struct String : public Kernel::Cap:
String (Cap c = Cap ()) : Cap (c): String (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
// TODO // TODO
// Keyboard interface. // Keyboard interface.
struct Keyboard : public Cap: struct Keyboard : public Kernel::Cap:
Keyboard (Cap c = Cap ()) : Cap (c): Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request: enum request:
SET_CB SET_CB = 1
GET_KEYS GET_KEYS
// At event: the callback is called with a keycode. One bit defines if it's a press or release event. // At event: the callback is called with a keycode. One bit defines if it's a press or release event.
enum constant: enum constant:
RELEASE = 1 << 31 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. // 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) ocall (cb, CAP_MASTER_DIRECT | SET_CB)
// Get a list of keys on this keyboard. The key codes start at zero with no gaps. // Get a list of keys on this keyboard. The key codes start at zero with no gaps.
List <String> get_keys (List <String> ret = Cap (0, alloc_cap ())): List <String> get_keys ():
icall (ret, CAP_MASTER_DIRECT | GET_KEYS) icall (CAP_MASTER_DIRECT | GET_KEYS)
return ret return Kernel::get_arg ()
// Display interface. // Display interface.
struct Display : public Cap: struct Display : public Kernel::Cap:
Display (Cap c = Cap ()) : Cap (c): Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request: enum request:
EOF_CB EOF_CB = 1
CREATE_FB CREATE_FB
USE_FB USE_FB
GET_INFO GET_INFO
// Register an end-of-frame callback. // 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. // 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) ocall (cb, CAP_MASTER_DIRECT | EOF_CB)
// Create a framebuffer for the display. When not in use, it can be freed by the user. // 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 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 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. // 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): unsigned create_framebuffer (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 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. // 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. // 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. // 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): void use_framebuffer (unsigned addr, Kernel::Cap unuse_cb = Kernel::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)) ocall (unuse_cb, Kernel::Num (CAP_MASTER_DIRECT | USE_FB, addr), Kernel::Num ((w << 16) | h, mode))
// Get information about the display. // Get information about the display.
void get_info (): void get_info ():
// TODO: Interface is to be designed. // TODO: Interface is to be designed.
@ -86,91 +86,95 @@ struct Display : public Cap:
// File system interface. // File system interface.
// filesystem-related interfaces: file, directory, stream, seekable, mappable. // filesystem-related interfaces: file, directory, stream, seekable, mappable.
// Normal files implement at least stream or seekable file. Directories implement directory. // Normal files implement at least stream or seekable file. Directories implement directory.
struct File : public Cap: struct File : public Kernel::Cap:
File (Cap c = Cap ()) : Cap (c): File (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request: enum request:
INFO INFO = 1
CLOSE CLOSE
MAP_HANDLE MAP_HANDLE
// Get information about the file. // Get information about the file.
Num get_info (unsigned type, Caps ret = Cap ()): Kernel::Num get_info (unsigned type):
return icall (ret, Num (CAP_MASTER_DIRECT | INFO, 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. // Close a file. If this is a directory, it implicitly closes all files opened from it.
void close (): void close ():
call (CAP_MASTER_DIRECT | 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. // 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): File map_handle ():
icall (ret, CAP_MASTER_DIRECT | MAP_HANDLE) icall (CAP_MASTER_DIRECT | MAP_HANDLE)
return Kernel::get_arg ()
// Directory interface. // Directory interface.
struct Directory : public File: struct Directory : public File:
Directory (Cap c = Cap ()) : File (c): Directory (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request: enum request:
GET_SIZE GET_SIZE = 1
GET_NAME GET_NAME
GET_FILE GET_FILE
GET_FILE_INFO GET_FILE_INFO
CREATE_FILE CREATE_FILE
DELETE_FILE DELETE_FILE
// Get the number of entries in this directory. // Get the number of entries in this directory.
Num get_size (): Kernel::Num get_size ():
return call (CAP_MASTER_DIRECT | 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. // 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): String get_name (Kernel::Num idx):
icall (target, CAP_MASTER_DIRECT | GET_NAME, idx) icall (CAP_MASTER_DIRECT | GET_NAME, idx)
return Kernel::get_arg ()
// Get the file. // Get the file.
void get_file (Num idx, File ret): File get_file (Kernel::Num idx):
icall (ret, CAP_MASTER_DIRECT | GET_FILE, 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. // 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 ()): Kernel::Num get_file_info (Kernel::Num idx, unsigned type):
return icall (ret, Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx) 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. // Create a new file. After this, any index may map to a different file.
void create_file (String name, File ret): File create_file (String name):
icall (ret, CAP_MASTER_DIRECT | CREATE_FILE) icall (CAP_MASTER_DIRECT | CREATE_FILE)
return Kernel::get_arg ()
// Delete a file. After this, any index may map to a different file. // 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) call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
// Stream interface. // Stream interface.
struct Stream : public File: struct Stream : public File:
Stream (Cap c = Cap ()) : File (c): Stream (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request: enum request:
READ READ = 1
WRITE WRITE
// Try to read size bytes. Returns the number of bytes successfully read. // Try to read size bytes. Returns the number of bytes successfully read.
Num read (Num size, String ret): Kernel::Num read (Kernel::Num size):
return icall (ret, CAP_MASTER_DIRECT | READ, size) return icall (CAP_MASTER_DIRECT | READ, size)
// Try to write size bytes. Returns the number of bytes successfully written. // 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) return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
// Seekable file interface. // Seekable file interface.
struct Seekable : public File: struct Seekable : public File:
Seekable (Cap c = Cap ()) : File (c): Seekable (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request: enum request:
READ READ = 1
WRITE WRITE
TRUNCATE TRUNCATE
// Try to read size bytes from position idx. Returns the number of bytes successfully read. // Try to read size bytes from position idx. Returns the number of bytes successfully read.
Num read (Num idx, unsigned size, String ret): Kernel::Num read (Kernel::Num idx, unsigned size):
return icall (ret, Num (CAP_MASTER_DIRECT | READ, size), idx) 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. // 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) return ocall (s, CAP_MASTER_DIRECT | WRITE, idx)
// Truncate file to size idx. The file is extended with zeroes if it gets longer. // 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) call (CAP_MASTER_DIRECT | TRUNCATE, idx)
// Mappable file interface. // Mappable file interface.
struct Mappable : public Seekable: struct Mappable : public Seekable:
Mappable (Cap c = Cap ()) : Seekable (c): Mappable (Kernel::Cap c = Kernel::Cap ()) : Seekable (c):
// TODO: to be designed. // TODO: to be designed.
// Block device interface. // Block device interface.
struct Block_device : public Mappable: 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. // TODO: to be designed.

View File

@ -59,29 +59,14 @@ enum cap_type:
CAP_LOCKLEDS CAP_LOCKLEDS
CAP_PWM CAP_PWM
static unsigned events static Kernel::Cap events[NUM_EVENTS]
static Caps event_caps
static void event (event_type type, unsigned data): static void event (event_type type, unsigned data):
kdebug ("event t/d/e=") events[type].invoke (data)
kdebug_num (type)
kdebug_char ('/')
kdebug_num (data)
kdebug_char ('/')
kdebug_num (events)
kdebug_char ('\n')
Cap (events, type).invoke (data)
static void set_cb (Cap cap, event_type type): static void set_cb (event_type type):
kdebug ("gpio set cb ") Kernel::free_cap (events[type])
kdebug_num (type) events[type] = Kernel::get_arg ()
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)
class DevKeyboard: class DevKeyboard:
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] 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: for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
keys[col] = 0xff keys[col] = 0xff
scan () scan ()
event (KEYBOARD_EVENT, ~0)
enum Keys: enum Keys:
N0, N1, N2, N3, N4, N5, N6, N7, N8, N9 N0, N1, N2, N3, N4, N5, N6, N7, N8, N9
@ -225,7 +209,6 @@ class Touchpad:
void send_initial (): void send_initial ():
old_state = 0 old_state = 0
check_events () check_events ()
event (TOUCHPAD_EVENT, ~0)
class Lockleds: class Lockleds:
// Note that num lock is in port 2. The others are in port 0. // 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) 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. // 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 () Kernel::schedule ()
map_gpio () map_gpio ()
map_pwm0 () map_pwm0 ()
event_caps = __my_memory.create_caps (NUM_EVENTS) for unsigned i = 0; i < NUM_EVENTS; ++i:
events = event_caps.use () events[i] = Kernel::alloc_cap ()
DevKeyboard kbd DevKeyboard kbd
Touchpad tp Touchpad tp
Lockleds leds Lockleds leds
Pwm pwm Pwm pwm
Caps c = __my_memory.create_caps (4) Kernel::Caps c = Kernel::my_memory.create_caps (4)
unsigned init_slot = c.use () unsigned init_slot = c.use ()
__my_receiver.create_capability (CAP_KEYBOARD, Cap (init_slot, 0)) Kernel::set_recv_arg (Kernel::Cap (init_slot, 0))
__my_receiver.create_capability (CAP_TOUCHPAD, Cap (init_slot, 1)) Kernel::my_receiver.create_capability (CAP_KEYBOARD)
__my_receiver.create_capability (CAP_LOCKLEDS, Cap (init_slot, 2)) Kernel::set_recv_arg (Kernel::Cap (init_slot, 1))
__my_receiver.create_capability (CAP_PWM, Cap (init_slot, 3)) 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_cap (c)
free_slot (init_slot) Kernel::free_slot (init_slot)
if kbd.is_scanning (): if kbd.is_scanning ():
__my_receiver.set_alarm (ALARM_INTERVAL) Kernel::my_receiver.set_alarm (ALARM_INTERVAL)
// Enable interrupts. All are in port 0. // 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 GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
Kernel::register_interrupt (IRQ_GPIO0) Kernel::register_interrupt (IRQ_GPIO0)
kdebug ("gpio ready\n")
unsigned slot = alloc_slot ()
while true: while true:
Kernel::schedule () Kernel::schedule ()
Cap::OMessage msg Kernel::wait ()
Kernel::wait (&msg, slot) switch Kernel::recv.protected_data.l:
switch (unsigned)msg.cap_protected.value ():
case ~0: case ~0:
// Alarm. // Alarm.
kbd.scan () kbd.scan ()
if kbd.is_scanning (): if kbd.is_scanning ():
__my_receiver.set_alarm (ALARM_INTERVAL) Kernel::my_receiver.set_alarm (ALARM_INTERVAL)
break break
case IRQ_GPIO0: case IRQ_GPIO0:
// Always scan keyboard and touchpad on any interrupt. // Always scan keyboard and touchpad on any interrupt.
@ -321,20 +305,29 @@ Num start ():
Kernel::register_interrupt (IRQ_GPIO0) Kernel::register_interrupt (IRQ_GPIO0)
break break
case CAP_KEYBOARD: case CAP_KEYBOARD:
set_cb (Cap (slot, 1), KEYBOARD_EVENT) kdebug ("gpio: keyboard callback registered.\n")
Cap (slot, 0).invoke () set_cb (KEYBOARD_EVENT)
Kernel::recv.reply.invoke ()
kbd.send_initial () kbd.send_initial ()
event (KEYBOARD_EVENT, ~0)
break break
case CAP_TOUCHPAD: case CAP_TOUCHPAD:
set_cb (Cap (slot, 1), TOUCHPAD_EVENT) kdebug ("gpio: touchpad callback registered.\n")
Cap (slot, 0).invoke () set_cb (TOUCHPAD_EVENT)
Kernel::recv.reply.invoke ()
tp.send_initial () tp.send_initial ()
event (TOUCHPAD_EVENT, ~0)
break break
case CAP_LOCKLEDS: case CAP_LOCKLEDS:
leds.set (msg.data[0].l) leds.set (Kernel::recv.data[0].l)
Cap (slot, 0).invoke () Kernel::recv.reply.invoke ()
break break
case CAP_PWM: case CAP_PWM:
pwm.set_backlight (msg.data[0].l) pwm.set_backlight (Kernel::recv.data[0].l)
Cap (slot, 0).invoke () Kernel::recv.reply.invoke ()
break
default:
kdebug ("invalid gpio operation ")
kdebug_num (Kernel::recv.protected_data.l)
kdebug ("\n")
break break

View File

@ -21,7 +21,7 @@
static Keyboard kbd, tp static Keyboard kbd, tp
static Display lcd static Display lcd
static Cap lockleds, pwm static Kernel::Cap lockleds, pwm
// Event types. // Event types.
enum type: enum type:
@ -30,71 +30,63 @@ enum type:
static void setup (): static void setup ():
unsigned state = 0 unsigned state = 0
unsigned slot = alloc_slot () Kernel::recv.arg = Kernel::alloc_cap ()
while true: while true:
Cap::OMessage msg Kernel::wait ()
Kernel::wait (&msg, slot) switch Kernel::recv.data[0].value ():
switch msg.data[0].value ():
case INIT_SET_GPIO: case INIT_SET_GPIO:
kdebug ("gpio\n") 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 () unsigned gpio_slot = caps.use ()
Cap (slot, 0).invoke () kbd = Kernel::Cap (gpio_slot, 0)
kbd = Cap (gpio_slot, 0) tp = Kernel::Cap (gpio_slot, 1)
tp = Cap (gpio_slot, 1) lockleds = Kernel::Cap (gpio_slot, 2)
lockleds = Cap (gpio_slot, 2) pwm = Kernel::Cap (gpio_slot, 3)
pwm = Cap (gpio_slot, 3) reply.invoke ()
Kernel::free_cap (reply)
++state ++state
break break
case INIT_SET_LCD: case INIT_SET_LCD:
kdebug ("lcd\n") kdebug ("lcd\n")
lcd = Cap (slot, 1).clone () lcd = Kernel::get_arg ()
Cap (slot, 0).invoke () Kernel::recv.reply.invoke ()
++state ++state
break break
if state == 2: if state == 2:
break break
Caps caps = __my_memory.create_caps (2) Kernel::schedule ()
Cap kc = __my_receiver.create_capability (KBD, Cap (slot, 0)) kdebug ("init registering keyboard\n")
kdebug ("init0: ") Kernel::Cap kc = Kernel::my_receiver.create_capability (KBD)
caps.print (0)
kbd.set_cb (kc) kbd.set_cb (kc)
kdebug ("init1: ") Kernel::Cap tc = Kernel::my_receiver.create_capability (TP)
caps.print (0)
Cap tc = __my_receiver.create_capability (TP, Cap (slot, 1))
kdebug ("init2: ")
caps.print (1)
tp.set_cb (tc) tp.set_cb (tc)
kdebug ("init3: ")
caps.print (1)
pwm.call (1) pwm.call (1)
free_slot (slot)
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":" char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
Num start (): Kernel::Num start ():
// Set up lcd first // Set up lcd first
Kernel::schedule () Kernel::schedule ()
kdebug ("start init\n") kdebug ("start init\n")
setup () setup ()
kdebug ("run init\n") kdebug ("run init\n")
while true: while true:
Cap::OMessage msg Kernel::wait ()
Kernel::wait (&msg) switch Kernel::recv.protected_data.value ():
switch msg.cap_protected.value ():
case KBD: case KBD:
unsigned code = msg.data[0].l unsigned code = Kernel::recv.data[0].l
if code & Keyboard::RELEASE: if code & Keyboard::RELEASE:
break break
kdebug_char (decode_kbd[code]) kdebug_char (decode_kbd[code])
break break
case TP: case TP:
unsigned leds = 0 unsigned leds = 0
if msg.data[0].l & 1: if Kernel::recv.data[0].l & 1:
leds |= 0x1 leds |= 0x1
else: else:
leds |= 0x4 leds |= 0x4
if !(msg.data[0].l & Keyboard::RELEASE): if !(Kernel::recv.data[0].l & Keyboard::RELEASE):
leds |= 0x2 leds |= 0x2
lockleds.call (leds) lockleds.call (leds)
break break

View File

@ -103,7 +103,7 @@ static void log_str (char const *str):
while *str: while *str:
log_char (*str++) log_char (*str++)
static void log_num (Num n): static void log_num (Kernel::Num n):
char const *encode = "0123456789abcdef" char const *encode = "0123456789abcdef"
log_char ('[') log_char ('[')
for unsigned i = 0; i < 8; ++i: 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 (encode[(n.l >> (4 * (7 - i))) & 0xf])
log_char (']') log_char (']')
static void log_msg (Cap::OMessage *msg): static void log_msg ():
log_str ("cap_prot:") log_str ("prot:")
log_num (msg->cap_protected) log_num (Kernel::recv.protected_data)
log_str ("data:") log_str ("data:")
for unsigned i = 0; i < 2; ++i: for unsigned i = 0; i < 2; ++i:
log_num (msg->data[i]) log_num (Kernel::recv.data[i])
log_char ('\n') log_char ('\n')
Num start (): Kernel::Num start ():
map_lcd () map_lcd ()
map_cpm () map_cpm ()
Descriptor descriptor __attribute__ ((aligned (16))) Descriptor descriptor __attribute__ ((aligned (16)))
unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS 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) assert (physical & PAGE_MASK && ~physical)
for unsigned i = 0; i < pages; ++i: 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) p.alloc_physical (physical + i * PAGE_SIZE, false, true)
__my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE) Kernel::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE)
free_cap (p) Kernel::free_cap (p)
for unsigned y = 0; y < 480; ++y: for unsigned y = 0; y < 480; ++y:
unsigned g = (y << 6) / 480 unsigned g = (y << 6) / 480
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480) unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
@ -150,9 +150,9 @@ Num start ():
ob = b ob = b
b = 0x1f b = 0x1f
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b) 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) physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK)
free_cap (p) Kernel::free_cap (p)
descriptor.next = physical_descriptor descriptor.next = physical_descriptor
descriptor.frame = physical descriptor.frame = physical
descriptor.id = 0xdeadbeef descriptor.id = 0xdeadbeef
@ -161,28 +161,32 @@ Num start ():
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0") __asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
reset () 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") __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) Kernel::Cap set_eof_cb = Kernel::my_receiver.create_capability (LCD_EOF_CB)
__my_parent.ocall (set_eof_cb, INIT_SET_LCD) Kernel::my_parent.ocall (set_eof_cb, INIT_SET_LCD)
unsigned slot = alloc_slot () unsigned slot = Kernel::alloc_slot ()
Cap eof_cb (0, alloc_cap ()) Kernel::Cap eof_cb = Kernel::alloc_cap ()
while true: while true:
Cap::OMessage msg Kernel::wait ()
Kernel::wait (&msg, slot) //log_msg ()
//log_msg (&msg) switch Kernel::recv.protected_data.l:
switch msg.cap_protected.value ():
case IRQ_LCD: case IRQ_LCD:
lcd_clr_eof () lcd_clr_eof ()
eof_cb.invoke () eof_cb.invoke ()
break break
case LCD_EOF_CB: case LCD_EOF_CB:
Cap (slot, 1).clone (eof_cb) Kernel::free_cap (eof_cb)
Cap (slot, 0).invoke () eof_cb = Kernel::recv.arg
Kernel::recv.arg = Kernel::alloc_cap ()
Kernel::recv.reply.invoke ()
Kernel::register_interrupt (IRQ_LCD) Kernel::register_interrupt (IRQ_LCD)
break break
case LCD_LOG: case LCD_LOG:
log_char (msg.data[0].l) log_char (Kernel::recv.data[0].l)
break
default:
log_char ('~')
break break

View File

@ -18,13 +18,44 @@
#include "kernel.hh" #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): void kThread::raise (unsigned code, unsigned data):
dpanic (code, "raise") dpanic (code, "raise")
dbg_log ("raise ") dbg_log ("raise ")
dbg_log_num ((unsigned)current) dbg_log_num ((unsigned)current)
dbg_log_char ('/') dbg_log_char ('/')
if code < NUM_EXCEPTION_CODES: if code < Kernel::NUM_EXCEPTION_CODES:
dbg_log (exception_name[code]) dbg_log (Kernel::exception_name[code])
else: else:
dbg_log ("invalid code:") dbg_log ("invalid code:")
dbg_log_num (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: if slots < 1 || !caps[0] || !caps[0]->cap (0)->target:
return return
kCapability::Context c kCapability::Context c
c.caps = NULL c.data[0] = Kernel::Num (code, data)
c.data[0] = Num (code, data)
c.data[1] = 0
caps[0]->cap (0)->invoke (&c) caps[0]->cap (0)->invoke (&c)
// From user-provided, thus untrusted, data, find a capability. // 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 ()
return kCapRef (caps[slot], num) 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. // Try to deliver a message.
bool kReceiver::try_deliver (): bool kReceiver::try_deliver ():
if !messages: if !messages:
@ -85,24 +103,37 @@ bool kReceiver::try_deliver ():
kMessage *m = last_message kMessage *m = last_message
if protected_only: if protected_only:
for ; m; m = (kMessage *)m->prev: 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 protected_only = false
break break
if !m: if !m:
return false return false
owner->fill_slot (owner->recv_slot, m->caps) bool dummy
kThread_arch_receive (owner, m->cap_protected, recv_protected, m->data) 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) address_space->free_message (this, m)
owner->unwait () owner->unwait ()
return true return true
// Send a message to a receiver; try to deliver it immediately. // Send a message to a receiver; try to deliver it immediately.
bool kReceiver::send_message (Num cap_protected, kCapability::Context *c): bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *c):
if owner && owner->is_waiting () && (cap_protected.value () == reply_protected_data.value () || !protected_only): //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: if protected_only:
protected_only = false protected_only = false
owner->fill_slot (owner->recv_slot, c->caps) bool dummy
kThread_arch_receive (owner, cap_protected, recv_protected, c->data) 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 () owner->unwait ()
return true return true
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue. // 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. // TODO: use sender-provided storage.
if !msg: if !msg:
return false return false
msg->cap_protected = cap_protected msg->protected_data = protected_data
if protected_only && cap_protected.value () == reply_protected_data.value (): 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. // Put this message in the end (where it will be first seen). Clear the protected_only flag.
protected_only = false protected_only = false
if msg->next: if msg->next:
@ -128,59 +159,69 @@ bool kReceiver::send_message (Num cap_protected, kCapability::Context *c):
last_message = msg last_message = msg
for unsigned i = 0; i < 2; ++i: for unsigned i = 0; i < 2; ++i:
msg->data[i] = c->data[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 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 kReceiver *reply_target
static Num reply_protected static Kernel::Num reply_protected
static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0): static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
kCapability::Context c kCapability::Context c
c.data[0] = Num (num1, num2) c.data[0] = Kernel::Num (num1, num2)
c.data[1] = num3 c.data[1] = num3
c.caps = NULL if reply_target:
invoke (reply_target, reply_protected, &c, NULL) reply_target->send_message (reply_protected, &c)
static void reply_cap (unsigned target, Num cap_protected, kCapRef *ref):
if reply.valid ():
reply.set ((kReceiver *)target, cap_protected, kCapRef (), ref)
else: else:
dpanic (0x87677654, "no target to reply capability to") dpanic (0, "nothing to reply to")
reply_num (0)
static void receiver_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): static void reply_cap (unsigned target, Kernel::Num protected_data, kCapRef *ref):
kReceiver *receiver = (kReceiver *)cap_protected.l 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: switch cmd:
case Receiver::SET_OWNER: case Kernel::Receiver::SET_OWNER:
if c->caps->size < 2: if !c->arg.valid ():
reply_num (~0) reply_num (~0)
return return
unsigned cap = (unsigned)c->caps->cap (1)->target unsigned cap = (unsigned)c->arg->target
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Thread::SET_OWNER): if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Kernel::Thread::SET_OWNER):
// FIXME: This makes it impossible to use a fake kThread capability. // FIXME: This makes it impossible to use a fake kThread capability.
return return
receiver->own ((kThread *)c->caps->cap (1)->cap_protected.l) receiver->own ((kThread *)c->arg->protected_data.l)
break break
case Receiver::CREATE_CAPABILITY: case Kernel::Receiver::CREATE_CAPABILITY:
reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities) reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities)
return return
case Receiver::CREATE_CALL_CAPABILITY: case Kernel::Receiver::CREATE_CALL_CAPABILITY:
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Receiver::CALL_ASYNC : Receiver::CALL), cap_protected, &((kObject *)cap_protected.l)->refs) reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
return 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) reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0)
return return
case Receiver::SET_REPLY_PROTECTED_DATA: case Kernel::Receiver::SET_REPLY_PROTECTED_DATA:
receiver->reply_protected_data = c->data[1] receiver->reply_protected_data = c->data[1]
break break
case Receiver::GET_ALARM: case Kernel::Receiver::GET_ALARM:
reply_num (receiver->alarm_count) reply_num (receiver->alarm_count)
return return
case Receiver::SET_ALARM: case Kernel::Receiver::SET_ALARM:
case Receiver::ADD_ALARM: case Kernel::Receiver::ADD_ALARM:
unsigned old = receiver->alarm_count unsigned old = receiver->alarm_count
if cmd == Receiver::SET_ALARM: if cmd == Kernel::Receiver::SET_ALARM:
receiver->alarm_count = c->data[1].l receiver->alarm_count = c->data[1].l
else: else:
receiver->alarm_count += c->data[1].l 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) reply_num (receiver->alarm_count)
return return
default: default:
reply_num (ERR_INVALID_OPERATION) dpanic (0, "invalid receiver operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
return return
reply_num (0) reply_num (0)
static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
kMemory *mem = (kMemory *)cap_protected.l kMemory *mem = (kMemory *)protected_data.l
switch cmd: switch cmd:
case Memory::CREATE: case Kernel::Memory::CREATE:
switch c->data[0].h: switch c->data[0].h:
case CAPTYPE_RECEIVER: case CAPTYPE_RECEIVER:
kReceiver *ret = mem->alloc_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) reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs)
else: else:
dpanic (0x03311992, "out of memory creating receiver") dpanic (0x03311992, "out of memory creating receiver")
reply_num (ERR_OUT_OF_MEMORY) reply_num (Kernel::ERR_OUT_OF_MEMORY)
return return
case CAPTYPE_MEMORY: case CAPTYPE_MEMORY:
kMemory *ret = mem->alloc_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) reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs)
else: else:
dpanic (0x13311992, "out of memory creating memory") dpanic (0x13311992, "out of memory creating memory")
reply_num (ERR_OUT_OF_MEMORY) reply_num (Kernel::ERR_OUT_OF_MEMORY)
return return
case CAPTYPE_THREAD: case CAPTYPE_THREAD:
kThread *ret = mem->alloc_thread (c->data[1].l) 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) reply_cap (CAPTYPE_THREAD | CAP_MASTER, (unsigned)ret, &ret->refs)
else: else:
dpanic (0x23311992, "out of memory creating thread") dpanic (0x23311992, "out of memory creating thread")
reply_num (ERR_OUT_OF_MEMORY) reply_num (Kernel::ERR_OUT_OF_MEMORY)
return return
case CAPTYPE_PAGE: case CAPTYPE_PAGE:
kPage *ret = mem->alloc_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) reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs)
else: else:
dpanic (0x33311992, "out of memory creating page") dpanic (0x33311992, "out of memory creating page")
reply_num (ERR_OUT_OF_MEMORY) reply_num (Kernel::ERR_OUT_OF_MEMORY)
return return
case CAPTYPE_CAPS: case CAPTYPE_CAPS:
kCaps *ret = mem->alloc_caps (c->data[1].l) 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) reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs)
else: else:
dpanic (0x43311992, "out of memory creating caps") dpanic (0x43311992, "out of memory creating caps")
reply_num (ERR_OUT_OF_MEMORY) reply_num (Kernel::ERR_OUT_OF_MEMORY)
return return
default: default:
dpanic (0, "invalid create type")
reply_num (~0) reply_num (~0)
return return
break break
case Memory::DESTROY: case Kernel::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: 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) reply_num (~0)
return return
switch (unsigned)c->caps->cap (1)->target & CAPTYPE_MASK: switch (unsigned)c->arg->target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER: case CAPTYPE_RECEIVER:
mem->free_receiver ((kReceiver *)c->caps->cap (1)->cap_protected.l) mem->free_receiver ((kReceiver *)c->arg->protected_data.l)
break break
case CAPTYPE_MEMORY: case CAPTYPE_MEMORY:
mem->free_memory ((kMemory *)c->caps->cap (1)->cap_protected.l) mem->free_memory ((kMemory *)c->arg->protected_data.l)
break break
case CAPTYPE_THREAD: case CAPTYPE_THREAD:
mem->free_thread ((kThread *)c->caps->cap (1)->cap_protected.l) mem->free_thread ((kThread *)c->arg->protected_data.l)
break break
case CAPTYPE_PAGE: case CAPTYPE_PAGE:
mem->free_page ((kPage *)c->caps->cap (1)->cap_protected.l) mem->free_page ((kPage *)c->arg->protected_data.l)
break break
case CAPTYPE_CAPS: case CAPTYPE_CAPS:
mem->free_caps ((kCaps *)c->caps->cap (1)->cap_protected.l) mem->free_caps ((kCaps *)c->arg->protected_data.l)
break break
default: default:
panic (0x55228930, "invalid case") panic (0x55228930, "invalid case")
return return
break break
case Memory::LIST: case Kernel::Memory::LIST:
// TODO // TODO
break break
case Memory::MAP: case Kernel::Memory::MAP:
// FIXME: this should work for fake pages as well. // 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") dpanic (0x22993341, "Trying to map non-page")
reply_num (~0) reply_num (~0)
return return
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l kPage *page = (kPage *)c->arg->protected_data.l
if page->address_space != mem: if page->address_space != mem:
dpanic (0x52993341, "Trying to map foreign page") dpanic (0x52993341, "Trying to map foreign page")
reply_num (~0) reply_num (~0)
return 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) mem->map (page, c->data[1].l & PAGE_MASK, readonly)
break break
case Memory::MAPPING: case Kernel::Memory::MAPPING:
bool readonly bool readonly
kPage *page = mem->get_mapping (c->data[1].l, &readonly) kPage *page = mem->get_mapping (c->data[1].l, &readonly)
unsigned t = CAPTYPE_PAGE | CAP_MASTER unsigned t = CAPTYPE_PAGE | CAP_MASTER
if readonly: if readonly:
t |= Page::READONLY t |= Kernel::Page::READONLY
reply_cap (t, (unsigned)page, &page->refs) reply_cap (t, (unsigned)page, &page->refs)
return return
case Memory::GET_LIMIT: case Kernel::Memory::GET_LIMIT:
reply_num (mem->limit) reply_num (mem->limit)
return return
case Memory::SET_LIMIT: case Kernel::Memory::SET_LIMIT:
mem->limit = c->data[1].l mem->limit = c->data[1].l
break break
default: default:
reply_num (ERR_INVALID_OPERATION) dpanic (0, "invalid memory operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
return return
reply_num (0) reply_num (0)
static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
kThread *thread = (kThread *)cap_protected.l kThread *thread = (kThread *)protected_data.l
switch cmd: switch cmd:
case Thread::GET_INFO: case Kernel::Thread::GET_INFO:
switch c->data[0].h: switch c->data[0].h:
case Thread::PC: case Kernel::Thread::PC:
reply_num (thread->pc) reply_num (thread->pc)
return return
case Thread::SP: case Kernel::Thread::SP:
reply_num (thread->sp) reply_num (thread->sp)
return return
case Thread::FLAGS: case Kernel::Thread::FLAGS:
reply_num (thread->flags) reply_num (thread->flags)
return return
default: default:
reply_num (*kThread_arch_info (thread, c->data[0].h)) reply_num (*kThread_arch_info (thread, c->data[0].h))
return return
case Thread::SET_INFO: case Kernel::Thread::SET_INFO:
unsigned *value unsigned *value
switch c->data[1].l: switch c->data[1].l:
case Thread::PC: case Kernel::Thread::PC:
value = &thread->pc value = &thread->pc
break break
case Thread::SP: case Kernel::Thread::SP:
value = &thread->sp value = &thread->sp
break break
case Thread::FLAGS: case Kernel::Thread::FLAGS:
// It is not possible to set the PRIV flag (but it can be reset). // It is not possible to set the PRIV flag (but it can be reset).
if c->data[1].l & Thread::PRIV: if c->data[1].l & Kernel::Thread::PRIV:
c->data[1].h &= ~Thread::PRIV c->data[1].h &= ~Kernel::Thread::PRIV
value = &thread->flags 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) unsigned v = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
if (v & Thread::WAITING) != (*value & Thread::WAITING): if (v & Kernel::Thread::WAITING) != (*value & Kernel::Thread::WAITING):
if v & Thread::WAITING: if v & Kernel::Thread::WAITING:
thread->wait () thread->wait ()
else else
thread->unwait () thread->unwait ()
if (v & Thread::RUNNING) != (*value & Thread::RUNNING): if (v & Kernel::Thread::RUNNING) != (*value & Kernel::Thread::RUNNING):
if v & Thread::RUNNING: if v & Kernel::Thread::RUNNING:
thread->run () thread->run ()
else else
thread->unrun () thread->unrun ()
@ -367,93 +411,114 @@ static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
if value: if value:
*value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h) *value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
break break
case Thread::USE_SLOT: case Kernel::Thread::USE_SLOT:
if c->data[1].l >= thread->slots || c->caps->size < 2: if c->data[1].l >= thread->slots || !c->arg.valid ():
dbg_send (5, 3) dbg_send (5, 3)
dpanic (c->data[1].l, "no argument given for USE_SLOT") dpanic (c->data[1].l, "no argument given for USE_SLOT")
reply_num (~0) reply_num (~0)
return return
// FIXME: This doesn't allow using a fake caps. // 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") dpanic (0, "argument for USE_SLOT is not a caps")
reply_num (~0) reply_num (~0)
return return
thread->fill_slot (c->data[1].l, (kCaps *)c->caps->cap (1)->cap_protected.l) unsigned slot = c->data[1].l
reply_num (0) kCaps *new_caps = (kCaps *)c->arg->protected_data.l
return if slot >= thread->slots:
case Thread::SCHEDULE: 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 do_schedule = true
return return
default: default:
if !(thread->flags & Thread::PRIV): if !(thread->flags & Kernel::Thread::PRIV):
reply_num (ERR_INVALID_OPERATION) dpanic (0, "invalid thread operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
return return
switch cmd: switch cmd:
case Thread::PRIV_REGISTER_INTERRUPT: case Kernel::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) 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 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) reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)&top_memory, &top_memory.refs)
return return
case Thread::PRIV_MAKE_PRIV: case Kernel::Thread::PRIV_MAKE_PRIV:
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_THREAD: if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
reply_num (~0) reply_num (~0)
return return
((kThread *)c->caps->cap (1)->cap_protected.l)->flags |= Thread::PRIV ((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV
break break
case Thread::PRIV_ALLOC_RANGE: case Kernel::Thread::PRIV_ALLOC_RANGE:
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_MEMORY: if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
panic (0x54365435, "non-memory argument to alloc_range") panic (0x54365435, "non-memory argument to alloc_range")
reply_num (~0) reply_num (~0)
return 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): if !mem->use (c->data[1].l):
dpanic (0x34365435, "out of memory during alloc_range") dpanic (0x34365435, "out of memory during alloc_range")
reply_num (ERR_OUT_OF_MEMORY) reply_num (Kernel::ERR_OUT_OF_MEMORY)
return return
unsigned data = phys_alloc (c->data[1].l) unsigned data = phys_alloc (c->data[1].l)
if !data: if !data:
mem->unuse (c->data[1].l) mem->unuse (c->data[1].l)
dpanic (0x14365435, "out of memory during alloc_range") dpanic (0x14365435, "out of memory during alloc_range")
reply_num (ERR_OUT_OF_MEMORY) reply_num (Kernel::ERR_OUT_OF_MEMORY)
return return
reply_num (data & ~0xc0000000) reply_num (data & ~0xc0000000)
return return
case Thread::PRIV_ALLOC_PHYSICAL: case Kernel::Thread::PRIV_ALLOC_PHYSICAL:
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target & ~REQUEST_MASK) != CAPTYPE_PAGE: 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") panic (0x21342134, "no page provided for alloc physical")
reply_num (~0) reply_num (~0)
return return
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l kPage *page = (kPage *)c->arg->protected_data.l
page->forget () page->forget ()
if !(c->data[1].l & 2): if !(c->data[1].l & 2):
if page->flags & Page::PAYING: if page->flags & Kernel::Page::PAYING:
page->flags &= ~Page::PAYING page->flags &= ~Kernel::Page::PAYING
page->address_space->unuse () page->address_space->unuse ()
else: else:
// This is for mapping allocated ranges. They are already paid for. Record that. // 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 () page->address_space->unuse ()
else: else:
page->flags |= Page::PAYING page->flags |= Kernel::Page::PAYING
page->frame = c->data[1].l & PAGE_MASK page->frame = c->data[1].l & PAGE_MASK
page->flags |= Page::FRAME page->flags |= Kernel::Page::FRAME
if !(c->data[1].l & 1): if !(c->data[1].l & 1):
page->flags |= Page::UNCACHED page->flags |= Kernel::Page::UNCACHED
if !(c->data[1].l & 2): if !(c->data[1].l & 2):
page->flags |= Page::PHYSICAL page->flags |= Kernel::Page::PHYSICAL
kPage_arch_update_mapping (page) kPage_arch_update_mapping (page)
break break
case Thread::PRIV_PHYSICAL_ADDRESS: case Kernel::Thread::PRIV_PHYSICAL_ADDRESS:
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_PAGE: if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
dpanic (0x99049380, "invalid page for physical address") dpanic (0x99049380, "invalid page for physical address")
reply_num (~0) reply_num (~0)
return return
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l kPage *page = (kPage *)c->arg->protected_data.l
reply_num (page->frame & ~0xc0000000) reply_num (page->frame & ~0xc0000000)
return 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: default:
reply_num (ERR_INVALID_OPERATION) dpanic (0, "invalid priv thread operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
return return
reply_num (0) reply_num (0)
return return
@ -461,10 +526,10 @@ static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
static bool page_check_payment (kPage *page): static bool page_check_payment (kPage *page):
kPage *p kPage *p
for p = page->share_prev; p; p = p->share_prev: for p = page->share_prev; p; p = p->share_prev:
if p->flags & Page::PAYING: if p->flags & Kernel::Page::PAYING:
return true return true
for p = page->share_next; p; p = p->share_next: for p = page->share_next; p; p = p->share_next:
if p->flags & Page::PAYING: if p->flags & Kernel::Page::PAYING:
return true return true
// No kPage is paying for this frame anymore. // No kPage is paying for this frame anymore.
raw_pfree (page->frame) raw_pfree (page->frame)
@ -473,38 +538,38 @@ static bool page_check_payment (kPage *page):
p->frame = NULL p->frame = NULL
p->share_prev = NULL p->share_prev = NULL
p->share_next = NULL p->share_next = NULL
p->flags &= ~(Page::SHARED | Page::FRAME) p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME)
kPage_arch_update_mapping (p) kPage_arch_update_mapping (p)
for p = page, next = p->share_next; p; p = next, next = p->share_next: for p = page, next = p->share_next; p; p = next, next = p->share_next:
p->frame = NULL p->frame = NULL
p->share_prev = NULL p->share_prev = NULL
p->share_next = NULL p->share_next = NULL
p->flags &= ~(Page::SHARED | Page::FRAME) p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME)
kPage_arch_update_mapping (p) kPage_arch_update_mapping (p)
return false return false
static void page_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
kPage *page = (kPage *)cap_protected.l kPage *page = (kPage *)protected_data.l
switch cmd & ~Page::READONLY: switch cmd & ~Kernel::Page::READONLY:
case Page::SHARE: case Kernel::Page::SHARE:
if c->caps->size < 2: if !c->arg.valid ():
// Cannot share without a target page. // Cannot share without a target page.
reply_num (~0) reply_num (~0)
return 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. // FIXME: This makes it impossible to use a fake kPage capability.
reply_num (~0) reply_num (~0)
return return
kPage *t = (kPage *)c->caps->cap (1)->cap_protected.l kPage *t = (kPage *)c->arg->protected_data.l
t->forget () t->forget ()
if c->data[0].h & Page::READONLY || cmd & Page::READONLY: if c->data[0].h & Kernel::Page::READONLY || cmd & Kernel::Page::READONLY:
t->flags |= Page::READONLY t->flags |= Kernel::Page::READONLY
if !(page->flags & Page::FRAME): if !(page->flags & Kernel::Page::FRAME):
break break
if c->data[0].h & Page::COPY: if c->data[0].h & Kernel::Page::COPY:
if ~t->flags & Page::PAYING: if ~t->flags & Kernel::Page::PAYING:
break 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 unsigned *d = (unsigned *)page->frame
if t == page: if t == page:
kPage *other = page->share_next ? page->share_next : page->share_prev 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->share_prev = NULL
page_check_payment (other) page_check_payment (other)
else: else:
t->flags |= Page::FRAME t->flags |= Kernel::Page::FRAME
t->frame = raw_zalloc () t->frame = raw_zalloc ()
for unsigned i = 0; i <= (c->data[0].h & ~PAGE_MASK); i += 4: for unsigned i = 0; i <= (c->data[0].h & ~PAGE_MASK); i += 4:
((unsigned *)t->frame)[i >> 2] = d[i >> 2] ((unsigned *)t->frame)[i >> 2] = d[i >> 2]
else: else:
if t != page: if t != page:
t->frame = page->frame t->frame = page->frame
t->flags |= Page::FRAME t->flags |= Kernel::Page::FRAME
page->frame = NULL page->frame = NULL
page->flags &= ~Page::FRAME page->flags &= ~Kernel::Page::FRAME
kPage_arch_update_mapping (page) kPage_arch_update_mapping (page)
kPage_arch_update_mapping (t) kPage_arch_update_mapping (t)
else: else:
if t == page: if t == page:
break break
if c->data[0].h & Page::FORGET: if c->data[0].h & Kernel::Page::FORGET:
if ~page->flags & Page::SHARED: if ~page->flags & Kernel::Page::SHARED:
if t->flags & Page::PAYING: if t->flags & Kernel::Page::PAYING:
t->frame = page->frame t->frame = page->frame
t->flags |= Page::FRAME t->flags |= Kernel::Page::FRAME
page->frame = NULL page->frame = NULL
page->flags &= ~Page::FRAME page->flags &= ~Kernel::Page::FRAME
kPage_arch_update_mapping (page) kPage_arch_update_mapping (page)
else: else:
t->share_prev = page->share_prev 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 t->share_prev->share_next = t
kPage_arch_update_mapping (t) kPage_arch_update_mapping (t)
break break
case Page::SET_FLAGS: case Kernel::Page::SET_FLAGS:
if cmd & Page::READONLY: if cmd & Kernel::Page::READONLY:
reply_num (~0) reply_num (~0)
return return
// Always refuse to set reserved flags. // 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. // Remember the old flags.
unsigned old = page->flags unsigned old = page->flags
// Compute the new flags. // Compute the new flags.
unsigned new_flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h) 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 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. // Decrease the use counter in any case.
page->address_space->unuse () page->address_space->unuse ()
if !page_check_payment (page): if !page_check_payment (page):
new_flags &= ~Page::FRAME new_flags &= ~Kernel::Page::FRAME
// If we start paying, increase the use counter. // 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 !page->address_space->use():
// If it doesn't work, refuse to set the flag, and refuse to allocate a frame. // If it doesn't work, refuse to set the flag, and refuse to allocate a frame.
new_flags &= ~(Page::PAYING | Page::FRAME) new_flags &= ~(Kernel::Page::PAYING | Kernel::Page::FRAME)
if old & Page::FRAME: if old & Kernel::Page::FRAME:
new_flags |= Page::FRAME new_flags |= Kernel::Page::FRAME
// If we want a frame, see if we can get it. // 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 kPage *p
for p = page; p; p = p->share_prev: for p = page; p; p = p->share_prev:
if p->flags & Page::PAYING: if p->flags & Kernel::Page::PAYING:
break break
if !p: if !p:
for p = page->share_next; p; p = p->share_next: for p = page->share_next; p; p = p->share_next:
if p->flags & Page::PAYING: if p->flags & Kernel::Page::PAYING:
break break
if !p: if !p:
new_flags &= ~Page::FRAME new_flags &= ~Kernel::Page::FRAME
// If we can get the new frame, get it. // 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 () page->frame = page->address_space->zalloc ()
kPage_arch_update_mapping (page) kPage_arch_update_mapping (page)
break break
default: default:
reply_num (ERR_INVALID_OPERATION) dpanic (0, "invalid page operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
return return
reply_num (0) reply_num (0)
@ -619,6 +685,9 @@ static void print_cap (kCapRef cap, kCapRef self):
dbg_log_num (cap.index, 1) dbg_log_num (cap.index, 1)
if !cap.valid (): if !cap.valid ():
dbg_log_char ('!') 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: for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
print_cap (c, self) print_cap (c, self)
if cap.deref () == self.deref (): if cap.deref () == self.deref ():
@ -626,10 +695,17 @@ static void print_cap (kCapRef cap, kCapRef self):
else: else:
dbg_log_char (']') dbg_log_char (']')
static void caps_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c): static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
kCaps *caps = (kCapsP)cap_protected.l kCaps *caps = (kCapsP)protected_data.l
switch cmd: 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: if c->data[1].l >= caps->size:
dpanic (0, "invalid caps for print") dpanic (0, "invalid caps for print")
return return
@ -662,66 +738,66 @@ static void caps_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapa
dbg_log_char ('\n') dbg_log_char ('\n')
return return
default: default:
reply_num (ERR_INVALID_OPERATION) dpanic (0, "invalid caps operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
return return
static void kill_reply (kCapability *self): static void kill_reply (kReceiver *r):
while self->parent.valid (): kCapRef cap = r->refs
self = self->parent.deref () while cap.valid ():
while self->sibling_prev.valid (): kCapability *c = cap.deref ()
self->sibling_prev->invalidate () cap = c->sibling_next
while self->sibling_next.valid (): if (unsigned)c->target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
self->sibling_next->invalidate () c->invalidate ()
self->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: // Kernel calling convention:
// data[0].l is the request. // data[0].l is the request.
// caps[0] is the reply capability // caps[0] is the reply capability
// other parameters' meanings depend on the operation. // other parameters' meanings depend on the operation.
if target == (CAPTYPE_RECEIVER | Receiver::CALL) || target == (CAPTYPE_RECEIVER | Receiver::CALL_ASYNC): if target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL_ASYNC):
// This is a call capability. caps->cap (0) is the capability to call. It should be replaced by the reply capability. // This is a call capability. reply is the capability to call. It should be replaced by the reply capability.
reply_target = (kReceiver *)cap_protected.l ((kReceiver *)protected_data.l)->protected_only = target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL)
reply_target->protected_only = target == (CAPTYPE_RECEIVER | Receiver::CALL)
if must_wait: if must_wait:
old_current->wait () old_current->wait ()
if !c->caps || c->caps->size == 0: if !reply_target:
// No caps, so no target to call.
dpanic (0x54635675, "no target to call") dpanic (0x54635675, "no target to call")
return return
kReceiver *call_target = c->caps->cap (0)->target if ((unsigned)reply_target & ~KERNEL_MASK) != 0:
Num call_cap_protected = c->caps->cap (0)->cap_protected
if ((unsigned)call_target & ~KERNEL_MASK) != 0:
// This is a user-implemented object. Create a real reply capability. // This is a user-implemented object. Create a real reply capability.
c->caps->cap (0)->invalidate () kReceiver *call_target = reply_target
c->caps->set (0, (kReceiver *)(CAPTYPE_RECEIVER | Receiver::REPLY), cap_protected, kCapRef (), &((kReceiver *)cap_protected.l)->refs) c->reply = kCapRef (&reply_caps, 0)
call_target->send_message (call_cap_protected, c) c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Kernel::Receiver::REPLY), protected_data, kCapRef (), &((kReceiver *)protected_data.l)->refs)
else if (unsigned)call_target == (CAPTYPE_RECEIVER | Receiver::REPLY): 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. // Reply capability: destroy all before invoke.
kill_reply (c->caps->cap (0)) kReceiver *r = (kReceiver *)reply_protected.l
kReceiver *r = (kReceiver *)call_cap_protected.l kill_reply (r)
r->send_message (r->reply_protected_data, c) r->send_message (r->reply_protected_data, c)
else: else:
// Kernel call: don't create actual capablities. // 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 reply_protected = reply_target->reply_protected_data
c->caps->cap (0)->invalidate () kernel_invoke ((unsigned)call_target->target, call_target->protected_data, c)
kernel_invoke ((unsigned)call_target, call_cap_protected, c, NULL)
return return
if must_wait: if must_wait:
old_current->wait () old_current->wait ()
if target == (CAPTYPE_RECEIVER | Receiver::REPLY): if target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
// This is a reply capability. // This is a reply capability.
kReceiver *r = (kReceiver *)cap_protected.l kReceiver *r = (kReceiver *)protected_data.l
kill_reply (self) kill_reply (r)
r->send_message (r->reply_protected_data, c) r->send_message (r->reply_protected_data, c)
return return
if !target: if !target:
return return
reply = kCapRef (c->caps, 0)
unsigned cmd unsigned cmd
if (target & REQUEST_MASK) == CAP_MASTER: if (target & REQUEST_MASK) == CAP_MASTER:
if c->data[0].l & CAP_MASTER_CREATE: 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 return
cmd = c->data[0].l cmd = c->data[0].l
c->data[0].l = 0 c->data[0].l = 0
@ -729,36 +805,38 @@ static void kernel_invoke (unsigned target, Num cap_protected, kCapability::Cont
cmd = target & REQUEST_MASK cmd = target & REQUEST_MASK
switch target & CAPTYPE_MASK: switch target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER: case CAPTYPE_RECEIVER:
receiver_invoke (cmd, target, cap_protected, c) receiver_invoke (cmd, target, protected_data, c)
break break
case CAPTYPE_MEMORY: case CAPTYPE_MEMORY:
memory_invoke (cmd, target, cap_protected, c) memory_invoke (cmd, target, protected_data, c)
break break
case CAPTYPE_THREAD: case CAPTYPE_THREAD:
thread_invoke (cmd, target, cap_protected, c) thread_invoke (cmd, target, protected_data, c)
break break
case CAPTYPE_PAGE: case CAPTYPE_PAGE:
page_invoke (cmd, target, cap_protected, c) page_invoke (cmd, target, protected_data, c)
break break
case CAPTYPE_CAPS: case CAPTYPE_CAPS:
caps_invoke (cmd, target, cap_protected, c) caps_invoke (cmd, target, protected_data, c)
break break
default: default:
panic (0x99337744, "invalid capability type invoked") panic (0x99337744, "invalid capability type invoked")
return return
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: if (unsigned)target & ~KERNEL_MASK:
// This is not a kernel capability: send a message to the receiver. // This is not a kernel capability: send a message to the receiver.
if must_wait: if must_wait:
old_current->wait () old_current->wait ()
target->send_message (cap_protected, c) target->send_message (protected_data, c)
return return
// This is a kernel capability. Use a function to allow optimized call capabilities. // This is a kernel capability. Use a function to allow optimized call capabilities.
if !c->caps || c->caps->size < 1: context = c
reply_target = NULL if c->reply.valid ():
reply_target = c->reply->target
reply_protected = c->reply->protected_data
else: else:
reply_target = c->caps->cap (0)->target reply_target = NULL
reply_protected = c->caps->cap (0)->cap_protected kernel_invoke ((unsigned)target, protected_data, c)
kernel_invoke ((unsigned)target, cap_protected, c, self)

824
iris.hhp
View File

@ -33,47 +33,6 @@
#define PAGE_SIZE (1 << PAGE_BITS) #define PAGE_SIZE (1 << PAGE_BITS)
#define PAGE_MASK (~(PAGE_SIZE - 1)) #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 KERNEL_MASK 0xfff
#define CAPTYPE_MASK 0xe00 #define CAPTYPE_MASK 0xe00
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK) #define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
@ -94,425 +53,422 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
// Master capabilities can create others. // Master capabilities can create others.
#define CAP_MASTER_CREATE (1 << 31) #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 __receiver_num 0
#define __thread_num 1 #define __thread_num 1
#define __memory_num 2 #define __memory_num 2
#define __call_num 3 #define __call_num 3
#define __parent_num 4 #define __parent_num 4
#define __tmp_slot 1
// If this flag is set in a capability, it is copied instead of mapped. // 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. // If it is set in the target capability, the Thread waits after the request.
#define CAP_COPY ((unsigned)0x80000000) #define CAP_COPY ((unsigned)0x80000000)
// This constant signifies that no capability is passed. // This constant signifies that no capability is passed.
#define CAP_NONE (~CAP_COPY) #define CAP_NONE (~CAP_COPY)
extern Receiver __my_receiver namespace Kernel:
extern Thread __my_thread enum Exception_code:
extern Memory __my_memory NO_ERROR
extern Cap __my_call ERR_WRITE_DENIED
extern Cap __my_parent ERR_UNMAPPED_READ
extern Caps __my_caps 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 () #ifndef NDEBUG
unsigned alloc_cap () static const char *exception_name[NUM_EXCEPTION_CODES] = {
void free_slot (unsigned slot) "no error",
void free_cap (Cap cap) "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: struct Num:
unsigned code unsigned l, h
inline Cap copy () const Num (unsigned long long n = 0) : l (n), h (n >> 32):
inline Cap () Num (unsigned ll, unsigned hh) : l (ll), h (hh):
explicit inline Cap (unsigned c) unsigned long long value () const:
inline Cap (unsigned slot, unsigned idx) return ((unsigned long long)h << 32) | l
inline unsigned slot () const unsigned &low ():
inline unsigned idx () const return l
struct IMessage unsigned &high ():
struct OMessage return h
inline void invoke (IMessage const *i, OMessage *o) unsigned const &low () const:
inline void call (IMessage *i, OMessage *o) return l
inline void invoke (Num d0 = 0, Num d1 = 0) unsigned const &high () const:
inline Num call (Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0) return h
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 Cap::IMessage: struct Cap
Num data[2] struct Caps
unsigned islot struct Receiver
unsigned oslot struct Thread
unsigned num, first struct Page
Cap *set struct Memory
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 Receiver : public Cap: unsigned alloc_slot ()
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx): Cap alloc_cap ()
Receiver (Cap c = Cap ()) : Cap (c): void free_slot (unsigned slot)
enum request: void free_cap (Cap cap)
// Operations
SET_OWNER = 1 struct Cap:
CREATE_CAPABILITY unsigned code
CREATE_CALL_CAPABILITY inline Cap copy () const
CREATE_ASYNC_CALL_CAPABILITY inline Cap ()
GET_REPLY_PROTECTED_DATA explicit inline Cap (unsigned c)
SET_REPLY_PROTECTED_DATA inline Cap (unsigned slot, unsigned idx)
GET_ALARM inline unsigned slot () const
SET_ALARM inline unsigned idx () const
ADD_ALARM struct IMessage
// Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability. inline void invoke (Num d0 = 0, Num d1 = 0, Cap arg = Cap (CAP_NONE))
REPLY inline Num call (Num d0 = 0, Num d1 = 0)
// A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY. inline Num icall (Num d0 = 0, Num d1 = 0)
CALL inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0)
// A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY. inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0)
CALL_ASYNC inline void _invoke (IMessage const *i)
void set_owner (Cap owner): inline void _call (IMessage *i)
ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
Cap create_capability (unsigned protected_data, Cap ret = Cap (0, alloc_cap ())): struct __recv_data_t:
icall (ret, CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data) 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 return ret
Num get_reply_protected_data (): inline Cap get_arg ():
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA) Cap ret = recv.arg
void set_reply_protected_data (Num data): recv.arg = alloc_cap ()
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)
return ret return ret
inline void set_recv_arg (Cap c):
free_cap (recv.arg)
recv.arg = c
struct Thread : public Cap: struct Cap::IMessage:
Thread (unsigned slot, unsigned idx) : Cap (slot, idx): Num data[2]
Thread (Cap c = Cap ()) : Cap (c): Cap reply, arg
enum request: Cap Cap::copy () const:
// Info details are arch-specific. return Cap (code | CAP_COPY)
GET_INFO = 1 Cap::Cap () : code (CAP_NONE):
SET_INFO Cap::Cap (unsigned c) : code (c):
USE_SLOT Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)):
SCHEDULE unsigned Cap::slot () const:
PRIV_ALLOC_RANGE return (code >> 16) & 0x7fff
PRIV_PHYSICAL_ADDRESS unsigned Cap::idx () const:
PRIV_ALLOC_PHYSICAL return code & 0xffff
PRIV_MAKE_PRIV void Cap::_invoke (IMessage const *i):
PRIV_GET_TOP_MEMORY __recv_data_t *r = &recv
PRIV_REGISTER_INTERRUPT __asm__ volatile ("lw $v0, %1\n"
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner. "\tlw $a0, 0($v0)\n"
SET_OWNER "\tlw $a1, 4($v0)\n"
// These get/set_info are not arch-specific. "\tlw $a2, 8($v0)\n"
enum info_type: "\tlw $a3, 12($v0)\n"
PC = ~0 "\tlw $t0, 16($v0)\n"
SP = ~1 "\tlw $t1, 20($v0)\n"
FLAGS = ~2 "\tlw $v0, %2\n"
enum flags: "\tlw $t2, 24($v0)\n"
PRIV = 1 << 31 "\tlw $t3, 28($v0)\n"
WAITING = 1 << 30 "\tlw $v0, %0\n"
RUNNING = 1 << 29 "\tsyscall\n"
USER_FLAGS = ~(PRIV | WAITING | RUNNING) "\tlw $v0, %2\n"
void make_priv (): "\tsw $a0, 0($v0)\n"
__my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV) "\tsw $a1, 4($v0)\n"
unsigned get_info (unsigned info): "\tsw $a2, 8($v0)\n"
return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l "\tsw $a3, 12($v0)\n"
void set_info (unsigned info, unsigned value, unsigned mask = ~0): "\tsw $t0, 16($v0)\n"
call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask)) "\tsw $t1, 20($v0)"
void set_pc (unsigned pc): :: "m"(code), "m"(i), "m"(r)
set_info (PC, pc) : "memory", "v0", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3")
void set_sp (unsigned sp): void Cap::_call (IMessage *i):
set_info (SP, sp) i->reply = *this
void set_flags (unsigned value, unsigned mask): my_call.copy ()._invoke (i)
set_info (FLAGS, value, mask) void Cap::invoke (Num d0, Num d1, Cap arg):
unsigned get_pc (): IMessage i
return get_info (PC) i.data[0] = d0
unsigned get_sp (): i.data[1] = d1
return get_info (SP) i.reply = Cap (CAP_NONE)
unsigned get_flags (): i.arg = arg
return get_info (FLAGS) _invoke (&i)
void run (bool run): Num Cap::call (Num d0, Num d1):
set_flags (run ? RUNNING : 0, RUNNING) IMessage i
void wait (bool wait): i.data[0] = d0
set_flags (wait ? WAITING : 0, WAITING) i.data[1] = d1
inline unsigned use (Caps caps, unsigned slot = alloc_slot ()) _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: struct Receiver : public Cap:
Caps (unsigned slot, unsigned idx) : Cap (slot, idx): Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
Caps (Cap c = Cap ()) : Cap (c): Receiver (Cap c = Cap ()) : Cap (c):
enum request: enum request:
// Not an operation; this capability can be used in Thread::USE_SLOT. // Operations
USE = 1 SET_OWNER = 1
PRINT CREATE_CAPABILITY
unsigned use (unsigned slot = alloc_slot ()): CREATE_CALL_CAPABILITY
return __my_thread.use (*this, slot) CREATE_ASYNC_CALL_CAPABILITY
void print (unsigned idx): GET_REPLY_PROTECTED_DATA
invoke (CAP_MASTER_DIRECT | PRINT, idx) 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): struct Thread : public Cap:
ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot) Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
return slot 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: struct Caps : public Cap:
Page (unsigned slot, unsigned idx) : Cap (slot, idx): Caps (unsigned slot, unsigned idx) : Cap (slot, idx):
Page (Cap c = Cap ()) : Cap (c): Caps (Cap c = Cap ()) : Cap (c):
enum request: enum request:
SHARE = 1 // Not an operation; this capability can be used in Thread::USE_SLOT.
GET_FLAGS USE = 1
SET_FLAGS SET
// Not an operation; a capability with this bit cannot write to the page. PRINT
READONLY = 8 unsigned use (unsigned slot = alloc_slot ()):
enum share_detail: return my_thread.use (*this, slot)
// Operation details for PAGE_SHARE void set (unsigned idx, Cap cap):
// Forget the source page during the operation. This makes it a move. ocall (cap, CAP_MASTER_DIRECT | SET, idx)
FORGET void print (unsigned idx):
// Make the target independent of the source (make a copy if needed). invoke (CAP_MASTER_DIRECT | PRINT, idx)
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: unsigned Thread::use (Caps caps, unsigned slot):
Memory (unsigned slot, unsigned idx) : Cap (slot, idx): ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot)
Memory (Cap c = Cap ()) : Cap (c): return slot
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
struct Kernel: struct Page : public Cap:
static void wait (Cap::OMessage *o, unsigned islot = ~0): 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 Cap::IMessage i
i.islot = islot Cap ().copy ()._invoke (&i)
i.num = 0 inline void schedule ():
i.first = 0 my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE)
i.oslot = ~0 inline void register_interrupt (unsigned num):
Cap cs[2] my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
i.set = cs inline void unregister_interrupt (unsigned num):
Cap ().copy ().invoke (&i, o) my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
static void schedule (): inline Cap get_top_memory ():
__my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE) my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
static void register_interrupt (unsigned num): return get_arg ()
__my_thread.ocall (__my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num) inline void dbg_send (unsigned code, unsigned bits = 32):
static void unregister_interrupt (unsigned num): my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits))
__my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num) inline void panic (unsigned code):
static Cap get_top_memory (Cap ret = Cap (0, alloc_cap ())): my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code)
__my_thread.icall (ret, CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
return ret
void Receiver::sleep (unsigned value, OMessage *ret, unsigned slot): void Receiver::sleep (unsigned value):
__my_receiver.set_alarm (value) my_receiver.set_alarm (value)
Kernel::wait (ret, slot) wait ()
// The start function has this prototype (there is no main function).
Kernel::Num start ()
#if 1 #if 1
// Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing. // Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing.

View File

@ -60,7 +60,7 @@ struct kCapRef:
kCapRef (kCapsP c, unsigned i) : caps (c), index (i): kCapRef (kCapsP c, unsigned i) : caps (c), index (i):
kCapRef () : caps (NULL), index (~0): kCapRef () : caps (NULL), index (~0):
inline void clone (kCapRef source, bool copy) 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: struct kObject:
kCapRef refs kCapRef refs
@ -80,20 +80,17 @@ bool kObject::is_free ():
// Include architecture-specific parts. // Include architecture-specific parts.
#include "arch.hh" #include "arch.hh"
struct kMessage : public kObject:
Num cap_protected
Num data[2]
kCapsP caps
struct kCapability : public kObject: struct kCapability : public kObject:
struct Context: struct Context:
Num data[2] Kernel::Num data[2]
kCaps *caps kCapRef reply
kCapRef arg
bool copy[2]
kReceiverP target kReceiverP target
kCapRef parent kCapRef parent
kCapRef children kCapRef children
kCapRef sibling_prev, sibling_next kCapRef sibling_prev, sibling_next
Num cap_protected Kernel::Num protected_data
inline void invoke (kCapability::Context *c) inline void invoke (kCapability::Context *c)
void invalidate () void invalidate ()
@ -103,7 +100,7 @@ struct kThread : public kObject:
kThread_arch arch kThread_arch arch
unsigned flags unsigned flags
kThreadP schedule_prev, schedule_next kThreadP schedule_prev, schedule_next
unsigned recv_slot unsigned recv_reply, recv_arg
// caps is an array of slots pointers to kCapses. // caps is an array of slots pointers to kCapses.
unsigned slots unsigned slots
// TODO: handle freeing of capses which are in use. // TODO: handle freeing of capses which are in use.
@ -114,9 +111,8 @@ struct kThread : public kObject:
void wait () void wait ()
void unwait () void unwait ()
bool is_waiting (): bool is_waiting ():
return flags & Thread::WAITING return flags & Kernel::Thread::WAITING
kCapRef find_capability (unsigned code, bool *copy) kCapRef find_capability (unsigned code, bool *copy)
void fill_slot (unsigned slot, kCaps *new_caps)
struct kReceiver : public kObject: struct kReceiver : public kObject:
kThreadP owner kThreadP owner
@ -131,15 +127,14 @@ struct kReceiver : public kObject:
// The message queue. kMessages are added at the tail, and removed at the front. // The message queue. kMessages are added at the tail, and removed at the front.
kMessageP messages kMessageP messages
kMessageP last_message kMessageP last_message
Num recv_protected Kernel::Num reply_protected_data
Num reply_protected_data
bool protected_only bool protected_only
// This limit is for messages stored in its address space. There is unlimited space if senders provide it. // This limit is for messages stored in its address space. There is unlimited space if senders provide it.
unsigned queue_limit unsigned queue_limit
void own (kThreadP o) void own (kThreadP o)
void orphan () void orphan ()
bool try_deliver () 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: struct kPage : public kObject:
unsigned frame unsigned frame
@ -154,9 +149,15 @@ struct kCaps : public kObject:
kCapability caps[1] kCapability caps[1]
kCapability *cap (unsigned idx): kCapability *cap (unsigned idx):
return &caps[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) 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: struct kMemory : public kObject:
kFree *frees kFree *frees
kPageP pages kPageP pages
@ -203,7 +204,7 @@ extern "C":
#define panic(n, m) panic_impl ((n), __LINE__, __PRETTY_FUNCTION__, (m)) #define panic(n, m) panic_impl ((n), __LINE__, __PRETTY_FUNCTION__, (m))
void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "") void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "")
#ifndef NDEBUG #ifndef NDEBUG
EXTERN Num dbg_code EXTERN Kernel::Num dbg_code
EXTERN kCapRef dbg_cap EXTERN kCapRef dbg_cap
void dbg_log_char (unsigned ch) void dbg_log_char (unsigned ch)
void dbg_log (char const *str) void dbg_log (char const *str)
@ -241,11 +242,11 @@ unsigned phys_alloc (unsigned num)
void phys_free (unsigned page, unsigned num) void phys_free (unsigned page, unsigned num)
// Defind in invoke.ccp // 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. // Defined by architecture-specific files.
void kThread_arch_init (kThread *thread) 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) unsigned *kThread_arch_info (kThread *thread, unsigned num)
void kMemory_arch_init (kMemory *mem) void kMemory_arch_init (kMemory *mem)
void kMemory_arch_free (kMemory *mem) void kMemory_arch_free (kMemory *mem)
@ -265,10 +266,10 @@ kCapability *kCapRef::deref ():
return caps ? caps->cap (index) : NULL return caps ? caps->cap (index) : NULL
void kCapRef::clone (kCapRef source, bool copy): void kCapRef::clone (kCapRef source, bool copy):
caps->clone (index, source, 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) caps->set (index, target, pdata, parent, parent_ptr)
void kCapability::invoke (kCapability::Context *c): 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) #define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0)

View File

@ -77,7 +77,6 @@ unsigned phys_alloc (unsigned num):
return ret return ret
void phys_free (unsigned page, unsigned num): void phys_free (unsigned page, unsigned num):
return
unsigned size = num << PAGE_BITS unsigned size = num << PAGE_BITS
if !first_free || (unsigned)first_free > page: if !first_free || (unsigned)first_free > page:
// This is the first free block. // This is the first free block.

View File

@ -34,15 +34,13 @@ void kThread_arch_init (kThread *thread):
thread->arch.hi = 0 thread->arch.hi = 0
thread->arch.lo = 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[0] = data[0].l
thread->arch.a[1] = data[0].h thread->arch.a[1] = data[0].h
thread->arch.a[2] = data[1].l thread->arch.a[2] = data[1].l
thread->arch.a[3] = data[1].h thread->arch.a[3] = data[1].h
thread->arch.s[0] = cap_protected.l thread->arch.t[0] = protected_data.l
thread->arch.s[1] = cap_protected.h thread->arch.t[1] = protected_data.h
thread->arch.s[2] = recv_protected.l
thread->arch.s[3] = recv_protected.h
unsigned *kThread_arch_info (kThread *thread, unsigned num): unsigned *kThread_arch_info (kThread *thread, unsigned num):
switch num: switch num:
@ -184,7 +182,7 @@ static unsigned make_entry_lo (kPage *page, bool readonly):
if !page->frame: if !page->frame:
return 0 return 0
unsigned flags unsigned flags
if page->flags & Page::UNCACHED: if page->flags & Kernel::Page::UNCACHED:
flags = 0x10 | 0x2 flags = 0x10 | 0x2
else: else:
flags = 0x18 | 0x2 flags = 0x18 | 0x2
@ -271,7 +269,7 @@ void kPage_arch_update_mapping (kPage *page):
if !page->arch.first_mapped: if !page->arch.first_mapped:
return return
kMemory *as = page->address_space 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: for arch_page *p = page->arch.first_mapped; p; p = p->next_mapped:
unsigned de = p->mapping >> 21 unsigned de = p->mapping >> 21
unsigned te = (p->mapping >> 12) & ((1 << 9) - 1) unsigned te = (p->mapping >> 12) & ((1 << 9) - 1)

View File

@ -24,7 +24,6 @@
#define NUM_SLOTS 4 #define NUM_SLOTS 4
#define NUM_CAPS 16 #define NUM_CAPS 16
#define NUM_TMP_CAPS 2
static void init_idle (): static void init_idle ():
// initialize idle task as if it is currently running. // initialize idle task as if it is currently running.
@ -34,7 +33,7 @@ static void init_idle ():
idle.schedule_next = NULL idle.schedule_next = NULL
idle.address_space = &idle_memory idle.address_space = &idle_memory
idle.refs.reset () idle.refs.reset ()
idle.flags = Thread::RUNNING | Thread::PRIV idle.flags = Kernel::Thread::RUNNING | Kernel::Thread::PRIV
// initialize idle_memory. // initialize idle_memory.
idle_memory.prev = NULL idle_memory.prev = NULL
idle_memory.next = NULL idle_memory.next = NULL
@ -53,7 +52,7 @@ static void init_idle ():
idle_page.prev = NULL idle_page.prev = NULL
idle_page.next = NULL idle_page.next = NULL
idle_page.frame = 0x80000000 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.refs.reset ()
idle_page.address_space = NULL idle_page.address_space = NULL
current = &idle current = &idle
@ -156,7 +155,7 @@ static void init_threads ():
if !pages[idx]: if !pages[idx]:
pages[idx] = mem->alloc_page () pages[idx] = mem->alloc_page ()
pages[idx]->frame = thread_start[i] + (idx << PAGE_BITS) 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 ++top_memory.limit
mem->use () mem->use ()
if !mem->map (pages[idx], p, readonly): if !mem->map (pages[idx], p, readonly):
@ -177,7 +176,7 @@ static void init_threads ():
if !page->frame: if !page->frame:
panic (0x02220022, "out of memory"); panic (0x02220022, "out of memory");
return return
page->flags = Page::PAYING | Page::FRAME page->flags = Kernel::Page::PAYING | Kernel::Page::FRAME
if !mem->map (page, p): if !mem->map (page, p):
panic (0x33557799, "unable to map initial bss page") panic (0x33557799, "unable to map initial bss page")
return return
@ -198,22 +197,21 @@ static void init_threads ():
top_memory.pfree (thread_start[i] + (p << PAGE_BITS)) top_memory.pfree (thread_start[i] + (p << PAGE_BITS))
kPage *stackpage = mem->alloc_page () kPage *stackpage = mem->alloc_page ()
stackpage->frame = mem->zalloc () stackpage->frame = mem->zalloc ()
stackpage->flags = Page::PAYING | Page::FRAME stackpage->flags = Kernel::Page::PAYING | Kernel::Page::FRAME
if !stackpage || !mem->map (stackpage, 0x7ffff000): if !stackpage || !mem->map (stackpage, 0x7ffff000):
panic (0x13151719, "unable to map initial stack page") panic (0x13151719, "unable to map initial stack page")
return return
thread->caps[0] = mem->alloc_caps (NUM_CAPS) 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[0] = NUM_SLOTS
thread->arch.a[1] = NUM_CAPS thread->arch.a[1] = NUM_CAPS
kReceiver *recv = mem->alloc_receiver () kReceiver *recv = mem->alloc_receiver ()
recv->owner = thread recv->owner = thread
thread->receivers = recv thread->receivers = recv
thread->caps[0]->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Num ((unsigned)recv), kCapRef (), &recv->refs) 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), Num ((unsigned)thread), kCapRef (), &thread->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), Num ((unsigned)mem), kCapRef (), &mem->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 | Receiver::CALL), Num ((unsigned)recv), kCapRef (), &recv->refs) thread->caps[0]->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Kernel::Receiver::CALL), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs)
thread->flags = Thread::RUNNING | Thread::PRIV thread->flags = Kernel::Thread::RUNNING | Kernel::Thread::PRIV
if !i: if !i:
first_scheduled = thread first_scheduled = thread
init_receiver = recv init_receiver = recv

View File

@ -31,7 +31,7 @@ static void handle_exit ():
schedule () schedule ()
if !current: if !current:
current = &idle 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") panic (current->flags, "non-scheduled thread running")
if !current: if !current:
current = &idle current = &idle
@ -55,7 +55,7 @@ static void handle_exit ():
asids[current->address_space->arch.asid] = (unsigned)current->address_space asids[current->address_space->arch.asid] = (unsigned)current->address_space
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid) cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
directory = current->address_space->arch.directory directory = current->address_space->arch.directory
if current->flags & Thread::PRIV: if current->flags & Kernel::Thread::PRIV:
cp0_set (CP0_STATUS, 0x1000ff13) cp0_set (CP0_STATUS, 0x1000ff13)
else: else:
cp0_set (CP0_STATUS, 0x0000ff13) cp0_set (CP0_STATUS, 0x0000ff13)
@ -68,7 +68,7 @@ kThread *tlb_refill ():
if !directory: if !directory:
unsigned addr unsigned addr
cp0_get (CP0_BAD_V_ADDR, 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 () handle_exit ()
return current return current
unsigned EntryHi unsigned EntryHi
@ -77,7 +77,7 @@ kThread *tlb_refill ():
if !t: if !t:
unsigned addr unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr) cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_NO_PAGE_TABLE, addr) current->raise (Kernel::ERR_NO_PAGE_TABLE, addr)
else: else:
// - 2 instead of - 1 means reset bit 0 // - 2 instead of - 1 means reset bit 0
unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2) unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2)
@ -104,7 +104,6 @@ kThread *interrupt ():
kCapability::Context c kCapability::Context c
for unsigned j = 0; j < 2; ++j: for unsigned j = 0; j < 2; ++j:
c.data[j] = 0 c.data[j] = 0
c.caps = NULL
arch_interrupt_receiver[i]->send_message (i, &c) arch_interrupt_receiver[i]->send_message (i, &c)
arch_interrupt_receiver[i] = NULL arch_interrupt_receiver[i] = NULL
if ipr & (1 << IRQ_OST0): 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) target = old_current->find_capability (old_current->arch.v[0], &must_wait)
do_schedule = false do_schedule = false
kCapability::Context msg kCapability::Context msg
unsigned num = old_current->arch.s[2] msg.reply = old_current->find_capability (old_current->arch.t[0], &msg.copy[0])
unsigned first = old_current->arch.s[3] msg.arg = old_current->find_capability (old_current->arch.t[1], &msg.copy[1])
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, &copy)
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
if must_wait: 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 !target.valid ():
if must_wait: if must_wait:
old_current->wait () old_current->wait ()
return return
msg.data[0] = Num (old_current->arch.a[0], old_current->arch.a[1]) msg.data[0] = Kernel::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[1] = Kernel::Num (old_current->arch.a[2], old_current->arch.a[3])
target->invoke (&msg) target->invoke (&msg)
if do_schedule && !must_wait: if do_schedule && !must_wait:
// If the call was to schedule without wait, it isn't done yet. // If the call was to schedule without wait, it isn't done yet.
schedule () 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. // 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 current = old_current
@ -181,31 +163,31 @@ kThread *exception ():
// TLB modification. // TLB modification.
unsigned addr unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr) cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_WRITE_DENIED, addr) current->raise (Kernel::ERR_WRITE_DENIED, addr)
break break
case 2: case 2:
// TLB load or instruction fetch. // TLB load or instruction fetch.
unsigned addr unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr) cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_UNMAPPED_READ, addr) current->raise (Kernel::ERR_UNMAPPED_READ, addr)
break break
case 3: case 3:
// TLB store. // TLB store.
unsigned addr unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr) cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_UNMAPPED_WRITE, addr) current->raise (Kernel::ERR_UNMAPPED_WRITE, addr)
break break
case 4: case 4:
// Address error load or instruction fetch. // Address error load or instruction fetch.
unsigned addr unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr) cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_INVALID_ADDRESS_READ, addr) current->raise (Kernel::ERR_INVALID_ADDRESS_READ, addr)
break break
case 5: case 5:
// Address error store. // Address error store.
unsigned addr unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr) cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (ERR_INVALID_ADDRESS_WRITE, addr) current->raise (Kernel::ERR_INVALID_ADDRESS_WRITE, addr)
break break
case 6: case 6:
// Bus error instruction fetch. // Bus error instruction fetch.
@ -224,7 +206,7 @@ kThread *exception ():
case 9: case 9:
// Breakpoint. // Breakpoint.
#if 0 || defined (NDEBUG) #if 0 || defined (NDEBUG)
//current->raise (ERR_BREAKPOINT, 0) //current->raise (Kernel::ERR_BREAKPOINT, 0)
#ifndef NDEBUG #ifndef NDEBUG
current->pc += 4 current->pc += 4
#endif #endif
@ -250,19 +232,19 @@ kThread *exception ():
break break
case 10: case 10:
// Reserved instruction. // Reserved instruction.
current->raise (ERR_RESERVED_INSTRUCTION, 0) current->raise (Kernel::ERR_RESERVED_INSTRUCTION, 0)
break break
case 11: case 11:
// Coprocessor unusable. // Coprocessor unusable.
current->raise (ERR_COPROCESSOR_UNUSABLE, 0) current->raise (Kernel::ERR_COPROCESSOR_UNUSABLE, 0)
break break
case 12: case 12:
// Arithmetic overflow. // Arithmetic overflow.
current->raise (ERR_OVERFLOW, 0) current->raise (Kernel::ERR_OVERFLOW, 0)
break break
case 13: case 13:
// Trap. // Trap.
current->raise (ERR_TRAP, 0) current->raise (Kernel::ERR_TRAP, 0)
break break
case 15: case 15:
// Floating point exception. // Floating point exception.
@ -270,7 +252,7 @@ kThread *exception ():
break break
case 23: case 23:
// Reference to WatchHi/WatchLo address. // Reference to WatchHi/WatchLo address.
current->raise (ERR_WATCHPOINT, 0) current->raise (Kernel::ERR_WATCHPOINT, 0)
break break
case 24: case 24:
// Machine check. // Machine check.

View File

@ -135,14 +135,14 @@
// Default lcd framebuffer mapping space. // Default lcd framebuffer mapping space.
#define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000) #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 <iris.hh> #include <iris.hh>
static void __map_io (unsigned physical, unsigned mapping): 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. // false means not cachable; false means don't free when done.
p.alloc_physical (physical, false, false) p.alloc_physical (physical, false, false)
__my_memory.map (p, mapping) Kernel::my_memory.map (p, mapping)
free_cap (p) Kernel::free_cap (p)
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0) #define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_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 #ifndef __KERNEL
static __inline__ void cdelay (unsigned ds): static __inline__ void cdelay (unsigned ds):
__my_receiver.set_alarm (ds * (HZ / 100)) Kernel::my_receiver.set_alarm (ds * (HZ / 100))
Cap ().call (~0) Kernel::Cap ().call (~0)
#endif #endif
/*************************************************************************** /***************************************************************************

View File

@ -23,10 +23,10 @@ void dbg_log_char (unsigned ch):
if !dbg_cap.valid (): if !dbg_cap.valid ():
return return
kCapability::Context c kCapability::Context c
c.caps = NULL
c.data[0] = ch c.data[0] = ch
c.data[1] = 0 ++dbg_code.l
dbg_cap->invoke (&c) dbg_cap->invoke (&c)
--dbg_code.l
void dbg_log (char const *str): void dbg_log (char const *str):
while *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]) dbg_log_char (encode[(num >> (4 * ((digits - 1) - i))) & 0xf])
return return
#if 0 || defined (NDEBUG) #if 1 || defined (NDEBUG)
void panic_impl (unsigned n, unsigned line, char const *name, char const *message): void panic_impl (unsigned n, unsigned line, char const *name, char const *message):
// Stop all threads. // Stop all threads.
while first_scheduled: while first_scheduled:

View File

@ -36,31 +36,30 @@ static void unrun_thread (kThread *thread):
thread->schedule_next->schedule_prev = thread->schedule_prev thread->schedule_next->schedule_prev = thread->schedule_prev
void kThread::run (): void kThread::run ():
if flags & Thread::RUNNING: if flags & Kernel::Thread::RUNNING:
return return
flags |= Thread::RUNNING flags |= Kernel::Thread::RUNNING
if is_waiting (): if is_waiting ():
return return
run_thread (this) run_thread (this)
void kThread::unrun (): void kThread::unrun ():
if !(flags & Thread::RUNNING): if !(flags & Kernel::Thread::RUNNING):
return return
flags &= ~Thread::RUNNING flags &= ~Kernel::Thread::RUNNING
if is_waiting (): if is_waiting ():
return return
unrun_thread (this) unrun_thread (this)
void kThread::unwait (): void kThread::unwait ():
flags &= ~Thread::WAITING flags &= ~Kernel::Thread::WAITING
if flags & Thread::RUNNING: if flags & Kernel::Thread::RUNNING:
run_thread (this) run_thread (this)
static void alarm_tick (kReceiver *recv): static void alarm_tick (kReceiver *recv):
if !recv->alarm_count: if !recv->alarm_count:
// Send message and stop counting. // Send message and stop counting.
kCapability::Context c kCapability::Context c
c.caps = NULL
for unsigned i = 0; i < 2; ++i: for unsigned i = 0; i < 2; ++i:
c.data[i] = 0 c.data[i] = 0
recv->send_message (~0, &c) recv->send_message (~0, &c)
@ -74,9 +73,9 @@ static void alarm_tick (kReceiver *recv):
--recv->alarm_count --recv->alarm_count
void kThread::wait (): void kThread::wait ():
if flags & Thread::RUNNING: if flags & Kernel::Thread::RUNNING:
unrun_thread (this) unrun_thread (this)
flags |= Thread::WAITING flags |= Kernel::Thread::WAITING
// Try to receive a message from a kReceiver immediately. // Try to receive a message from a kReceiver immediately.
for kReceiver *r = receivers; r; r = r->next_owned: for kReceiver *r = receivers; r; r = r->next_owned:
if r->try_deliver (): if r->try_deliver ():