1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2025-04-06 08:47:29 +03: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,11 +28,13 @@ 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
@ -42,6 +44,9 @@ void free_slot (unsigned slot):
__first_free_slot = &__slot_admin[slot] __first_free_slot = &__slot_admin[slot]
void free_cap (Cap cap): void free_cap (Cap cap):
if cap.slot () != 0:
kdebug ("trying to free capability from non-0 slot\n")
return
list *l = &__cap_admin[cap.idx ()] list *l = &__cap_admin[cap.idx ()]
l->prev = NULL l->prev = NULL
l->next = __first_free_cap l->next = __first_free_cap
@ -52,6 +57,7 @@ void free_cap (Cap cap):
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.
kdebug ("out of slots!\n")
return ~0 return ~0
list *ret = __first_free_slot list *ret = __first_free_slot
__first_free_slot = ret->next __first_free_slot = ret->next
@ -59,15 +65,16 @@ unsigned alloc_slot ():
ret->next->prev = NULL ret->next->prev = NULL
return ret - __slot_admin 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")
return Cap (0, CAP_NONE)
list *ret = __first_free_cap list *ret = __first_free_cap
__first_free_cap = ret->next __first_free_cap = ret->next
if ret->next: if ret->next:
ret->next->prev = NULL ret->next->prev = NULL
return ret - __cap_admin 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
if slot >= thread->slots:
dpanic (0, "using invalid slot")
return return
case Thread::SCHEDULE: 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)

364
iris.hhp
View File

@ -33,6 +33,39 @@
#define PAGE_SIZE (1 << PAGE_BITS) #define PAGE_SIZE (1 << PAGE_BITS)
#define PAGE_MASK (~(PAGE_SIZE - 1)) #define PAGE_MASK (~(PAGE_SIZE - 1))
#define KERNEL_MASK 0xfff
#define CAPTYPE_MASK 0xe00
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
#define CAPTYPE_INVALID 0x000
#define CAPTYPE_RECEIVER 0x200
#define CAPTYPE_MEMORY 0x400
#define CAPTYPE_THREAD 0x600
#define CAPTYPE_PAGE 0x800
#define CAPTYPE_CAPS 0xa00
//#define CAPTYPE_??? 0xc00
//#define CAPTYPE_??? 0xe00
// All kernel capabilities have a master capability, which can create others.
#define CAP_MASTER 0
// Create, invoke and forget, with masked data set to 0.
#define CAP_MASTER_DIRECT 0
// Master capabilities can create others.
#define CAP_MASTER_CREATE (1 << 31)
#define __receiver_num 0
#define __thread_num 1
#define __memory_num 2
#define __call_num 3
#define __parent_num 4
// If this flag is set in a capability, it is copied instead of mapped.
// If it is set in the target capability, the Thread waits after the request.
#define CAP_COPY ((unsigned)0x80000000)
// This constant signifies that no capability is passed.
#define CAP_NONE (~CAP_COPY)
namespace Kernel:
enum Exception_code: enum Exception_code:
NO_ERROR NO_ERROR
ERR_WRITE_DENIED ERR_WRITE_DENIED
@ -74,26 +107,6 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
} }
#endif #endif
#define KERNEL_MASK 0xfff
#define CAPTYPE_MASK 0xe00
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
#define CAPTYPE_INVALID 0x000
#define CAPTYPE_RECEIVER 0x200
#define CAPTYPE_MEMORY 0x400
#define CAPTYPE_THREAD 0x600
#define CAPTYPE_PAGE 0x800
#define CAPTYPE_CAPS 0xa00
//#define CAPTYPE_??? 0xc00
//#define CAPTYPE_??? 0xe00
// All kernel capabilities have a master capability, which can create others.
#define CAP_MASTER 0
// Create, invoke and forget, with masked data set to 0.
#define CAP_MASTER_DIRECT 0
// Master capabilities can create others.
#define CAP_MASTER_CREATE (1 << 31)
struct Num: struct Num:
unsigned l, h unsigned l, h
Num (unsigned long long n = 0) : l (n), h (n >> 32): Num (unsigned long long n = 0) : l (n), h (n >> 32):
@ -109,9 +122,6 @@ struct Num:
unsigned const &high () const: unsigned const &high () const:
return h return h
// The start function has this prototype (there is no main function).
Num start ()
struct Cap struct Cap
struct Caps struct Caps
struct Receiver struct Receiver
@ -119,29 +129,8 @@ struct Thread
struct Page struct Page
struct Memory struct Memory
#define __receiver_num 0
#define __thread_num 1
#define __memory_num 2
#define __call_num 3
#define __parent_num 4
#define __tmp_slot 1
// If this flag is set in a capability, it is copied instead of mapped.
// If it is set in the target capability, the Thread waits after the request.
#define CAP_COPY ((unsigned)0x80000000)
// This constant signifies that no capability is passed.
#define CAP_NONE (~CAP_COPY)
extern Receiver __my_receiver
extern Thread __my_thread
extern Memory __my_memory
extern Cap __my_call
extern Cap __my_parent
extern Caps __my_caps
unsigned alloc_slot () unsigned alloc_slot ()
unsigned alloc_cap () Cap alloc_cap ()
void free_slot (unsigned slot) void free_slot (unsigned slot)
void free_cap (Cap cap) void free_cap (Cap cap)
@ -154,26 +143,41 @@ struct Cap:
inline unsigned slot () const inline unsigned slot () const
inline unsigned idx () const inline unsigned idx () const
struct IMessage struct IMessage
struct OMessage inline void invoke (Num d0 = 0, Num d1 = 0, Cap arg = Cap (CAP_NONE))
inline void invoke (IMessage const *i, OMessage *o) inline Num call (Num d0 = 0, Num d1 = 0)
inline void call (IMessage *i, OMessage *o) inline Num icall (Num d0 = 0, Num d1 = 0)
inline void invoke (Num d0 = 0, Num d1 = 0) inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0)
inline Num call (Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0) inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0)
inline Num icall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0) inline void _invoke (IMessage const *i)
inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0) inline void _call (IMessage *i)
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 __recv_data_t:
Num data[2]
Num protected_data
Cap reply, arg
extern Receiver my_receiver
extern Thread my_thread
extern Memory my_memory
extern Cap my_call
extern Cap my_parent
extern __recv_data_t recv
inline Cap get_reply ():
Cap ret = recv.reply
recv.reply = alloc_cap ()
return ret
inline Cap get_arg ():
Cap ret = recv.arg
recv.arg = alloc_cap ()
return ret
inline void set_recv_arg (Cap c):
free_cap (recv.arg)
recv.arg = c
struct Cap::IMessage: struct Cap::IMessage:
Num data[2] Num data[2]
unsigned islot Cap reply, arg
unsigned oslot
unsigned num, first
Cap *set
struct Cap::OMessage:
Num data[2]
Num cap_protected
Num recv_protected
Cap Cap::copy () const: Cap Cap::copy () const:
return Cap (code | CAP_COPY) return Cap (code | CAP_COPY)
Cap::Cap () : code (CAP_NONE): Cap::Cap () : code (CAP_NONE):
@ -183,118 +187,65 @@ unsigned Cap::slot () const:
return (code >> 16) & 0x7fff return (code >> 16) & 0x7fff
unsigned Cap::idx () const: unsigned Cap::idx () const:
return code & 0xffff return code & 0xffff
void Cap::invoke (IMessage const *i, OMessage *o): void Cap::_invoke (IMessage const *i):
Cap *s = i->set __recv_data_t *r = &recv
__asm__ volatile ("lw $v0, %3\n" __asm__ volatile ("lw $v0, %1\n"
"\tlw $t0, 0($v0)\n"
"\tlw $t1, 4($v0)\n"
"\tlw $v0, %2\n"
"\tlw $a0, 0($v0)\n" "\tlw $a0, 0($v0)\n"
"\tlw $a1, 4($v0)\n" "\tlw $a1, 4($v0)\n"
"\tlw $a2, 8($v0)\n" "\tlw $a2, 8($v0)\n"
"\tlw $a3, 12($v0)\n" "\tlw $a3, 12($v0)\n"
"\tlw $s0, 16($v0)\n" "\tlw $t0, 16($v0)\n"
"\tlw $s1, 20($v0)\n" "\tlw $t1, 20($v0)\n"
"\tlw $s2, 24($v0)\n" "\tlw $v0, %2\n"
"\tlw $s3, 28($v0)\n" "\tlw $t2, 24($v0)\n"
"\tlw $v0, %1\n" "\tlw $t3, 28($v0)\n"
"\tsyscall\n"
"\tlw $v0, %0\n" "\tlw $v0, %0\n"
"\tsyscall\n"
"\tlw $v0, %2\n"
"\tsw $a0, 0($v0)\n" "\tsw $a0, 0($v0)\n"
"\tsw $a1, 4($v0)\n" "\tsw $a1, 4($v0)\n"
"\tsw $a2, 8($v0)\n" "\tsw $a2, 8($v0)\n"
"\tsw $a3, 12($v0)\n" "\tsw $a3, 12($v0)\n"
"\tsw $s0, 16($v0)\n" "\tsw $t0, 16($v0)\n"
"\tsw $s1, 20($v0)\n" "\tsw $t1, 20($v0)"
"\tsw $s2, 24($v0)\n" :: "m"(code), "m"(i), "m"(r)
"\tsw $s3, 28($v0)" : "memory", "v0", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3")
: "=m"(o) void Cap::_call (IMessage *i):
: "m"(code), "m"(i), "m"(s) i->reply = *this
: "memory", "v0", "s0", "s1", "s2", "s3", "a0", "a1", "a2", "a3", "t0", "t1") my_call.copy ()._invoke (i)
void Cap::call (IMessage *i, OMessage *o): void Cap::invoke (Num d0, Num d1, Cap arg):
i->set[0] = *this
__my_call.copy ().invoke (i, o)
void Cap::invoke (Num d0, Num d1):
IMessage i 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[0] = d0
i.data[1] = d1 i.data[1] = d1
invoke (&i, &o) i.reply = Cap (CAP_NONE)
Num Cap::call (Num d0, Num d1, unsigned oslot, unsigned islot): i.arg = arg
_invoke (&i)
Num Cap::call (Num d0, Num d1):
IMessage i 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[0] = d0
i.data[1] = d1 i.data[1] = d1
call (&i, &o) _call (&i)
return o.data[0] return recv.data[0]
Num Cap::icall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot): Num Cap::icall (Num d0, Num d1):
IMessage i 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[0] = d0
i.data[1] = d1 i.data[1] = d1
call (&i, &o) _call (&i)
Cap (oslot, 0).clone (c) return recv.data[0]
return o.data[0] Num Cap::ocall (Cap c, Num d0, Num d1):
Num Cap::ocall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot):
IMessage i 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[0] = d0
i.data[1] = d1 i.data[1] = d1
call (&i, &o) i.arg = c
return o.data[0] _call (&i)
Num Cap::iocall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot): return recv.data[0]
Num Cap::iocall (Cap c, Num d0, Num d1):
IMessage i 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[0] = d0
i.data[1] = d1 i.data[1] = d1
call (&i, &o) i.arg = c
Cap (oslot, 0).clone (c) _call (&i)
return o.data[0] return recv.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: struct Receiver : public Cap:
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx): Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
@ -318,9 +269,9 @@ struct Receiver : public Cap:
CALL_ASYNC CALL_ASYNC
void set_owner (Cap owner): void set_owner (Cap owner):
ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER) ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
Cap create_capability (unsigned protected_data, Cap ret = Cap (0, alloc_cap ())): Cap create_capability (Num protected_data):
icall (ret, CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data) icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
return ret return get_arg ()
Num get_reply_protected_data (): Num get_reply_protected_data ():
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA) return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
void set_reply_protected_data (Num data): void set_reply_protected_data (Num data):
@ -331,13 +282,13 @@ struct Receiver : public Cap:
return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
void set_alarm (unsigned data): void set_alarm (unsigned data):
call (CAP_MASTER_DIRECT | SET_ALARM, data) call (CAP_MASTER_DIRECT | SET_ALARM, data)
static inline void sleep (unsigned value, OMessage *ret, unsigned slot = __tmp_slot) static inline void sleep (unsigned value)
Cap create_call_capability (Cap ret = Cap (0, alloc_cap ())): Cap create_call_capability ():
icall (ret, CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY) icall (CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
return ret return get_arg ()
Cap create_async_call_capability (Cap ret = Cap (0, alloc_cap ())): Cap create_async_call_capability ():
icall (ret, CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY) icall (CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
return ret return get_arg ()
struct Thread : public Cap: struct Thread : public Cap:
Thread (unsigned slot, unsigned idx) : Cap (slot, idx): Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
@ -356,6 +307,8 @@ struct Thread : public Cap:
PRIV_REGISTER_INTERRUPT PRIV_REGISTER_INTERRUPT
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner. // This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
SET_OWNER SET_OWNER
DBG_SEND
PRIV_PANIC
// These get/set_info are not arch-specific. // These get/set_info are not arch-specific.
enum info_type: enum info_type:
PC = ~0 PC = ~0
@ -367,7 +320,7 @@ struct Thread : public Cap:
RUNNING = 1 << 29 RUNNING = 1 << 29
USER_FLAGS = ~(PRIV | WAITING | RUNNING) USER_FLAGS = ~(PRIV | WAITING | RUNNING)
void make_priv (): void make_priv ():
__my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV) my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV)
unsigned get_info (unsigned info): unsigned get_info (unsigned info):
return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l
void set_info (unsigned info, unsigned value, unsigned mask = ~0): void set_info (unsigned info, unsigned value, unsigned mask = ~0):
@ -396,9 +349,12 @@ struct Caps : public Cap:
enum request: enum request:
// Not an operation; this capability can be used in Thread::USE_SLOT. // Not an operation; this capability can be used in Thread::USE_SLOT.
USE = 1 USE = 1
SET
PRINT PRINT
unsigned use (unsigned slot = alloc_slot ()): unsigned use (unsigned slot = alloc_slot ()):
return __my_thread.use (*this, slot) return my_thread.use (*this, slot)
void set (unsigned idx, Cap cap):
ocall (cap, CAP_MASTER_DIRECT | SET, idx)
void print (unsigned idx): void print (unsigned idx):
invoke (CAP_MASTER_DIRECT | PRINT, idx) invoke (CAP_MASTER_DIRECT | PRINT, idx)
@ -443,9 +399,9 @@ struct Page : public Cap:
void set_flags (unsigned new_flags, unsigned mask): void set_flags (unsigned new_flags, unsigned mask):
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask)) call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
unsigned physical_address (): unsigned physical_address ():
return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
void alloc_physical (unsigned address, bool cachable, bool freeable): 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)) my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
struct Memory : public Cap: struct Memory : public Cap:
Memory (unsigned slot, unsigned idx) : Cap (slot, idx): Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
@ -458,21 +414,21 @@ struct Memory : public Cap:
MAPPING MAPPING
GET_LIMIT GET_LIMIT
SET_LIMIT SET_LIMIT
Page create_page (Page ret = Cap (0, alloc_cap ())): Page create_page ():
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE)) icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
return ret return get_arg ()
Thread create_thread (unsigned slots, Thread ret = Cap (0, alloc_cap ())): Thread create_thread (unsigned slots):
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots) icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
return ret return get_arg ()
Receiver create_receiver (Receiver ret = Cap (0, alloc_cap ())): Receiver create_receiver ():
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER)) icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
return ret return get_arg ()
Memory create_memory (Memory ret = Cap (0, alloc_cap ())): Memory create_memory ():
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY)) icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
return ret return get_arg ()
Caps create_caps (unsigned size, Caps ret = Cap (0, alloc_cap ())): Caps create_caps (unsigned size):
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size) icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
return ret return get_arg ()
void destroy (Cap target): void destroy (Cap target):
ocall (target, CAP_MASTER_DIRECT | DESTROY) ocall (target, CAP_MASTER_DIRECT | DESTROY)
// TODO: LIST // TODO: LIST
@ -480,39 +436,39 @@ struct Memory : public Cap:
if readonly: if readonly:
address |= Page::READONLY address |= Page::READONLY
ocall (page, CAP_MASTER_DIRECT | MAP, address) ocall (page, CAP_MASTER_DIRECT | MAP, address)
Page mapping (void *address, Page ret = Cap (0, alloc_cap ())): Page mapping (void *address):
icall (ret, CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address)) icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
return ret return get_arg ()
unsigned get_limit (unsigned limit): unsigned get_limit (unsigned limit):
return call (CAP_MASTER_DIRECT | GET_LIMIT).l return call (CAP_MASTER_DIRECT | GET_LIMIT).l
void set_limit (unsigned limit): void set_limit (unsigned limit):
call (CAP_MASTER_DIRECT | SET_LIMIT, limit) call (CAP_MASTER_DIRECT | SET_LIMIT, limit)
unsigned alloc_range (unsigned pages): unsigned alloc_range (unsigned pages):
return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l
struct Kernel: inline void wait ():
static void wait (Cap::OMessage *o, unsigned islot = ~0):
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 ():