1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-01 01:15: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
kMessage *kMemory::alloc_message (kReceiver *target):
kMessage *ret = (kMessage *)search_free (sizeof (kMessage), (void **)&target->messages)
kMessage *ret = (kMessage *)search_free (sizeof (kMessage) + sizeof (kCapability), (void **)&target->messages)
if !ret:
return NULL
ret->caps.size = 2
if !ret->next:
target->last_message = ret
return ret
@ -243,9 +244,9 @@ kMemory *kMemory::alloc_memory ():
kMemory_arch_init (ret)
return ret
void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr):
void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr):
caps[index].target = target
caps[index].cap_protected = pdata
caps[index].protected_data = pdata
caps[index].parent = parent
caps[index].children.reset ()
caps[index].sibling_prev.reset ()
@ -262,18 +263,21 @@ void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, k
caps[index].sibling_next->sibling_prev = kCapRef (this, index)
void kCaps::clone (unsigned index, kCapRef source, bool copy):
cap (index)->invalidate ()
if !source.valid ():
return
if copy:
if source->parent.valid ():
set (index, source->target, source->cap_protected, source->parent)
set (index, source->target, source->protected_data, source->parent)
else if (unsigned)source->target & ~KERNEL_MASK:
set (index, source->target, source->cap_protected, kCapRef (), &source->target->capabilities)
set (index, source->target, source->protected_data, kCapRef (), &source->target->capabilities)
else:
set (index, source->target, source->cap_protected, kCapRef (), &((kObject *)source->cap_protected.l)->refs)
set (index, source->target, source->protected_data, kCapRef (), &((kObject *)source->protected_data.l)->refs)
else:
set (index, source->target, source->cap_protected, source)
set (index, source->target, source->protected_data, source)
void kMemory::free_page (kPage *page):
if page->flags & Page::PAYING:
if page->flags & Kernel::Page::PAYING:
unuse ()
if page->frame:
pfree (page->frame)
@ -324,7 +328,7 @@ void kCapability::invalidate ():
else if (unsigned)target & ~KERNEL_MASK:
target->capabilities = sibling_next
else:
((kObject *)cap_protected.l)->refs = sibling_next
((kObject *)protected_data.l)->refs = sibling_next
if sibling_next.valid ():
sibling_next->sibling_prev = sibling_prev
parent.reset ()
@ -342,7 +346,7 @@ void kCapability::invalidate ():
c->children.reset ()
c->sibling_prev.reset ()
c->sibling_next.reset ()
c->cap_protected = 0
c->protected_data = 0
c = next
void kMemory::free_caps (kCaps *c):
@ -376,8 +380,8 @@ void kPage::forget ():
share_next = NULL
else:
// If the page has a frame and should be freed, free it.
if !((flags ^ Page::FRAME) & (Page::PHYSICAL | Page::FRAME)):
if !((flags ^ Kernel::Page::FRAME) & (Kernel::Page::PHYSICAL | Kernel::Page::FRAME)):
raw_pfree (frame)
frame = 0
flags &= ~(Page::FRAME | Page::SHARED | Page::PHYSICAL | Page::UNCACHED)
flags &= ~(Kernel::Page::FRAME | Kernel::Page::SHARED | Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
kPage_arch_update_mapping (this)

View File

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

View File

@ -24,59 +24,59 @@
// This shouldn't really be here. But where should it be?
// Requests made by initial threads to tell init about themselves.
enum init_requests:
INIT_SET_GPIO
INIT_SET_GPIO = 1
INIT_SET_LCD
// List interface.
template <typename _T> //
struct List : public Cap:
List (Cap c = Cap ()) : Cap (c):
struct List : public Kernel::Cap:
List (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
// TODO
struct String : public Cap:
String (Cap c = Cap ()) : Cap (c):
struct String : public Kernel::Cap:
String (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
// TODO
// Keyboard interface.
struct Keyboard : public Cap:
Keyboard (Cap c = Cap ()) : Cap (c):
struct Keyboard : public Kernel::Cap:
Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
SET_CB
SET_CB = 1
GET_KEYS
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
enum constant:
RELEASE = 1 << 31
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events.
void set_cb (Cap cb):
void set_cb (Kernel::Cap cb):
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
// Get a list of keys on this keyboard. The key codes start at zero with no gaps.
List <String> get_keys (List <String> ret = Cap (0, alloc_cap ())):
icall (ret, CAP_MASTER_DIRECT | GET_KEYS)
return ret
List <String> get_keys ():
icall (CAP_MASTER_DIRECT | GET_KEYS)
return Kernel::get_arg ()
// Display interface.
struct Display : public Cap:
Display (Cap c = Cap ()) : Cap (c):
struct Display : public Kernel::Cap:
Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
EOF_CB
EOF_CB = 1
CREATE_FB
USE_FB
GET_INFO
// Register an end-of-frame callback.
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
void set_eof_cb (Cap cb):
void set_eof_cb (Kernel::Cap cb):
ocall (cb, CAP_MASTER_DIRECT | EOF_CB)
// Create a framebuffer for the display. When not in use, it can be freed by the user.
// The pages must be cappages holding Page capabilities. They are filled by the display.
// The passed numbers must be 0 or match a mode that the device can use.
// The returned number is the physical address of the framebuffer. It can be used with display_use_framebuffer.
unsigned create_framebuffer (Caps pages, unsigned w = 0, unsigned h = 0, unsigned mode = 0):
return icall (pages, Num (CAP_MASTER_DIRECT | CREATE_FB, 0), Num ((w << 16) | h, mode)).l
unsigned create_framebuffer (unsigned w = 0, unsigned h = 0, unsigned mode = 0):
return icall (Kernel::Num (CAP_MASTER_DIRECT | CREATE_FB, 0), Kernel::Num ((w << 16) | h, mode)).l
// Use a framebuffer. The address must have been returned from display_create_framebuffer.
// w, h and mode must match the values given at creation time.
// unuse_cb is called the next time this operation is requested for this display.
void use_framebuffer (unsigned addr, Cap unuse_cb = Cap (), unsigned w = 0, unsigned h = 0, unsigned mode = 0):
ocall (unuse_cb, Num (CAP_MASTER_DIRECT | USE_FB, addr), Num ((w << 16) | h, mode))
void use_framebuffer (unsigned addr, Kernel::Cap unuse_cb = Kernel::Cap (), unsigned w = 0, unsigned h = 0, unsigned mode = 0):
ocall (unuse_cb, Kernel::Num (CAP_MASTER_DIRECT | USE_FB, addr), Kernel::Num ((w << 16) | h, mode))
// Get information about the display.
void get_info ():
// TODO: Interface is to be designed.
@ -86,91 +86,95 @@ struct Display : public Cap:
// File system interface.
// filesystem-related interfaces: file, directory, stream, seekable, mappable.
// Normal files implement at least stream or seekable file. Directories implement directory.
struct File : public Cap:
File (Cap c = Cap ()) : Cap (c):
struct File : public Kernel::Cap:
File (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
INFO
INFO = 1
CLOSE
MAP_HANDLE
// Get information about the file.
Num get_info (unsigned type, Caps ret = Cap ()):
return icall (ret, Num (CAP_MASTER_DIRECT | INFO, type))
Kernel::Num get_info (unsigned type):
return icall (Kernel::Num (CAP_MASTER_DIRECT | INFO, type))
// Close a file. If this is a directory, it implicitly closes all files opened from it.
void close ():
call (CAP_MASTER_DIRECT | CLOSE)
// Map a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle.
File map_handle (File ret):
icall (ret, CAP_MASTER_DIRECT | MAP_HANDLE)
File map_handle ():
icall (CAP_MASTER_DIRECT | MAP_HANDLE)
return Kernel::get_arg ()
// Directory interface.
struct Directory : public File:
Directory (Cap c = Cap ()) : File (c):
Directory (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request:
GET_SIZE
GET_SIZE = 1
GET_NAME
GET_FILE
GET_FILE_INFO
CREATE_FILE
DELETE_FILE
// Get the number of entries in this directory.
Num get_size ():
Kernel::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
// Get the filename. The return value is the size of the string, the page is filled with the string itself.
void get_name (Num idx, String target):
icall (target, CAP_MASTER_DIRECT | GET_NAME, idx)
String get_name (Kernel::Num idx):
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
return Kernel::get_arg ()
// Get the file.
void get_file (Num idx, File ret):
icall (ret, CAP_MASTER_DIRECT | GET_FILE, idx)
File get_file (Kernel::Num idx):
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
return Kernel::get_arg ()
// Get file info. This returns the same information as file_get_info, without opening the file.
Num get_file_info (Num idx, unsigned type, Caps ret = Cap ()):
return icall (ret, Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
Kernel::Num get_file_info (Kernel::Num idx, unsigned type):
return icall (Kernel::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
// Create a new file. After this, any index may map to a different file.
void create_file (String name, File ret):
icall (ret, CAP_MASTER_DIRECT | CREATE_FILE)
File create_file (String name):
icall (CAP_MASTER_DIRECT | CREATE_FILE)
return Kernel::get_arg ()
// Delete a file. After this, any index may map to a different file.
void delete_file (Num idx):
void delete_file (Kernel::Num idx):
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
// Stream interface.
struct Stream : public File:
Stream (Cap c = Cap ()) : File (c):
Stream (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request:
READ
READ = 1
WRITE
// Try to read size bytes. Returns the number of bytes successfully read.
Num read (Num size, String ret):
return icall (ret, CAP_MASTER_DIRECT | READ, size)
Kernel::Num read (Kernel::Num size):
return icall (CAP_MASTER_DIRECT | READ, size)
// Try to write size bytes. Returns the number of bytes successfully written.
Num write (String s, Num size):
Kernel::Num write (String s, Kernel::Num size):
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
// Seekable file interface.
struct Seekable : public File:
Seekable (Cap c = Cap ()) : File (c):
Seekable (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request:
READ
READ = 1
WRITE
TRUNCATE
// Try to read size bytes from position idx. Returns the number of bytes successfully read.
Num read (Num idx, unsigned size, String ret):
return icall (ret, Num (CAP_MASTER_DIRECT | READ, size), idx)
Kernel::Num read (Kernel::Num idx, unsigned size):
return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, size), idx)
// Try to write size bytes at position idx; the file is extended with zeroes if the write is past the end. Returns the number of bytes successfully written.
Num write (Num idx, String s):
Kernel::Num write (Kernel::Num idx, String s):
return ocall (s, CAP_MASTER_DIRECT | WRITE, idx)
// Truncate file to size idx. The file is extended with zeroes if it gets longer.
void truncate (Num idx):
void truncate (Kernel::Num idx):
call (CAP_MASTER_DIRECT | TRUNCATE, idx)
// Mappable file interface.
struct Mappable : public Seekable:
Mappable (Cap c = Cap ()) : Seekable (c):
Mappable (Kernel::Cap c = Kernel::Cap ()) : Seekable (c):
// TODO: to be designed.
// Block device interface.
struct Block_device : public Mappable:
Block_device (Cap c = Cap ()) : Mappable (c):
Block_device (Kernel::Cap c = Kernel::Cap ()) : Mappable (c):
// TODO: to be designed.

View File

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

View File

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

View File

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

View File

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

824
iris.hhp
View File

@ -33,47 +33,6 @@
#define PAGE_SIZE (1 << PAGE_BITS)
#define PAGE_MASK (~(PAGE_SIZE - 1))
enum Exception_code:
NO_ERROR
ERR_WRITE_DENIED
ERR_UNMAPPED_READ
ERR_UNMAPPED_WRITE
ERR_INVALID_ADDRESS_READ
ERR_INVALID_ADDRESS_WRITE
ERR_RESERVED_INSTRUCTION
ERR_COPROCESSOR_UNUSABLE
ERR_OVERFLOW
ERR_TRAP
ERR_WATCHPOINT
ERR_BREAKPOINT
ERR_NO_PAGE_DIRECTORY
ERR_NO_PAGE_TABLE
ERR_OUT_OF_MEMORY
// The following are not raised, but returned.
ERR_INVALID_OPERATION
NUM_EXCEPTION_CODES
#ifndef NDEBUG
static const char *exception_name[NUM_EXCEPTION_CODES] = {
"no error",
"write denied",
"unmapped read",
"unmapped write",
"invalid address read",
"invalid address write",
"reserved instruction",
"coprocessor unusable",
"overflow",
"trap",
"watchpoint",
"breakpoint",
"no page directory",
"no page table",
"out of memory",
"invalid operation"
}
#endif
#define KERNEL_MASK 0xfff
#define CAPTYPE_MASK 0xe00
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
@ -94,425 +53,422 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
// Master capabilities can create others.
#define CAP_MASTER_CREATE (1 << 31)
struct Num:
unsigned l, h
Num (unsigned long long n = 0) : l (n), h (n >> 32):
Num (unsigned ll, unsigned hh) : l (ll), h (hh):
unsigned long long value () const:
return ((unsigned long long)h << 32) | l
unsigned &low ():
return l
unsigned &high ():
return h
unsigned const &low () const:
return l
unsigned const &high () const:
return h
// The start function has this prototype (there is no main function).
Num start ()
struct Cap
struct Caps
struct Receiver
struct Thread
struct Page
struct Memory
#define __receiver_num 0
#define __thread_num 1
#define __memory_num 2
#define __call_num 3
#define __parent_num 4
#define __tmp_slot 1
// If this flag is set in a capability, it is copied instead of mapped.
// If it is set in the target capability, the Thread waits after the request.
#define CAP_COPY ((unsigned)0x80000000)
// This constant signifies that no capability is passed.
#define CAP_NONE (~CAP_COPY)
extern Receiver __my_receiver
extern Thread __my_thread
extern Memory __my_memory
extern Cap __my_call
extern Cap __my_parent
extern Caps __my_caps
namespace Kernel:
enum Exception_code:
NO_ERROR
ERR_WRITE_DENIED
ERR_UNMAPPED_READ
ERR_UNMAPPED_WRITE
ERR_INVALID_ADDRESS_READ
ERR_INVALID_ADDRESS_WRITE
ERR_RESERVED_INSTRUCTION
ERR_COPROCESSOR_UNUSABLE
ERR_OVERFLOW
ERR_TRAP
ERR_WATCHPOINT
ERR_BREAKPOINT
ERR_NO_PAGE_DIRECTORY
ERR_NO_PAGE_TABLE
ERR_OUT_OF_MEMORY
// The following are not raised, but returned.
ERR_INVALID_OPERATION
NUM_EXCEPTION_CODES
unsigned alloc_slot ()
unsigned alloc_cap ()
void free_slot (unsigned slot)
void free_cap (Cap cap)
#ifndef NDEBUG
static const char *exception_name[NUM_EXCEPTION_CODES] = {
"no error",
"write denied",
"unmapped read",
"unmapped write",
"invalid address read",
"invalid address write",
"reserved instruction",
"coprocessor unusable",
"overflow",
"trap",
"watchpoint",
"breakpoint",
"no page directory",
"no page table",
"out of memory",
"invalid operation"
}
#endif
struct Cap:
unsigned code
inline Cap copy () const
inline Cap ()
explicit inline Cap (unsigned c)
inline Cap (unsigned slot, unsigned idx)
inline unsigned slot () const
inline unsigned idx () const
struct IMessage
struct OMessage
inline void invoke (IMessage const *i, OMessage *o)
inline void call (IMessage *i, OMessage *o)
inline void invoke (Num d0 = 0, Num d1 = 0)
inline Num call (Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
inline Num icall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
inline Cap clone (Cap target = Cap (0, alloc_cap ()))
struct Num:
unsigned l, h
Num (unsigned long long n = 0) : l (n), h (n >> 32):
Num (unsigned ll, unsigned hh) : l (ll), h (hh):
unsigned long long value () const:
return ((unsigned long long)h << 32) | l
unsigned &low ():
return l
unsigned &high ():
return h
unsigned const &low () const:
return l
unsigned const &high () const:
return h
struct Cap::IMessage:
Num data[2]
unsigned islot
unsigned oslot
unsigned num, first
Cap *set
struct Cap::OMessage:
Num data[2]
Num cap_protected
Num recv_protected
Cap Cap::copy () const:
return Cap (code | CAP_COPY)
Cap::Cap () : code (CAP_NONE):
Cap::Cap (unsigned c) : code (c):
Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)):
unsigned Cap::slot () const:
return (code >> 16) & 0x7fff
unsigned Cap::idx () const:
return code & 0xffff
void Cap::invoke (IMessage const *i, OMessage *o):
Cap *s = i->set
__asm__ volatile ("lw $v0, %3\n"
"\tlw $t0, 0($v0)\n"
"\tlw $t1, 4($v0)\n"
"\tlw $v0, %2\n"
"\tlw $a0, 0($v0)\n"
"\tlw $a1, 4($v0)\n"
"\tlw $a2, 8($v0)\n"
"\tlw $a3, 12($v0)\n"
"\tlw $s0, 16($v0)\n"
"\tlw $s1, 20($v0)\n"
"\tlw $s2, 24($v0)\n"
"\tlw $s3, 28($v0)\n"
"\tlw $v0, %1\n"
"\tsyscall\n"
"\tlw $v0, %0\n"
"\tsw $a0, 0($v0)\n"
"\tsw $a1, 4($v0)\n"
"\tsw $a2, 8($v0)\n"
"\tsw $a3, 12($v0)\n"
"\tsw $s0, 16($v0)\n"
"\tsw $s1, 20($v0)\n"
"\tsw $s2, 24($v0)\n"
"\tsw $s3, 28($v0)"
: "=m"(o)
: "m"(code), "m"(i), "m"(s)
: "memory", "v0", "s0", "s1", "s2", "s3", "a0", "a1", "a2", "a3", "t0", "t1")
void Cap::call (IMessage *i, OMessage *o):
i->set[0] = *this
__my_call.copy ().invoke (i, o)
void Cap::invoke (Num d0, Num d1):
IMessage i
OMessage o
i.oslot = ~0
i.islot = ~0
Cap cs[2]
i.set = cs
i.num = 0
i.data[0] = d0
i.data[1] = d1
invoke (&i, &o)
Num Cap::call (Num d0, Num d1, unsigned oslot, unsigned islot):
IMessage i
OMessage o
Cap cs[2]
i.set = cs
i.oslot = oslot
i.islot = islot
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
call (&i, &o)
return o.data[0]
Num Cap::icall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot):
IMessage i
OMessage o
Cap cs[2]
i.set = cs
i.oslot = oslot
i.islot = islot
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
call (&i, &o)
Cap (oslot, 0).clone (c)
return o.data[0]
Num Cap::ocall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot):
IMessage i
OMessage o
Cap cs[2]
cs[1] = c
i.set = cs
i.oslot = oslot
i.islot = islot
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
call (&i, &o)
return o.data[0]
Num Cap::iocall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot):
IMessage i
OMessage o
Cap cs[2]
cs[1] = c
i.set = cs
i.oslot = oslot
i.islot = islot
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
call (&i, &o)
Cap (oslot, 0).clone (c)
return o.data[0]
Cap Cap::clone (Cap target):
IMessage i
OMessage o
Cap cs[2]
cs[0] = this->copy ()
i.set = cs
i.oslot = target.slot ()
i.first = target.idx ()
i.num = 1
i.islot = ~0
i.data[0] = 0
i.data[1] = 0
Cap ().invoke (&i, &o)
return target
struct Cap
struct Caps
struct Receiver
struct Thread
struct Page
struct Memory
struct Receiver : public Cap:
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
Receiver (Cap c = Cap ()) : Cap (c):
enum request:
// Operations
SET_OWNER = 1
CREATE_CAPABILITY
CREATE_CALL_CAPABILITY
CREATE_ASYNC_CALL_CAPABILITY
GET_REPLY_PROTECTED_DATA
SET_REPLY_PROTECTED_DATA
GET_ALARM
SET_ALARM
ADD_ALARM
// Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability.
REPLY
// A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY.
CALL
// A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY.
CALL_ASYNC
void set_owner (Cap owner):
ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
Cap create_capability (unsigned protected_data, Cap ret = Cap (0, alloc_cap ())):
icall (ret, CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
unsigned alloc_slot ()
Cap alloc_cap ()
void free_slot (unsigned slot)
void free_cap (Cap cap)
struct Cap:
unsigned code
inline Cap copy () const
inline Cap ()
explicit inline Cap (unsigned c)
inline Cap (unsigned slot, unsigned idx)
inline unsigned slot () const
inline unsigned idx () const
struct IMessage
inline void invoke (Num d0 = 0, Num d1 = 0, Cap arg = Cap (CAP_NONE))
inline Num call (Num d0 = 0, Num d1 = 0)
inline Num icall (Num d0 = 0, Num d1 = 0)
inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0)
inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0)
inline void _invoke (IMessage const *i)
inline void _call (IMessage *i)
struct __recv_data_t:
Num data[2]
Num protected_data
Cap reply, arg
extern Receiver my_receiver
extern Thread my_thread
extern Memory my_memory
extern Cap my_call
extern Cap my_parent
extern __recv_data_t recv
inline Cap get_reply ():
Cap ret = recv.reply
recv.reply = alloc_cap ()
return ret
Num get_reply_protected_data ():
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
void set_reply_protected_data (Num data):
call (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data)
unsigned get_alarm ():
return call (CAP_MASTER_DIRECT | GET_ALARM).l
unsigned add_alarm (unsigned data):
return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
void set_alarm (unsigned data):
call (CAP_MASTER_DIRECT | SET_ALARM, data)
static inline void sleep (unsigned value, OMessage *ret, unsigned slot = __tmp_slot)
Cap create_call_capability (Cap ret = Cap (0, alloc_cap ())):
icall (ret, CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
return ret
Cap create_async_call_capability (Cap ret = Cap (0, alloc_cap ())):
icall (ret, CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
inline Cap get_arg ():
Cap ret = recv.arg
recv.arg = alloc_cap ()
return ret
inline void set_recv_arg (Cap c):
free_cap (recv.arg)
recv.arg = c
struct Thread : public Cap:
Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
Thread (Cap c = Cap ()) : Cap (c):
enum request:
// Info details are arch-specific.
GET_INFO = 1
SET_INFO
USE_SLOT
SCHEDULE
PRIV_ALLOC_RANGE
PRIV_PHYSICAL_ADDRESS
PRIV_ALLOC_PHYSICAL
PRIV_MAKE_PRIV
PRIV_GET_TOP_MEMORY
PRIV_REGISTER_INTERRUPT
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
SET_OWNER
// These get/set_info are not arch-specific.
enum info_type:
PC = ~0
SP = ~1
FLAGS = ~2
enum flags:
PRIV = 1 << 31
WAITING = 1 << 30
RUNNING = 1 << 29
USER_FLAGS = ~(PRIV | WAITING | RUNNING)
void make_priv ():
__my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV)
unsigned get_info (unsigned info):
return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l
void set_info (unsigned info, unsigned value, unsigned mask = ~0):
call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask))
void set_pc (unsigned pc):
set_info (PC, pc)
void set_sp (unsigned sp):
set_info (SP, sp)
void set_flags (unsigned value, unsigned mask):
set_info (FLAGS, value, mask)
unsigned get_pc ():
return get_info (PC)
unsigned get_sp ():
return get_info (SP)
unsigned get_flags ():
return get_info (FLAGS)
void run (bool run):
set_flags (run ? RUNNING : 0, RUNNING)
void wait (bool wait):
set_flags (wait ? WAITING : 0, WAITING)
inline unsigned use (Caps caps, unsigned slot = alloc_slot ())
struct Cap::IMessage:
Num data[2]
Cap reply, arg
Cap Cap::copy () const:
return Cap (code | CAP_COPY)
Cap::Cap () : code (CAP_NONE):
Cap::Cap (unsigned c) : code (c):
Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)):
unsigned Cap::slot () const:
return (code >> 16) & 0x7fff
unsigned Cap::idx () const:
return code & 0xffff
void Cap::_invoke (IMessage const *i):
__recv_data_t *r = &recv
__asm__ volatile ("lw $v0, %1\n"
"\tlw $a0, 0($v0)\n"
"\tlw $a1, 4($v0)\n"
"\tlw $a2, 8($v0)\n"
"\tlw $a3, 12($v0)\n"
"\tlw $t0, 16($v0)\n"
"\tlw $t1, 20($v0)\n"
"\tlw $v0, %2\n"
"\tlw $t2, 24($v0)\n"
"\tlw $t3, 28($v0)\n"
"\tlw $v0, %0\n"
"\tsyscall\n"
"\tlw $v0, %2\n"
"\tsw $a0, 0($v0)\n"
"\tsw $a1, 4($v0)\n"
"\tsw $a2, 8($v0)\n"
"\tsw $a3, 12($v0)\n"
"\tsw $t0, 16($v0)\n"
"\tsw $t1, 20($v0)"
:: "m"(code), "m"(i), "m"(r)
: "memory", "v0", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3")
void Cap::_call (IMessage *i):
i->reply = *this
my_call.copy ()._invoke (i)
void Cap::invoke (Num d0, Num d1, Cap arg):
IMessage i
i.data[0] = d0
i.data[1] = d1
i.reply = Cap (CAP_NONE)
i.arg = arg
_invoke (&i)
Num Cap::call (Num d0, Num d1):
IMessage i
i.data[0] = d0
i.data[1] = d1
_call (&i)
return recv.data[0]
Num Cap::icall (Num d0, Num d1):
IMessage i
i.data[0] = d0
i.data[1] = d1
_call (&i)
return recv.data[0]
Num Cap::ocall (Cap c, Num d0, Num d1):
IMessage i
i.data[0] = d0
i.data[1] = d1
i.arg = c
_call (&i)
return recv.data[0]
Num Cap::iocall (Cap c, Num d0, Num d1):
IMessage i
i.data[0] = d0
i.data[1] = d1
i.arg = c
_call (&i)
return recv.data[0]
struct Caps : public Cap:
Caps (unsigned slot, unsigned idx) : Cap (slot, idx):
Caps (Cap c = Cap ()) : Cap (c):
enum request:
// Not an operation; this capability can be used in Thread::USE_SLOT.
USE = 1
PRINT
unsigned use (unsigned slot = alloc_slot ()):
return __my_thread.use (*this, slot)
void print (unsigned idx):
invoke (CAP_MASTER_DIRECT | PRINT, idx)
struct Receiver : public Cap:
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
Receiver (Cap c = Cap ()) : Cap (c):
enum request:
// Operations
SET_OWNER = 1
CREATE_CAPABILITY
CREATE_CALL_CAPABILITY
CREATE_ASYNC_CALL_CAPABILITY
GET_REPLY_PROTECTED_DATA
SET_REPLY_PROTECTED_DATA
GET_ALARM
SET_ALARM
ADD_ALARM
// Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability.
REPLY
// A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY.
CALL
// A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY.
CALL_ASYNC
void set_owner (Cap owner):
ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
Cap create_capability (Num protected_data):
icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
return get_arg ()
Num get_reply_protected_data ():
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
void set_reply_protected_data (Num data):
call (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data)
unsigned get_alarm ():
return call (CAP_MASTER_DIRECT | GET_ALARM).l
unsigned add_alarm (unsigned data):
return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
void set_alarm (unsigned data):
call (CAP_MASTER_DIRECT | SET_ALARM, data)
static inline void sleep (unsigned value)
Cap create_call_capability ():
icall (CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
return get_arg ()
Cap create_async_call_capability ():
icall (CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
return get_arg ()
unsigned Thread::use (Caps caps, unsigned slot):
ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot)
return slot
struct Thread : public Cap:
Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
Thread (Cap c = Cap ()) : Cap (c):
enum request:
// Info details are arch-specific.
GET_INFO = 1
SET_INFO
USE_SLOT
SCHEDULE
PRIV_ALLOC_RANGE
PRIV_PHYSICAL_ADDRESS
PRIV_ALLOC_PHYSICAL
PRIV_MAKE_PRIV
PRIV_GET_TOP_MEMORY
PRIV_REGISTER_INTERRUPT
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
SET_OWNER
DBG_SEND
PRIV_PANIC
// These get/set_info are not arch-specific.
enum info_type:
PC = ~0
SP = ~1
FLAGS = ~2
enum flags:
PRIV = 1 << 31
WAITING = 1 << 30
RUNNING = 1 << 29
USER_FLAGS = ~(PRIV | WAITING | RUNNING)
void make_priv ():
my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV)
unsigned get_info (unsigned info):
return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l
void set_info (unsigned info, unsigned value, unsigned mask = ~0):
call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask))
void set_pc (unsigned pc):
set_info (PC, pc)
void set_sp (unsigned sp):
set_info (SP, sp)
void set_flags (unsigned value, unsigned mask):
set_info (FLAGS, value, mask)
unsigned get_pc ():
return get_info (PC)
unsigned get_sp ():
return get_info (SP)
unsigned get_flags ():
return get_info (FLAGS)
void run (bool run):
set_flags (run ? RUNNING : 0, RUNNING)
void wait (bool wait):
set_flags (wait ? WAITING : 0, WAITING)
inline unsigned use (Caps caps, unsigned slot = alloc_slot ())
struct Page : public Cap:
Page (unsigned slot, unsigned idx) : Cap (slot, idx):
Page (Cap c = Cap ()) : Cap (c):
enum request:
SHARE = 1
GET_FLAGS
SET_FLAGS
// Not an operation; a capability with this bit cannot write to the page.
READONLY = 8
enum share_detail:
// Operation details for PAGE_SHARE
// Forget the source page during the operation. This makes it a move.
FORGET
// Make the target independent of the source (make a copy if needed).
COPY
// Make the target unwritable.
//READONLY: use the value from request.
enum flag_values:
// This is a read-only flag, which is set if the Page is shared.
SHARED = 1
// When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them.
PAYING = 2
// Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems.
FRAME = 4
// A readonly page cannot be written to. This flag can not be reset while the frame is shared. The flag is already defined in request.
//READONLY = 8
// This is a read-only flag, saying if this is physical memory, which mustn't be freed.
PHYSICAL = 0x10
// This is a read-only flag, saying if this is uncachable memory.
UNCACHED = 0x20
void share (Cap target, unsigned flags):
ocall (target, CAP_MASTER_DIRECT | SHARE, flags)
unsigned get_flags ():
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
void set_flags (unsigned new_flags, unsigned mask):
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
unsigned physical_address ():
return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
void alloc_physical (unsigned address, bool cachable, bool freeable):
__my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
struct Caps : public Cap:
Caps (unsigned slot, unsigned idx) : Cap (slot, idx):
Caps (Cap c = Cap ()) : Cap (c):
enum request:
// Not an operation; this capability can be used in Thread::USE_SLOT.
USE = 1
SET
PRINT
unsigned use (unsigned slot = alloc_slot ()):
return my_thread.use (*this, slot)
void set (unsigned idx, Cap cap):
ocall (cap, CAP_MASTER_DIRECT | SET, idx)
void print (unsigned idx):
invoke (CAP_MASTER_DIRECT | PRINT, idx)
struct Memory : public Cap:
Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
Memory (Cap c = Cap ()) : Cap (c):
enum request:
CREATE = 1
DESTROY
LIST
MAP
MAPPING
GET_LIMIT
SET_LIMIT
Page create_page (Page ret = Cap (0, alloc_cap ())):
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
return ret
Thread create_thread (unsigned slots, Thread ret = Cap (0, alloc_cap ())):
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
return ret
Receiver create_receiver (Receiver ret = Cap (0, alloc_cap ())):
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
return ret
Memory create_memory (Memory ret = Cap (0, alloc_cap ())):
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
return ret
Caps create_caps (unsigned size, Caps ret = Cap (0, alloc_cap ())):
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
return ret
void destroy (Cap target):
ocall (target, CAP_MASTER_DIRECT | DESTROY)
// TODO: LIST
void map (Cap page, unsigned address, bool readonly = false):
if readonly:
address |= Page::READONLY
ocall (page, CAP_MASTER_DIRECT | MAP, address)
Page mapping (void *address, Page ret = Cap (0, alloc_cap ())):
icall (ret, CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
return ret
unsigned get_limit (unsigned limit):
return call (CAP_MASTER_DIRECT | GET_LIMIT).l
void set_limit (unsigned limit):
call (CAP_MASTER_DIRECT | SET_LIMIT, limit)
unsigned alloc_range (unsigned pages):
return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l
unsigned Thread::use (Caps caps, unsigned slot):
ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot)
return slot
struct Kernel:
static void wait (Cap::OMessage *o, unsigned islot = ~0):
struct Page : public Cap:
Page (unsigned slot, unsigned idx) : Cap (slot, idx):
Page (Cap c = Cap ()) : Cap (c):
enum request:
SHARE = 1
GET_FLAGS
SET_FLAGS
// Not an operation; a capability with this bit cannot write to the page.
READONLY = 8
enum share_detail:
// Operation details for PAGE_SHARE
// Forget the source page during the operation. This makes it a move.
FORGET
// Make the target independent of the source (make a copy if needed).
COPY
// Make the target unwritable.
//READONLY: use the value from request.
enum flag_values:
// This is a read-only flag, which is set if the Page is shared.
SHARED = 1
// When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them.
PAYING = 2
// Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems.
FRAME = 4
// A readonly page cannot be written to. This flag can not be reset while the frame is shared. The flag is already defined in request.
//READONLY = 8
// This is a read-only flag, saying if this is physical memory, which mustn't be freed.
PHYSICAL = 0x10
// This is a read-only flag, saying if this is uncachable memory.
UNCACHED = 0x20
void share (Cap target, unsigned flags):
ocall (target, CAP_MASTER_DIRECT | SHARE, flags)
unsigned get_flags ():
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
void set_flags (unsigned new_flags, unsigned mask):
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
unsigned physical_address ():
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
void alloc_physical (unsigned address, bool cachable, bool freeable):
my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
struct Memory : public Cap:
Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
Memory (Cap c = Cap ()) : Cap (c):
enum request:
CREATE = 1
DESTROY
LIST
MAP
MAPPING
GET_LIMIT
SET_LIMIT
Page create_page ():
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
return get_arg ()
Thread create_thread (unsigned slots):
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
return get_arg ()
Receiver create_receiver ():
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
return get_arg ()
Memory create_memory ():
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
return get_arg ()
Caps create_caps (unsigned size):
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
return get_arg ()
void destroy (Cap target):
ocall (target, CAP_MASTER_DIRECT | DESTROY)
// TODO: LIST
void map (Cap page, unsigned address, bool readonly = false):
if readonly:
address |= Page::READONLY
ocall (page, CAP_MASTER_DIRECT | MAP, address)
Page mapping (void *address):
icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
return get_arg ()
unsigned get_limit (unsigned limit):
return call (CAP_MASTER_DIRECT | GET_LIMIT).l
void set_limit (unsigned limit):
call (CAP_MASTER_DIRECT | SET_LIMIT, limit)
unsigned alloc_range (unsigned pages):
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l
inline void wait ():
Cap::IMessage i
i.islot = islot
i.num = 0
i.first = 0
i.oslot = ~0
Cap cs[2]
i.set = cs
Cap ().copy ().invoke (&i, o)
static void schedule ():
__my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE)
static void register_interrupt (unsigned num):
__my_thread.ocall (__my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
static void unregister_interrupt (unsigned num):
__my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
static Cap get_top_memory (Cap ret = Cap (0, alloc_cap ())):
__my_thread.icall (ret, CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
return ret
Cap ().copy ()._invoke (&i)
inline void schedule ():
my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE)
inline void register_interrupt (unsigned num):
my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
inline void unregister_interrupt (unsigned num):
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
inline Cap get_top_memory ():
my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
return get_arg ()
inline void dbg_send (unsigned code, unsigned bits = 32):
my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits))
inline void panic (unsigned code):
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code)
void Receiver::sleep (unsigned value, OMessage *ret, unsigned slot):
__my_receiver.set_alarm (value)
Kernel::wait (ret, slot)
void Receiver::sleep (unsigned value):
my_receiver.set_alarm (value)
wait ()
// The start function has this prototype (there is no main function).
Kernel::Num start ()
#if 1
// Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -135,14 +135,14 @@
// Default lcd framebuffer mapping space.
#define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000)
// Map IO memory (requires a priviledged __my_thread capability).
// Map IO memory (requires a priviledged Kernel::my_thread capability).
#include <iris.hh>
static void __map_io (unsigned physical, unsigned mapping):
Page p = __my_memory.create_page ()
Kernel::Page p = Kernel::my_memory.create_page ()
// false means not cachable; false means don't free when done.
p.alloc_physical (physical, false, false)
__my_memory.map (p, mapping)
free_cap (p)
Kernel::my_memory.map (p, mapping)
Kernel::free_cap (p)
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)
@ -2324,8 +2324,8 @@ static __inline__ void udelay (unsigned us):
#ifndef __KERNEL
static __inline__ void cdelay (unsigned ds):
__my_receiver.set_alarm (ds * (HZ / 100))
Cap ().call (~0)
Kernel::my_receiver.set_alarm (ds * (HZ / 100))
Kernel::Cap ().call (~0)
#endif
/***************************************************************************

View File

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

View File

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