mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-29 19:44:16 +02:00
working with new invoke system
This commit is contained in:
parent
4c73b034f8
commit
a838dd63c6
28
alloc.ccp
28
alloc.ccp
@ -195,9 +195,10 @@ kThread *kMemory::alloc_thread (unsigned size):
|
||||
return ret
|
||||
|
||||
kMessage *kMemory::alloc_message (kReceiver *target):
|
||||
kMessage *ret = (kMessage *)search_free (sizeof (kMessage), (void **)&target->messages)
|
||||
kMessage *ret = (kMessage *)search_free (sizeof (kMessage) + sizeof (kCapability), (void **)&target->messages)
|
||||
if !ret:
|
||||
return NULL
|
||||
ret->caps.size = 2
|
||||
if !ret->next:
|
||||
target->last_message = ret
|
||||
return ret
|
||||
@ -243,9 +244,9 @@ kMemory *kMemory::alloc_memory ():
|
||||
kMemory_arch_init (ret)
|
||||
return ret
|
||||
|
||||
void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
caps[index].target = target
|
||||
caps[index].cap_protected = pdata
|
||||
caps[index].protected_data = pdata
|
||||
caps[index].parent = parent
|
||||
caps[index].children.reset ()
|
||||
caps[index].sibling_prev.reset ()
|
||||
@ -262,18 +263,21 @@ void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, k
|
||||
caps[index].sibling_next->sibling_prev = kCapRef (this, index)
|
||||
|
||||
void kCaps::clone (unsigned index, kCapRef source, bool copy):
|
||||
cap (index)->invalidate ()
|
||||
if !source.valid ():
|
||||
return
|
||||
if copy:
|
||||
if source->parent.valid ():
|
||||
set (index, source->target, source->cap_protected, source->parent)
|
||||
set (index, source->target, source->protected_data, source->parent)
|
||||
else if (unsigned)source->target & ~KERNEL_MASK:
|
||||
set (index, source->target, source->cap_protected, kCapRef (), &source->target->capabilities)
|
||||
set (index, source->target, source->protected_data, kCapRef (), &source->target->capabilities)
|
||||
else:
|
||||
set (index, source->target, source->cap_protected, kCapRef (), &((kObject *)source->cap_protected.l)->refs)
|
||||
set (index, source->target, source->protected_data, kCapRef (), &((kObject *)source->protected_data.l)->refs)
|
||||
else:
|
||||
set (index, source->target, source->cap_protected, source)
|
||||
set (index, source->target, source->protected_data, source)
|
||||
|
||||
void kMemory::free_page (kPage *page):
|
||||
if page->flags & Page::PAYING:
|
||||
if page->flags & Kernel::Page::PAYING:
|
||||
unuse ()
|
||||
if page->frame:
|
||||
pfree (page->frame)
|
||||
@ -324,7 +328,7 @@ void kCapability::invalidate ():
|
||||
else if (unsigned)target & ~KERNEL_MASK:
|
||||
target->capabilities = sibling_next
|
||||
else:
|
||||
((kObject *)cap_protected.l)->refs = sibling_next
|
||||
((kObject *)protected_data.l)->refs = sibling_next
|
||||
if sibling_next.valid ():
|
||||
sibling_next->sibling_prev = sibling_prev
|
||||
parent.reset ()
|
||||
@ -342,7 +346,7 @@ void kCapability::invalidate ():
|
||||
c->children.reset ()
|
||||
c->sibling_prev.reset ()
|
||||
c->sibling_next.reset ()
|
||||
c->cap_protected = 0
|
||||
c->protected_data = 0
|
||||
c = next
|
||||
|
||||
void kMemory::free_caps (kCaps *c):
|
||||
@ -376,8 +380,8 @@ void kPage::forget ():
|
||||
share_next = NULL
|
||||
else:
|
||||
// If the page has a frame and should be freed, free it.
|
||||
if !((flags ^ Page::FRAME) & (Page::PHYSICAL | Page::FRAME)):
|
||||
if !((flags ^ Kernel::Page::FRAME) & (Kernel::Page::PHYSICAL | Kernel::Page::FRAME)):
|
||||
raw_pfree (frame)
|
||||
frame = 0
|
||||
flags &= ~(Page::FRAME | Page::SHARED | Page::PHYSICAL | Page::UNCACHED)
|
||||
flags &= ~(Kernel::Page::FRAME | Kernel::Page::SHARED | Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
|
||||
kPage_arch_update_mapping (this)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
514
invoke.ccp
514
invoke.ccp
@ -18,13 +18,44 @@
|
||||
|
||||
#include "kernel.hh"
|
||||
|
||||
static void log_message (char const *prefix, unsigned target, unsigned pdata, kCapability::Context *c):
|
||||
if !dbg_code.l:
|
||||
dbg_log (prefix)
|
||||
dbg_log (": ")
|
||||
dbg_log_num ((unsigned)old_current)
|
||||
dbg_log (" > ")
|
||||
dbg_log_num (target)
|
||||
dbg_log (":")
|
||||
dbg_log_num (pdata)
|
||||
dbg_log ("/")
|
||||
dbg_log_num (c->data[0].l)
|
||||
dbg_log (" ")
|
||||
dbg_log_num (c->data[0].h)
|
||||
dbg_log (",")
|
||||
dbg_log_num (c->data[1].l)
|
||||
dbg_log (" ")
|
||||
dbg_log_num (c->data[1].h)
|
||||
dbg_log (",")
|
||||
dbg_log_num (pdata)
|
||||
dbg_log (";")
|
||||
if c->reply.valid ():
|
||||
dbg_log_num ((unsigned)c->reply->target)
|
||||
dbg_log (":")
|
||||
dbg_log_num (c->reply->protected_data.l)
|
||||
dbg_log (",")
|
||||
if c->arg.valid ():
|
||||
dbg_log_num ((unsigned)c->arg->target)
|
||||
dbg_log (":")
|
||||
dbg_log_num (c->arg->protected_data.l)
|
||||
dbg_log ("\n")
|
||||
|
||||
void kThread::raise (unsigned code, unsigned data):
|
||||
dpanic (code, "raise")
|
||||
dbg_log ("raise ")
|
||||
dbg_log_num ((unsigned)current)
|
||||
dbg_log_char ('/')
|
||||
if code < NUM_EXCEPTION_CODES:
|
||||
dbg_log (exception_name[code])
|
||||
if code < Kernel::NUM_EXCEPTION_CODES:
|
||||
dbg_log (Kernel::exception_name[code])
|
||||
else:
|
||||
dbg_log ("invalid code:")
|
||||
dbg_log_num (code)
|
||||
@ -35,9 +66,7 @@ void kThread::raise (unsigned code, unsigned data):
|
||||
if slots < 1 || !caps[0] || !caps[0]->cap (0)->target:
|
||||
return
|
||||
kCapability::Context c
|
||||
c.caps = NULL
|
||||
c.data[0] = Num (code, data)
|
||||
c.data[1] = 0
|
||||
c.data[0] = Kernel::Num (code, data)
|
||||
caps[0]->cap (0)->invoke (&c)
|
||||
|
||||
// From user-provided, thus untrusted, data, find a capability.
|
||||
@ -65,17 +94,6 @@ kCapRef kThread::find_capability (unsigned code, bool *copy):
|
||||
return kCapRef ()
|
||||
return kCapRef (caps[slot], num)
|
||||
|
||||
void kThread::fill_slot (unsigned slot, kCaps *new_caps):
|
||||
if slot >= slots:
|
||||
if slot != ~0:
|
||||
dpanic (0, "waiting with invalid slot")
|
||||
return
|
||||
if caps[slot]:
|
||||
// TODO: invalidate slot.
|
||||
caps[slot] = new_caps
|
||||
if new_caps:
|
||||
// TODO: link it into a list.
|
||||
|
||||
// Try to deliver a message.
|
||||
bool kReceiver::try_deliver ():
|
||||
if !messages:
|
||||
@ -85,24 +103,37 @@ bool kReceiver::try_deliver ():
|
||||
kMessage *m = last_message
|
||||
if protected_only:
|
||||
for ; m; m = (kMessage *)m->prev:
|
||||
if m->cap_protected.value () == reply_protected_data.value ():
|
||||
if m->protected_data.value () == reply_protected_data.value ():
|
||||
protected_only = false
|
||||
break
|
||||
if !m:
|
||||
return false
|
||||
owner->fill_slot (owner->recv_slot, m->caps)
|
||||
kThread_arch_receive (owner, m->cap_protected, recv_protected, m->data)
|
||||
bool dummy
|
||||
kCapRef c = owner->find_capability (owner->recv_reply, &dummy)
|
||||
if c.valid ():
|
||||
c.clone (kCapRef (&m->caps, 0), true)
|
||||
c = owner->find_capability (owner->recv_arg, &dummy)
|
||||
if c.valid ():
|
||||
c.clone (kCapRef (&m->caps, 1), true)
|
||||
kThread_arch_receive (owner, m->protected_data, m->data)
|
||||
address_space->free_message (this, m)
|
||||
owner->unwait ()
|
||||
return true
|
||||
|
||||
// Send a message to a receiver; try to deliver it immediately.
|
||||
bool kReceiver::send_message (Num cap_protected, kCapability::Context *c):
|
||||
if owner && owner->is_waiting () && (cap_protected.value () == reply_protected_data.value () || !protected_only):
|
||||
bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *c):
|
||||
//log_message ("send_message", (unsigned)this, protected_data.l, c)
|
||||
if owner && owner->is_waiting () && (protected_data.value () == reply_protected_data.value () || !protected_only):
|
||||
if protected_only:
|
||||
protected_only = false
|
||||
owner->fill_slot (owner->recv_slot, c->caps)
|
||||
kThread_arch_receive (owner, cap_protected, recv_protected, c->data)
|
||||
bool dummy
|
||||
kCapRef cap = owner->find_capability (owner->recv_reply, &dummy)
|
||||
if cap.valid ():
|
||||
cap.clone (c->reply, c->copy[0])
|
||||
cap = owner->find_capability (owner->recv_arg, &dummy)
|
||||
if cap.valid ():
|
||||
cap.clone (c->arg, c->copy[1])
|
||||
kThread_arch_receive (owner, protected_data, c->data)
|
||||
owner->unwait ()
|
||||
return true
|
||||
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue.
|
||||
@ -115,8 +146,8 @@ bool kReceiver::send_message (Num cap_protected, kCapability::Context *c):
|
||||
// TODO: use sender-provided storage.
|
||||
if !msg:
|
||||
return false
|
||||
msg->cap_protected = cap_protected
|
||||
if protected_only && cap_protected.value () == reply_protected_data.value ():
|
||||
msg->protected_data = protected_data
|
||||
if protected_only && protected_data.value () == reply_protected_data.value ():
|
||||
// Put this message in the end (where it will be first seen). Clear the protected_only flag.
|
||||
protected_only = false
|
||||
if msg->next:
|
||||
@ -128,59 +159,69 @@ bool kReceiver::send_message (Num cap_protected, kCapability::Context *c):
|
||||
last_message = msg
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
msg->data[i] = c->data[i]
|
||||
msg->caps = c->caps
|
||||
msg->caps.clone (0, c->reply, c->copy[0])
|
||||
msg->caps.clone (1, c->arg, c->copy[1])
|
||||
return true
|
||||
|
||||
static kCapRef reply
|
||||
static kCapability::Context *context
|
||||
// reply_caps is the source of a receiver-generated reply capability.
|
||||
// replied_caps is the source of kernel-generated capabilities which are used as arguments in a reply.
|
||||
static kCaps reply_caps, replied_caps
|
||||
static kReceiver *reply_target
|
||||
static Num reply_protected
|
||||
static Kernel::Num reply_protected
|
||||
|
||||
static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
|
||||
kCapability::Context c
|
||||
c.data[0] = Num (num1, num2)
|
||||
c.data[0] = Kernel::Num (num1, num2)
|
||||
c.data[1] = num3
|
||||
c.caps = NULL
|
||||
invoke (reply_target, reply_protected, &c, NULL)
|
||||
|
||||
static void reply_cap (unsigned target, Num cap_protected, kCapRef *ref):
|
||||
if reply.valid ():
|
||||
reply.set ((kReceiver *)target, cap_protected, kCapRef (), ref)
|
||||
if reply_target:
|
||||
reply_target->send_message (reply_protected, &c)
|
||||
else:
|
||||
dpanic (0x87677654, "no target to reply capability to")
|
||||
reply_num (0)
|
||||
dpanic (0, "nothing to reply to")
|
||||
|
||||
static void receiver_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c):
|
||||
kReceiver *receiver = (kReceiver *)cap_protected.l
|
||||
static void reply_cap (unsigned target, Kernel::Num protected_data, kCapRef *ref):
|
||||
replied_caps.set (0, (kReceiver *)target, protected_data, kCapRef (), ref)
|
||||
kCapability::Context c
|
||||
c.arg = kCapRef (&replied_caps, 0)
|
||||
c.copy[1] = true
|
||||
if reply_target:
|
||||
reply_target->send_message (reply_protected, &c)
|
||||
else:
|
||||
dpanic (0, "nothing to reply to")
|
||||
c.arg->invalidate ()
|
||||
|
||||
static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
kReceiver *receiver = (kReceiver *)protected_data.l
|
||||
switch cmd:
|
||||
case Receiver::SET_OWNER:
|
||||
if c->caps->size < 2:
|
||||
case Kernel::Receiver::SET_OWNER:
|
||||
if !c->arg.valid ():
|
||||
reply_num (~0)
|
||||
return
|
||||
unsigned cap = (unsigned)c->caps->cap (1)->target
|
||||
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Thread::SET_OWNER):
|
||||
unsigned cap = (unsigned)c->arg->target
|
||||
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Kernel::Thread::SET_OWNER):
|
||||
// FIXME: This makes it impossible to use a fake kThread capability.
|
||||
return
|
||||
receiver->own ((kThread *)c->caps->cap (1)->cap_protected.l)
|
||||
receiver->own ((kThread *)c->arg->protected_data.l)
|
||||
break
|
||||
case Receiver::CREATE_CAPABILITY:
|
||||
case Kernel::Receiver::CREATE_CAPABILITY:
|
||||
reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities)
|
||||
return
|
||||
case Receiver::CREATE_CALL_CAPABILITY:
|
||||
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Receiver::CALL_ASYNC : Receiver::CALL), cap_protected, &((kObject *)cap_protected.l)->refs)
|
||||
case Kernel::Receiver::CREATE_CALL_CAPABILITY:
|
||||
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
|
||||
return
|
||||
case Receiver::GET_REPLY_PROTECTED_DATA:
|
||||
case Kernel::Receiver::GET_REPLY_PROTECTED_DATA:
|
||||
reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0)
|
||||
return
|
||||
case Receiver::SET_REPLY_PROTECTED_DATA:
|
||||
case Kernel::Receiver::SET_REPLY_PROTECTED_DATA:
|
||||
receiver->reply_protected_data = c->data[1]
|
||||
break
|
||||
case Receiver::GET_ALARM:
|
||||
case Kernel::Receiver::GET_ALARM:
|
||||
reply_num (receiver->alarm_count)
|
||||
return
|
||||
case Receiver::SET_ALARM:
|
||||
case Receiver::ADD_ALARM:
|
||||
case Kernel::Receiver::SET_ALARM:
|
||||
case Kernel::Receiver::ADD_ALARM:
|
||||
unsigned old = receiver->alarm_count
|
||||
if cmd == Receiver::SET_ALARM:
|
||||
if cmd == Kernel::Receiver::SET_ALARM:
|
||||
receiver->alarm_count = c->data[1].l
|
||||
else:
|
||||
receiver->alarm_count += c->data[1].l
|
||||
@ -204,14 +245,15 @@ static void receiver_invoke (unsigned cmd, unsigned target, Num cap_protected, k
|
||||
reply_num (receiver->alarm_count)
|
||||
return
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
dpanic (0, "invalid receiver operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
return
|
||||
reply_num (0)
|
||||
|
||||
static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c):
|
||||
kMemory *mem = (kMemory *)cap_protected.l
|
||||
static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
kMemory *mem = (kMemory *)protected_data.l
|
||||
switch cmd:
|
||||
case Memory::CREATE:
|
||||
case Kernel::Memory::CREATE:
|
||||
switch c->data[0].h:
|
||||
case CAPTYPE_RECEIVER:
|
||||
kReceiver *ret = mem->alloc_receiver ()
|
||||
@ -219,7 +261,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x03311992, "out of memory creating receiver")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_MEMORY:
|
||||
kMemory *ret = mem->alloc_memory ()
|
||||
@ -227,7 +269,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x13311992, "out of memory creating memory")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_THREAD:
|
||||
kThread *ret = mem->alloc_thread (c->data[1].l)
|
||||
@ -235,7 +277,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
reply_cap (CAPTYPE_THREAD | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x23311992, "out of memory creating thread")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_PAGE:
|
||||
kPage *ret = mem->alloc_page ()
|
||||
@ -243,7 +285,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x33311992, "out of memory creating page")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_CAPS:
|
||||
kCaps *ret = mem->alloc_caps (c->data[1].l)
|
||||
@ -251,112 +293,114 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x43311992, "out of memory creating caps")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
default:
|
||||
dpanic (0, "invalid create type")
|
||||
reply_num (~0)
|
||||
return
|
||||
break
|
||||
case Memory::DESTROY:
|
||||
if c->caps->size < 2 || (unsigned)c->caps->cap (1)->target & ~KERNEL_MASK || !c->caps->cap (1)->target || ((kObject *)c->caps->cap (1)->cap_protected.l)->address_space != mem:
|
||||
case Kernel::Memory::DESTROY:
|
||||
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || !c->arg->target || ((kObject *)c->arg->protected_data.l)->address_space != mem:
|
||||
reply_num (~0)
|
||||
return
|
||||
switch (unsigned)c->caps->cap (1)->target & CAPTYPE_MASK:
|
||||
switch (unsigned)c->arg->target & CAPTYPE_MASK:
|
||||
case CAPTYPE_RECEIVER:
|
||||
mem->free_receiver ((kReceiver *)c->caps->cap (1)->cap_protected.l)
|
||||
mem->free_receiver ((kReceiver *)c->arg->protected_data.l)
|
||||
break
|
||||
case CAPTYPE_MEMORY:
|
||||
mem->free_memory ((kMemory *)c->caps->cap (1)->cap_protected.l)
|
||||
mem->free_memory ((kMemory *)c->arg->protected_data.l)
|
||||
break
|
||||
case CAPTYPE_THREAD:
|
||||
mem->free_thread ((kThread *)c->caps->cap (1)->cap_protected.l)
|
||||
mem->free_thread ((kThread *)c->arg->protected_data.l)
|
||||
break
|
||||
case CAPTYPE_PAGE:
|
||||
mem->free_page ((kPage *)c->caps->cap (1)->cap_protected.l)
|
||||
mem->free_page ((kPage *)c->arg->protected_data.l)
|
||||
break
|
||||
case CAPTYPE_CAPS:
|
||||
mem->free_caps ((kCaps *)c->caps->cap (1)->cap_protected.l)
|
||||
mem->free_caps ((kCaps *)c->arg->protected_data.l)
|
||||
break
|
||||
default:
|
||||
panic (0x55228930, "invalid case")
|
||||
return
|
||||
break
|
||||
case Memory::LIST:
|
||||
case Kernel::Memory::LIST:
|
||||
// TODO
|
||||
break
|
||||
case Memory::MAP:
|
||||
case Kernel::Memory::MAP:
|
||||
// FIXME: this should work for fake pages as well.
|
||||
if c->caps->size < 2 || (unsigned)c->caps->cap (1)->target & ~KERNEL_MASK || ((unsigned)c->caps->cap (1)->target & CAPTYPE_MASK) != CAPTYPE_PAGE:
|
||||
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || ((unsigned)c->arg->target & CAPTYPE_MASK) != CAPTYPE_PAGE:
|
||||
dpanic (0x22993341, "Trying to map non-page")
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l
|
||||
kPage *page = (kPage *)c->arg->protected_data.l
|
||||
if page->address_space != mem:
|
||||
dpanic (0x52993341, "Trying to map foreign page")
|
||||
reply_num (~0)
|
||||
return
|
||||
bool readonly = c->data[1].l & (unsigned)c->caps->cap (1)->target & Page::READONLY
|
||||
bool readonly = c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY
|
||||
mem->map (page, c->data[1].l & PAGE_MASK, readonly)
|
||||
break
|
||||
case Memory::MAPPING:
|
||||
case Kernel::Memory::MAPPING:
|
||||
bool readonly
|
||||
kPage *page = mem->get_mapping (c->data[1].l, &readonly)
|
||||
unsigned t = CAPTYPE_PAGE | CAP_MASTER
|
||||
if readonly:
|
||||
t |= Page::READONLY
|
||||
t |= Kernel::Page::READONLY
|
||||
reply_cap (t, (unsigned)page, &page->refs)
|
||||
return
|
||||
case Memory::GET_LIMIT:
|
||||
case Kernel::Memory::GET_LIMIT:
|
||||
reply_num (mem->limit)
|
||||
return
|
||||
case Memory::SET_LIMIT:
|
||||
case Kernel::Memory::SET_LIMIT:
|
||||
mem->limit = c->data[1].l
|
||||
break
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
dpanic (0, "invalid memory operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
return
|
||||
reply_num (0)
|
||||
|
||||
static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c):
|
||||
kThread *thread = (kThread *)cap_protected.l
|
||||
static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
kThread *thread = (kThread *)protected_data.l
|
||||
switch cmd:
|
||||
case Thread::GET_INFO:
|
||||
case Kernel::Thread::GET_INFO:
|
||||
switch c->data[0].h:
|
||||
case Thread::PC:
|
||||
case Kernel::Thread::PC:
|
||||
reply_num (thread->pc)
|
||||
return
|
||||
case Thread::SP:
|
||||
case Kernel::Thread::SP:
|
||||
reply_num (thread->sp)
|
||||
return
|
||||
case Thread::FLAGS:
|
||||
case Kernel::Thread::FLAGS:
|
||||
reply_num (thread->flags)
|
||||
return
|
||||
default:
|
||||
reply_num (*kThread_arch_info (thread, c->data[0].h))
|
||||
return
|
||||
case Thread::SET_INFO:
|
||||
case Kernel::Thread::SET_INFO:
|
||||
unsigned *value
|
||||
switch c->data[1].l:
|
||||
case Thread::PC:
|
||||
case Kernel::Thread::PC:
|
||||
value = &thread->pc
|
||||
break
|
||||
case Thread::SP:
|
||||
case Kernel::Thread::SP:
|
||||
value = &thread->sp
|
||||
break
|
||||
case Thread::FLAGS:
|
||||
case Kernel::Thread::FLAGS:
|
||||
// It is not possible to set the PRIV flag (but it can be reset).
|
||||
if c->data[1].l & Thread::PRIV:
|
||||
c->data[1].h &= ~Thread::PRIV
|
||||
if c->data[1].l & Kernel::Thread::PRIV:
|
||||
c->data[1].h &= ~Kernel::Thread::PRIV
|
||||
value = &thread->flags
|
||||
if c->data[1].h & ~Thread::USER_FLAGS:
|
||||
if c->data[1].h & ~Kernel::Thread::USER_FLAGS:
|
||||
unsigned v = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
|
||||
if (v & Thread::WAITING) != (*value & Thread::WAITING):
|
||||
if v & Thread::WAITING:
|
||||
if (v & Kernel::Thread::WAITING) != (*value & Kernel::Thread::WAITING):
|
||||
if v & Kernel::Thread::WAITING:
|
||||
thread->wait ()
|
||||
else
|
||||
thread->unwait ()
|
||||
if (v & Thread::RUNNING) != (*value & Thread::RUNNING):
|
||||
if v & Thread::RUNNING:
|
||||
if (v & Kernel::Thread::RUNNING) != (*value & Kernel::Thread::RUNNING):
|
||||
if v & Kernel::Thread::RUNNING:
|
||||
thread->run ()
|
||||
else
|
||||
thread->unrun ()
|
||||
@ -367,93 +411,114 @@ static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
if value:
|
||||
*value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
|
||||
break
|
||||
case Thread::USE_SLOT:
|
||||
if c->data[1].l >= thread->slots || c->caps->size < 2:
|
||||
case Kernel::Thread::USE_SLOT:
|
||||
if c->data[1].l >= thread->slots || !c->arg.valid ():
|
||||
dbg_send (5, 3)
|
||||
dpanic (c->data[1].l, "no argument given for USE_SLOT")
|
||||
reply_num (~0)
|
||||
return
|
||||
// FIXME: This doesn't allow using a fake caps.
|
||||
if (unsigned)c->caps->cap (1)->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->caps->cap (1)->target != (CAPTYPE_CAPS | Caps::USE):
|
||||
if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Kernel::Caps::USE):
|
||||
dpanic (0, "argument for USE_SLOT is not a caps")
|
||||
reply_num (~0)
|
||||
return
|
||||
thread->fill_slot (c->data[1].l, (kCaps *)c->caps->cap (1)->cap_protected.l)
|
||||
reply_num (0)
|
||||
return
|
||||
case Thread::SCHEDULE:
|
||||
unsigned slot = c->data[1].l
|
||||
kCaps *new_caps = (kCaps *)c->arg->protected_data.l
|
||||
if slot >= thread->slots:
|
||||
dpanic (0, "using invalid slot")
|
||||
return
|
||||
if thread->caps[slot]:
|
||||
// TODO: invalidate slot.
|
||||
thread->caps[slot] = new_caps
|
||||
if new_caps:
|
||||
// TODO: link it into a list.
|
||||
break
|
||||
case Kernel::Thread::SCHEDULE:
|
||||
do_schedule = true
|
||||
return
|
||||
default:
|
||||
if !(thread->flags & Thread::PRIV):
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
if !(thread->flags & Kernel::Thread::PRIV):
|
||||
dpanic (0, "invalid thread operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
return
|
||||
switch cmd:
|
||||
case Thread::PRIV_REGISTER_INTERRUPT:
|
||||
arch_register_interrupt (c->data[1].l, c->caps->size >= 2 && (((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK) == CAPTYPE_RECEIVER ? (kReceiver *)c->caps->cap (1)->cap_protected.l : NULL)
|
||||
case Kernel::Thread::PRIV_REGISTER_INTERRUPT:
|
||||
arch_register_interrupt (c->data[1].l, c->arg.valid () && (((unsigned)c->arg->target) & ~REQUEST_MASK) == CAPTYPE_RECEIVER ? (kReceiver *)c->arg->protected_data.l : NULL)
|
||||
break
|
||||
case Thread::PRIV_GET_TOP_MEMORY:
|
||||
case Kernel::Thread::PRIV_GET_TOP_MEMORY:
|
||||
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)&top_memory, &top_memory.refs)
|
||||
return
|
||||
case Thread::PRIV_MAKE_PRIV:
|
||||
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
|
||||
case Kernel::Thread::PRIV_MAKE_PRIV:
|
||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
|
||||
reply_num (~0)
|
||||
return
|
||||
((kThread *)c->caps->cap (1)->cap_protected.l)->flags |= Thread::PRIV
|
||||
((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV
|
||||
break
|
||||
case Thread::PRIV_ALLOC_RANGE:
|
||||
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
|
||||
case Kernel::Thread::PRIV_ALLOC_RANGE:
|
||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
|
||||
panic (0x54365435, "non-memory argument to alloc_range")
|
||||
reply_num (~0)
|
||||
return
|
||||
kMemory *mem = (kMemory *)c->caps->cap (1)->cap_protected.l
|
||||
kMemory *mem = (kMemory *)c->arg->protected_data.l
|
||||
if !mem->use (c->data[1].l):
|
||||
dpanic (0x34365435, "out of memory during alloc_range")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
unsigned data = phys_alloc (c->data[1].l)
|
||||
if !data:
|
||||
mem->unuse (c->data[1].l)
|
||||
dpanic (0x14365435, "out of memory during alloc_range")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
reply_num (Kernel::ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
reply_num (data & ~0xc0000000)
|
||||
return
|
||||
case Thread::PRIV_ALLOC_PHYSICAL:
|
||||
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
case Kernel::Thread::PRIV_ALLOC_PHYSICAL:
|
||||
if !c->arg.valid ():
|
||||
panic (0x71342134, "no argument provided for alloc physical")
|
||||
reply_num (~0)
|
||||
return
|
||||
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
panic (0x21342134, "no page provided for alloc physical")
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l
|
||||
kPage *page = (kPage *)c->arg->protected_data.l
|
||||
page->forget ()
|
||||
if !(c->data[1].l & 2):
|
||||
if page->flags & Page::PAYING:
|
||||
page->flags &= ~Page::PAYING
|
||||
if page->flags & Kernel::Page::PAYING:
|
||||
page->flags &= ~Kernel::Page::PAYING
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
// This is for mapping allocated ranges. They are already paid for. Record that.
|
||||
if page->flags & Page::PAYING:
|
||||
if page->flags & Kernel::Page::PAYING:
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
page->flags |= Page::PAYING
|
||||
page->flags |= Kernel::Page::PAYING
|
||||
page->frame = c->data[1].l & PAGE_MASK
|
||||
page->flags |= Page::FRAME
|
||||
page->flags |= Kernel::Page::FRAME
|
||||
if !(c->data[1].l & 1):
|
||||
page->flags |= Page::UNCACHED
|
||||
page->flags |= Kernel::Page::UNCACHED
|
||||
if !(c->data[1].l & 2):
|
||||
page->flags |= Page::PHYSICAL
|
||||
page->flags |= Kernel::Page::PHYSICAL
|
||||
kPage_arch_update_mapping (page)
|
||||
break
|
||||
case Thread::PRIV_PHYSICAL_ADDRESS:
|
||||
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
|
||||
case Kernel::Thread::PRIV_PHYSICAL_ADDRESS:
|
||||
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
|
||||
dpanic (0x99049380, "invalid page for physical address")
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l
|
||||
kPage *page = (kPage *)c->arg->protected_data.l
|
||||
reply_num (page->frame & ~0xc0000000)
|
||||
return
|
||||
case Kernel::Thread::PRIV_PANIC:
|
||||
panic (c->data[1].l, "panic requested by thread")
|
||||
reply_num (~0)
|
||||
return
|
||||
case Kernel::Thread::DBG_SEND:
|
||||
dbg_send (c->data[1].l, c->data[1].h)
|
||||
break
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
dpanic (0, "invalid priv thread operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
return
|
||||
reply_num (0)
|
||||
return
|
||||
@ -461,10 +526,10 @@ static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
static bool page_check_payment (kPage *page):
|
||||
kPage *p
|
||||
for p = page->share_prev; p; p = p->share_prev:
|
||||
if p->flags & Page::PAYING:
|
||||
if p->flags & Kernel::Page::PAYING:
|
||||
return true
|
||||
for p = page->share_next; p; p = p->share_next:
|
||||
if p->flags & Page::PAYING:
|
||||
if p->flags & Kernel::Page::PAYING:
|
||||
return true
|
||||
// No kPage is paying for this frame anymore.
|
||||
raw_pfree (page->frame)
|
||||
@ -473,38 +538,38 @@ static bool page_check_payment (kPage *page):
|
||||
p->frame = NULL
|
||||
p->share_prev = NULL
|
||||
p->share_next = NULL
|
||||
p->flags &= ~(Page::SHARED | Page::FRAME)
|
||||
p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME)
|
||||
kPage_arch_update_mapping (p)
|
||||
for p = page, next = p->share_next; p; p = next, next = p->share_next:
|
||||
p->frame = NULL
|
||||
p->share_prev = NULL
|
||||
p->share_next = NULL
|
||||
p->flags &= ~(Page::SHARED | Page::FRAME)
|
||||
p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME)
|
||||
kPage_arch_update_mapping (p)
|
||||
return false
|
||||
|
||||
static void page_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c):
|
||||
kPage *page = (kPage *)cap_protected.l
|
||||
switch cmd & ~Page::READONLY:
|
||||
case Page::SHARE:
|
||||
if c->caps->size < 2:
|
||||
static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
kPage *page = (kPage *)protected_data.l
|
||||
switch cmd & ~Kernel::Page::READONLY:
|
||||
case Kernel::Page::SHARE:
|
||||
if !c->arg.valid ():
|
||||
// Cannot share without a target page.
|
||||
reply_num (~0)
|
||||
return
|
||||
if ((unsigned)c->caps->cap (1)->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
// FIXME: This makes it impossible to use a fake kPage capability.
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *t = (kPage *)c->caps->cap (1)->cap_protected.l
|
||||
kPage *t = (kPage *)c->arg->protected_data.l
|
||||
t->forget ()
|
||||
if c->data[0].h & Page::READONLY || cmd & Page::READONLY:
|
||||
t->flags |= Page::READONLY
|
||||
if !(page->flags & Page::FRAME):
|
||||
if c->data[0].h & Kernel::Page::READONLY || cmd & Kernel::Page::READONLY:
|
||||
t->flags |= Kernel::Page::READONLY
|
||||
if !(page->flags & Kernel::Page::FRAME):
|
||||
break
|
||||
if c->data[0].h & Page::COPY:
|
||||
if ~t->flags & Page::PAYING:
|
||||
if c->data[0].h & Kernel::Page::COPY:
|
||||
if ~t->flags & Kernel::Page::PAYING:
|
||||
break
|
||||
if !(c->data[0].h & Page::FORGET) || page->flags & Page::SHARED:
|
||||
if !(c->data[0].h & Kernel::Page::FORGET) || page->flags & Kernel::Page::SHARED:
|
||||
unsigned *d = (unsigned *)page->frame
|
||||
if t == page:
|
||||
kPage *other = page->share_next ? page->share_next : page->share_prev
|
||||
@ -519,28 +584,28 @@ static void page_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapa
|
||||
page->share_prev = NULL
|
||||
page_check_payment (other)
|
||||
else:
|
||||
t->flags |= Page::FRAME
|
||||
t->flags |= Kernel::Page::FRAME
|
||||
t->frame = raw_zalloc ()
|
||||
for unsigned i = 0; i <= (c->data[0].h & ~PAGE_MASK); i += 4:
|
||||
((unsigned *)t->frame)[i >> 2] = d[i >> 2]
|
||||
else:
|
||||
if t != page:
|
||||
t->frame = page->frame
|
||||
t->flags |= Page::FRAME
|
||||
t->flags |= Kernel::Page::FRAME
|
||||
page->frame = NULL
|
||||
page->flags &= ~Page::FRAME
|
||||
page->flags &= ~Kernel::Page::FRAME
|
||||
kPage_arch_update_mapping (page)
|
||||
kPage_arch_update_mapping (t)
|
||||
else:
|
||||
if t == page:
|
||||
break
|
||||
if c->data[0].h & Page::FORGET:
|
||||
if ~page->flags & Page::SHARED:
|
||||
if t->flags & Page::PAYING:
|
||||
if c->data[0].h & Kernel::Page::FORGET:
|
||||
if ~page->flags & Kernel::Page::SHARED:
|
||||
if t->flags & Kernel::Page::PAYING:
|
||||
t->frame = page->frame
|
||||
t->flags |= Page::FRAME
|
||||
t->flags |= Kernel::Page::FRAME
|
||||
page->frame = NULL
|
||||
page->flags &= ~Page::FRAME
|
||||
page->flags &= ~Kernel::Page::FRAME
|
||||
kPage_arch_update_mapping (page)
|
||||
else:
|
||||
t->share_prev = page->share_prev
|
||||
@ -561,51 +626,52 @@ static void page_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapa
|
||||
t->share_prev->share_next = t
|
||||
kPage_arch_update_mapping (t)
|
||||
break
|
||||
case Page::SET_FLAGS:
|
||||
if cmd & Page::READONLY:
|
||||
case Kernel::Page::SET_FLAGS:
|
||||
if cmd & Kernel::Page::READONLY:
|
||||
reply_num (~0)
|
||||
return
|
||||
// Always refuse to set reserved flags.
|
||||
c->data[1].h &= ~(Page::PHYSICAL | Page::UNCACHED)
|
||||
c->data[1].h &= ~(Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
|
||||
// Remember the old flags.
|
||||
unsigned old = page->flags
|
||||
// Compute the new flags.
|
||||
unsigned new_flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
|
||||
|
||||
// If we stop paying, see if the frame is still paid for. If not, free it.
|
||||
if ~new_flags & old & Page::PAYING:
|
||||
if ~new_flags & old & Kernel::Page::PAYING:
|
||||
// Decrease the use counter in any case.
|
||||
page->address_space->unuse ()
|
||||
if !page_check_payment (page):
|
||||
new_flags &= ~Page::FRAME
|
||||
new_flags &= ~Kernel::Page::FRAME
|
||||
|
||||
// If we start paying, increase the use counter.
|
||||
if new_flags & ~old & Page::PAYING:
|
||||
if new_flags & ~old & Kernel::Page::PAYING:
|
||||
if !page->address_space->use():
|
||||
// If it doesn't work, refuse to set the flag, and refuse to allocate a frame.
|
||||
new_flags &= ~(Page::PAYING | Page::FRAME)
|
||||
if old & Page::FRAME:
|
||||
new_flags |= Page::FRAME
|
||||
new_flags &= ~(Kernel::Page::PAYING | Kernel::Page::FRAME)
|
||||
if old & Kernel::Page::FRAME:
|
||||
new_flags |= Kernel::Page::FRAME
|
||||
|
||||
// If we want a frame, see if we can get it.
|
||||
if ~old & new_flags & Page::FRAME:
|
||||
if ~old & new_flags & Kernel::Page::FRAME:
|
||||
kPage *p
|
||||
for p = page; p; p = p->share_prev:
|
||||
if p->flags & Page::PAYING:
|
||||
if p->flags & Kernel::Page::PAYING:
|
||||
break
|
||||
if !p:
|
||||
for p = page->share_next; p; p = p->share_next:
|
||||
if p->flags & Page::PAYING:
|
||||
if p->flags & Kernel::Page::PAYING:
|
||||
break
|
||||
if !p:
|
||||
new_flags &= ~Page::FRAME
|
||||
new_flags &= ~Kernel::Page::FRAME
|
||||
// If we can get the new frame, get it.
|
||||
if ~old & new_flags & Page::FRAME:
|
||||
if ~old & new_flags & Kernel::Page::FRAME:
|
||||
page->frame = page->address_space->zalloc ()
|
||||
kPage_arch_update_mapping (page)
|
||||
break
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
dpanic (0, "invalid page operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
return
|
||||
reply_num (0)
|
||||
|
||||
@ -619,6 +685,9 @@ static void print_cap (kCapRef cap, kCapRef self):
|
||||
dbg_log_num (cap.index, 1)
|
||||
if !cap.valid ():
|
||||
dbg_log_char ('!')
|
||||
else:
|
||||
dbg_log_char ('=')
|
||||
dbg_log_num (cap->protected_data.l)
|
||||
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
|
||||
print_cap (c, self)
|
||||
if cap.deref () == self.deref ():
|
||||
@ -626,10 +695,17 @@ static void print_cap (kCapRef cap, kCapRef self):
|
||||
else:
|
||||
dbg_log_char (']')
|
||||
|
||||
static void caps_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c):
|
||||
kCaps *caps = (kCapsP)cap_protected.l
|
||||
static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
kCaps *caps = (kCapsP)protected_data.l
|
||||
switch cmd:
|
||||
case Caps::PRINT:
|
||||
case Kernel::Caps::SET:
|
||||
if c->data[1].l >= caps->size:
|
||||
dpanic (0, "invalid index for set caps")
|
||||
return
|
||||
caps->clone (c->data[1].l, c->arg, c->copy[1])
|
||||
reply_num (0)
|
||||
return
|
||||
case Kernel::Caps::PRINT:
|
||||
if c->data[1].l >= caps->size:
|
||||
dpanic (0, "invalid caps for print")
|
||||
return
|
||||
@ -662,66 +738,66 @@ static void caps_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapa
|
||||
dbg_log_char ('\n')
|
||||
return
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
dpanic (0, "invalid caps operation")
|
||||
reply_num (Kernel::ERR_INVALID_OPERATION)
|
||||
return
|
||||
|
||||
static void kill_reply (kCapability *self):
|
||||
while self->parent.valid ():
|
||||
self = self->parent.deref ()
|
||||
while self->sibling_prev.valid ():
|
||||
self->sibling_prev->invalidate ()
|
||||
while self->sibling_next.valid ():
|
||||
self->sibling_next->invalidate ()
|
||||
self->invalidate ()
|
||||
static void kill_reply (kReceiver *r):
|
||||
kCapRef cap = r->refs
|
||||
while cap.valid ():
|
||||
kCapability *c = cap.deref ()
|
||||
cap = c->sibling_next
|
||||
if (unsigned)c->target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
|
||||
c->invalidate ()
|
||||
|
||||
static void kernel_invoke (unsigned target, Num cap_protected, kCapability::Context *c, kCapability *self):
|
||||
static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
// Kernel calling convention:
|
||||
// data[0].l is the request.
|
||||
// caps[0] is the reply capability
|
||||
// other parameters' meanings depend on the operation.
|
||||
if target == (CAPTYPE_RECEIVER | Receiver::CALL) || target == (CAPTYPE_RECEIVER | Receiver::CALL_ASYNC):
|
||||
// This is a call capability. caps->cap (0) is the capability to call. It should be replaced by the reply capability.
|
||||
reply_target = (kReceiver *)cap_protected.l
|
||||
reply_target->protected_only = target == (CAPTYPE_RECEIVER | Receiver::CALL)
|
||||
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL_ASYNC):
|
||||
// This is a call capability. reply is the capability to call. It should be replaced by the reply capability.
|
||||
((kReceiver *)protected_data.l)->protected_only = target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL)
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
if !c->caps || c->caps->size == 0:
|
||||
// No caps, so no target to call.
|
||||
if !reply_target:
|
||||
dpanic (0x54635675, "no target to call")
|
||||
return
|
||||
kReceiver *call_target = c->caps->cap (0)->target
|
||||
Num call_cap_protected = c->caps->cap (0)->cap_protected
|
||||
if ((unsigned)call_target & ~KERNEL_MASK) != 0:
|
||||
if ((unsigned)reply_target & ~KERNEL_MASK) != 0:
|
||||
// This is a user-implemented object. Create a real reply capability.
|
||||
c->caps->cap (0)->invalidate ()
|
||||
c->caps->set (0, (kReceiver *)(CAPTYPE_RECEIVER | Receiver::REPLY), cap_protected, kCapRef (), &((kReceiver *)cap_protected.l)->refs)
|
||||
call_target->send_message (call_cap_protected, c)
|
||||
else if (unsigned)call_target == (CAPTYPE_RECEIVER | Receiver::REPLY):
|
||||
kReceiver *call_target = reply_target
|
||||
c->reply = kCapRef (&reply_caps, 0)
|
||||
c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Kernel::Receiver::REPLY), protected_data, kCapRef (), &((kReceiver *)protected_data.l)->refs)
|
||||
c->copy[0] = true
|
||||
call_target->send_message (reply_protected, c)
|
||||
c->reply->invalidate ()
|
||||
else if (unsigned)reply_target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
|
||||
// Reply capability: destroy all before invoke.
|
||||
kill_reply (c->caps->cap (0))
|
||||
kReceiver *r = (kReceiver *)call_cap_protected.l
|
||||
kReceiver *r = (kReceiver *)reply_protected.l
|
||||
kill_reply (r)
|
||||
r->send_message (r->reply_protected_data, c)
|
||||
else:
|
||||
// Kernel call: don't create actual capablities.
|
||||
kCapRef call_target = c->reply
|
||||
c->reply.reset ()
|
||||
reply_target = (kReceiver *)protected_data.l
|
||||
reply_protected = reply_target->reply_protected_data
|
||||
c->caps->cap (0)->invalidate ()
|
||||
kernel_invoke ((unsigned)call_target, call_cap_protected, c, NULL)
|
||||
kernel_invoke ((unsigned)call_target->target, call_target->protected_data, c)
|
||||
return
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
if target == (CAPTYPE_RECEIVER | Receiver::REPLY):
|
||||
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
|
||||
// This is a reply capability.
|
||||
kReceiver *r = (kReceiver *)cap_protected.l
|
||||
kill_reply (self)
|
||||
kReceiver *r = (kReceiver *)protected_data.l
|
||||
kill_reply (r)
|
||||
r->send_message (r->reply_protected_data, c)
|
||||
return
|
||||
if !target:
|
||||
return
|
||||
reply = kCapRef (c->caps, 0)
|
||||
unsigned cmd
|
||||
if (target & REQUEST_MASK) == CAP_MASTER:
|
||||
if c->data[0].l & CAP_MASTER_CREATE:
|
||||
reply_cap (target | (c->data[0].l & REQUEST_MASK), cap_protected, &((kObject *)cap_protected.l)->refs)
|
||||
reply_cap (target | (c->data[0].l & REQUEST_MASK), protected_data, &((kObject *)protected_data.l)->refs)
|
||||
return
|
||||
cmd = c->data[0].l
|
||||
c->data[0].l = 0
|
||||
@ -729,36 +805,38 @@ static void kernel_invoke (unsigned target, Num cap_protected, kCapability::Cont
|
||||
cmd = target & REQUEST_MASK
|
||||
switch target & CAPTYPE_MASK:
|
||||
case CAPTYPE_RECEIVER:
|
||||
receiver_invoke (cmd, target, cap_protected, c)
|
||||
receiver_invoke (cmd, target, protected_data, c)
|
||||
break
|
||||
case CAPTYPE_MEMORY:
|
||||
memory_invoke (cmd, target, cap_protected, c)
|
||||
memory_invoke (cmd, target, protected_data, c)
|
||||
break
|
||||
case CAPTYPE_THREAD:
|
||||
thread_invoke (cmd, target, cap_protected, c)
|
||||
thread_invoke (cmd, target, protected_data, c)
|
||||
break
|
||||
case CAPTYPE_PAGE:
|
||||
page_invoke (cmd, target, cap_protected, c)
|
||||
page_invoke (cmd, target, protected_data, c)
|
||||
break
|
||||
case CAPTYPE_CAPS:
|
||||
caps_invoke (cmd, target, cap_protected, c)
|
||||
caps_invoke (cmd, target, protected_data, c)
|
||||
break
|
||||
default:
|
||||
panic (0x99337744, "invalid capability type invoked")
|
||||
return
|
||||
return
|
||||
|
||||
void invoke (kReceiverP target, Num cap_protected, kCapability::Context *c, kCapability *self):
|
||||
void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
//log_message ("invoke", (unsigned)target, protected_data.l, c)
|
||||
if (unsigned)target & ~KERNEL_MASK:
|
||||
// This is not a kernel capability: send a message to the receiver.
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
target->send_message (cap_protected, c)
|
||||
target->send_message (protected_data, c)
|
||||
return
|
||||
// This is a kernel capability. Use a function to allow optimized call capabilities.
|
||||
if !c->caps || c->caps->size < 1:
|
||||
reply_target = NULL
|
||||
context = c
|
||||
if c->reply.valid ():
|
||||
reply_target = c->reply->target
|
||||
reply_protected = c->reply->protected_data
|
||||
else:
|
||||
reply_target = c->caps->cap (0)->target
|
||||
reply_protected = c->caps->cap (0)->cap_protected
|
||||
kernel_invoke ((unsigned)target, cap_protected, c, self)
|
||||
reply_target = NULL
|
||||
kernel_invoke ((unsigned)target, protected_data, c)
|
||||
|
824
iris.hhp
824
iris.hhp
@ -33,47 +33,6 @@
|
||||
#define PAGE_SIZE (1 << PAGE_BITS)
|
||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||
|
||||
enum Exception_code:
|
||||
NO_ERROR
|
||||
ERR_WRITE_DENIED
|
||||
ERR_UNMAPPED_READ
|
||||
ERR_UNMAPPED_WRITE
|
||||
ERR_INVALID_ADDRESS_READ
|
||||
ERR_INVALID_ADDRESS_WRITE
|
||||
ERR_RESERVED_INSTRUCTION
|
||||
ERR_COPROCESSOR_UNUSABLE
|
||||
ERR_OVERFLOW
|
||||
ERR_TRAP
|
||||
ERR_WATCHPOINT
|
||||
ERR_BREAKPOINT
|
||||
ERR_NO_PAGE_DIRECTORY
|
||||
ERR_NO_PAGE_TABLE
|
||||
ERR_OUT_OF_MEMORY
|
||||
// The following are not raised, but returned.
|
||||
ERR_INVALID_OPERATION
|
||||
NUM_EXCEPTION_CODES
|
||||
|
||||
#ifndef NDEBUG
|
||||
static const char *exception_name[NUM_EXCEPTION_CODES] = {
|
||||
"no error",
|
||||
"write denied",
|
||||
"unmapped read",
|
||||
"unmapped write",
|
||||
"invalid address read",
|
||||
"invalid address write",
|
||||
"reserved instruction",
|
||||
"coprocessor unusable",
|
||||
"overflow",
|
||||
"trap",
|
||||
"watchpoint",
|
||||
"breakpoint",
|
||||
"no page directory",
|
||||
"no page table",
|
||||
"out of memory",
|
||||
"invalid operation"
|
||||
}
|
||||
#endif
|
||||
|
||||
#define KERNEL_MASK 0xfff
|
||||
#define CAPTYPE_MASK 0xe00
|
||||
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
|
||||
@ -94,425 +53,422 @@ static const char *exception_name[NUM_EXCEPTION_CODES] = {
|
||||
// Master capabilities can create others.
|
||||
#define CAP_MASTER_CREATE (1 << 31)
|
||||
|
||||
struct Num:
|
||||
unsigned l, h
|
||||
Num (unsigned long long n = 0) : l (n), h (n >> 32):
|
||||
Num (unsigned ll, unsigned hh) : l (ll), h (hh):
|
||||
unsigned long long value () const:
|
||||
return ((unsigned long long)h << 32) | l
|
||||
unsigned &low ():
|
||||
return l
|
||||
unsigned &high ():
|
||||
return h
|
||||
unsigned const &low () const:
|
||||
return l
|
||||
unsigned const &high () const:
|
||||
return h
|
||||
|
||||
// The start function has this prototype (there is no main function).
|
||||
Num start ()
|
||||
|
||||
struct Cap
|
||||
struct Caps
|
||||
struct Receiver
|
||||
struct Thread
|
||||
struct Page
|
||||
struct Memory
|
||||
|
||||
#define __receiver_num 0
|
||||
#define __thread_num 1
|
||||
#define __memory_num 2
|
||||
#define __call_num 3
|
||||
#define __parent_num 4
|
||||
|
||||
#define __tmp_slot 1
|
||||
|
||||
// If this flag is set in a capability, it is copied instead of mapped.
|
||||
// If it is set in the target capability, the Thread waits after the request.
|
||||
#define CAP_COPY ((unsigned)0x80000000)
|
||||
// This constant signifies that no capability is passed.
|
||||
#define CAP_NONE (~CAP_COPY)
|
||||
|
||||
extern Receiver __my_receiver
|
||||
extern Thread __my_thread
|
||||
extern Memory __my_memory
|
||||
extern Cap __my_call
|
||||
extern Cap __my_parent
|
||||
extern Caps __my_caps
|
||||
namespace Kernel:
|
||||
enum Exception_code:
|
||||
NO_ERROR
|
||||
ERR_WRITE_DENIED
|
||||
ERR_UNMAPPED_READ
|
||||
ERR_UNMAPPED_WRITE
|
||||
ERR_INVALID_ADDRESS_READ
|
||||
ERR_INVALID_ADDRESS_WRITE
|
||||
ERR_RESERVED_INSTRUCTION
|
||||
ERR_COPROCESSOR_UNUSABLE
|
||||
ERR_OVERFLOW
|
||||
ERR_TRAP
|
||||
ERR_WATCHPOINT
|
||||
ERR_BREAKPOINT
|
||||
ERR_NO_PAGE_DIRECTORY
|
||||
ERR_NO_PAGE_TABLE
|
||||
ERR_OUT_OF_MEMORY
|
||||
// The following are not raised, but returned.
|
||||
ERR_INVALID_OPERATION
|
||||
NUM_EXCEPTION_CODES
|
||||
|
||||
unsigned alloc_slot ()
|
||||
unsigned alloc_cap ()
|
||||
void free_slot (unsigned slot)
|
||||
void free_cap (Cap cap)
|
||||
#ifndef NDEBUG
|
||||
static const char *exception_name[NUM_EXCEPTION_CODES] = {
|
||||
"no error",
|
||||
"write denied",
|
||||
"unmapped read",
|
||||
"unmapped write",
|
||||
"invalid address read",
|
||||
"invalid address write",
|
||||
"reserved instruction",
|
||||
"coprocessor unusable",
|
||||
"overflow",
|
||||
"trap",
|
||||
"watchpoint",
|
||||
"breakpoint",
|
||||
"no page directory",
|
||||
"no page table",
|
||||
"out of memory",
|
||||
"invalid operation"
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Cap:
|
||||
unsigned code
|
||||
inline Cap copy () const
|
||||
inline Cap ()
|
||||
explicit inline Cap (unsigned c)
|
||||
inline Cap (unsigned slot, unsigned idx)
|
||||
inline unsigned slot () const
|
||||
inline unsigned idx () const
|
||||
struct IMessage
|
||||
struct OMessage
|
||||
inline void invoke (IMessage const *i, OMessage *o)
|
||||
inline void call (IMessage *i, OMessage *o)
|
||||
inline void invoke (Num d0 = 0, Num d1 = 0)
|
||||
inline Num call (Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
|
||||
inline Num icall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
|
||||
inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
|
||||
inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
|
||||
inline Cap clone (Cap target = Cap (0, alloc_cap ()))
|
||||
struct Num:
|
||||
unsigned l, h
|
||||
Num (unsigned long long n = 0) : l (n), h (n >> 32):
|
||||
Num (unsigned ll, unsigned hh) : l (ll), h (hh):
|
||||
unsigned long long value () const:
|
||||
return ((unsigned long long)h << 32) | l
|
||||
unsigned &low ():
|
||||
return l
|
||||
unsigned &high ():
|
||||
return h
|
||||
unsigned const &low () const:
|
||||
return l
|
||||
unsigned const &high () const:
|
||||
return h
|
||||
|
||||
struct Cap::IMessage:
|
||||
Num data[2]
|
||||
unsigned islot
|
||||
unsigned oslot
|
||||
unsigned num, first
|
||||
Cap *set
|
||||
struct Cap::OMessage:
|
||||
Num data[2]
|
||||
Num cap_protected
|
||||
Num recv_protected
|
||||
Cap Cap::copy () const:
|
||||
return Cap (code | CAP_COPY)
|
||||
Cap::Cap () : code (CAP_NONE):
|
||||
Cap::Cap (unsigned c) : code (c):
|
||||
Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)):
|
||||
unsigned Cap::slot () const:
|
||||
return (code >> 16) & 0x7fff
|
||||
unsigned Cap::idx () const:
|
||||
return code & 0xffff
|
||||
void Cap::invoke (IMessage const *i, OMessage *o):
|
||||
Cap *s = i->set
|
||||
__asm__ volatile ("lw $v0, %3\n"
|
||||
"\tlw $t0, 0($v0)\n"
|
||||
"\tlw $t1, 4($v0)\n"
|
||||
"\tlw $v0, %2\n"
|
||||
"\tlw $a0, 0($v0)\n"
|
||||
"\tlw $a1, 4($v0)\n"
|
||||
"\tlw $a2, 8($v0)\n"
|
||||
"\tlw $a3, 12($v0)\n"
|
||||
"\tlw $s0, 16($v0)\n"
|
||||
"\tlw $s1, 20($v0)\n"
|
||||
"\tlw $s2, 24($v0)\n"
|
||||
"\tlw $s3, 28($v0)\n"
|
||||
"\tlw $v0, %1\n"
|
||||
"\tsyscall\n"
|
||||
"\tlw $v0, %0\n"
|
||||
"\tsw $a0, 0($v0)\n"
|
||||
"\tsw $a1, 4($v0)\n"
|
||||
"\tsw $a2, 8($v0)\n"
|
||||
"\tsw $a3, 12($v0)\n"
|
||||
"\tsw $s0, 16($v0)\n"
|
||||
"\tsw $s1, 20($v0)\n"
|
||||
"\tsw $s2, 24($v0)\n"
|
||||
"\tsw $s3, 28($v0)"
|
||||
: "=m"(o)
|
||||
: "m"(code), "m"(i), "m"(s)
|
||||
: "memory", "v0", "s0", "s1", "s2", "s3", "a0", "a1", "a2", "a3", "t0", "t1")
|
||||
void Cap::call (IMessage *i, OMessage *o):
|
||||
i->set[0] = *this
|
||||
__my_call.copy ().invoke (i, o)
|
||||
void Cap::invoke (Num d0, Num d1):
|
||||
IMessage i
|
||||
OMessage o
|
||||
i.oslot = ~0
|
||||
i.islot = ~0
|
||||
Cap cs[2]
|
||||
i.set = cs
|
||||
i.num = 0
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
invoke (&i, &o)
|
||||
Num Cap::call (Num d0, Num d1, unsigned oslot, unsigned islot):
|
||||
IMessage i
|
||||
OMessage o
|
||||
Cap cs[2]
|
||||
i.set = cs
|
||||
i.oslot = oslot
|
||||
i.islot = islot
|
||||
i.num = 2
|
||||
i.first = 0
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
call (&i, &o)
|
||||
return o.data[0]
|
||||
Num Cap::icall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot):
|
||||
IMessage i
|
||||
OMessage o
|
||||
Cap cs[2]
|
||||
i.set = cs
|
||||
i.oslot = oslot
|
||||
i.islot = islot
|
||||
i.num = 2
|
||||
i.first = 0
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
call (&i, &o)
|
||||
Cap (oslot, 0).clone (c)
|
||||
return o.data[0]
|
||||
Num Cap::ocall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot):
|
||||
IMessage i
|
||||
OMessage o
|
||||
Cap cs[2]
|
||||
cs[1] = c
|
||||
i.set = cs
|
||||
i.oslot = oslot
|
||||
i.islot = islot
|
||||
i.num = 2
|
||||
i.first = 0
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
call (&i, &o)
|
||||
return o.data[0]
|
||||
Num Cap::iocall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot):
|
||||
IMessage i
|
||||
OMessage o
|
||||
Cap cs[2]
|
||||
cs[1] = c
|
||||
i.set = cs
|
||||
i.oslot = oslot
|
||||
i.islot = islot
|
||||
i.num = 2
|
||||
i.first = 0
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
call (&i, &o)
|
||||
Cap (oslot, 0).clone (c)
|
||||
return o.data[0]
|
||||
Cap Cap::clone (Cap target):
|
||||
IMessage i
|
||||
OMessage o
|
||||
Cap cs[2]
|
||||
cs[0] = this->copy ()
|
||||
i.set = cs
|
||||
i.oslot = target.slot ()
|
||||
i.first = target.idx ()
|
||||
i.num = 1
|
||||
i.islot = ~0
|
||||
i.data[0] = 0
|
||||
i.data[1] = 0
|
||||
Cap ().invoke (&i, &o)
|
||||
return target
|
||||
struct Cap
|
||||
struct Caps
|
||||
struct Receiver
|
||||
struct Thread
|
||||
struct Page
|
||||
struct Memory
|
||||
|
||||
struct Receiver : public Cap:
|
||||
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Receiver (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
// Operations
|
||||
SET_OWNER = 1
|
||||
CREATE_CAPABILITY
|
||||
CREATE_CALL_CAPABILITY
|
||||
CREATE_ASYNC_CALL_CAPABILITY
|
||||
GET_REPLY_PROTECTED_DATA
|
||||
SET_REPLY_PROTECTED_DATA
|
||||
GET_ALARM
|
||||
SET_ALARM
|
||||
ADD_ALARM
|
||||
// Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability.
|
||||
REPLY
|
||||
// A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY.
|
||||
CALL
|
||||
// A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY.
|
||||
CALL_ASYNC
|
||||
void set_owner (Cap owner):
|
||||
ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
|
||||
Cap create_capability (unsigned protected_data, Cap ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
|
||||
unsigned alloc_slot ()
|
||||
Cap alloc_cap ()
|
||||
void free_slot (unsigned slot)
|
||||
void free_cap (Cap cap)
|
||||
|
||||
struct Cap:
|
||||
unsigned code
|
||||
inline Cap copy () const
|
||||
inline Cap ()
|
||||
explicit inline Cap (unsigned c)
|
||||
inline Cap (unsigned slot, unsigned idx)
|
||||
inline unsigned slot () const
|
||||
inline unsigned idx () const
|
||||
struct IMessage
|
||||
inline void invoke (Num d0 = 0, Num d1 = 0, Cap arg = Cap (CAP_NONE))
|
||||
inline Num call (Num d0 = 0, Num d1 = 0)
|
||||
inline Num icall (Num d0 = 0, Num d1 = 0)
|
||||
inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0)
|
||||
inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0)
|
||||
inline void _invoke (IMessage const *i)
|
||||
inline void _call (IMessage *i)
|
||||
|
||||
struct __recv_data_t:
|
||||
Num data[2]
|
||||
Num protected_data
|
||||
Cap reply, arg
|
||||
|
||||
extern Receiver my_receiver
|
||||
extern Thread my_thread
|
||||
extern Memory my_memory
|
||||
extern Cap my_call
|
||||
extern Cap my_parent
|
||||
extern __recv_data_t recv
|
||||
|
||||
inline Cap get_reply ():
|
||||
Cap ret = recv.reply
|
||||
recv.reply = alloc_cap ()
|
||||
return ret
|
||||
Num get_reply_protected_data ():
|
||||
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
|
||||
void set_reply_protected_data (Num data):
|
||||
call (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data)
|
||||
unsigned get_alarm ():
|
||||
return call (CAP_MASTER_DIRECT | GET_ALARM).l
|
||||
unsigned add_alarm (unsigned data):
|
||||
return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
|
||||
void set_alarm (unsigned data):
|
||||
call (CAP_MASTER_DIRECT | SET_ALARM, data)
|
||||
static inline void sleep (unsigned value, OMessage *ret, unsigned slot = __tmp_slot)
|
||||
Cap create_call_capability (Cap ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
|
||||
return ret
|
||||
Cap create_async_call_capability (Cap ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
|
||||
inline Cap get_arg ():
|
||||
Cap ret = recv.arg
|
||||
recv.arg = alloc_cap ()
|
||||
return ret
|
||||
inline void set_recv_arg (Cap c):
|
||||
free_cap (recv.arg)
|
||||
recv.arg = c
|
||||
|
||||
struct Thread : public Cap:
|
||||
Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Thread (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
// Info details are arch-specific.
|
||||
GET_INFO = 1
|
||||
SET_INFO
|
||||
USE_SLOT
|
||||
SCHEDULE
|
||||
PRIV_ALLOC_RANGE
|
||||
PRIV_PHYSICAL_ADDRESS
|
||||
PRIV_ALLOC_PHYSICAL
|
||||
PRIV_MAKE_PRIV
|
||||
PRIV_GET_TOP_MEMORY
|
||||
PRIV_REGISTER_INTERRUPT
|
||||
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
|
||||
SET_OWNER
|
||||
// These get/set_info are not arch-specific.
|
||||
enum info_type:
|
||||
PC = ~0
|
||||
SP = ~1
|
||||
FLAGS = ~2
|
||||
enum flags:
|
||||
PRIV = 1 << 31
|
||||
WAITING = 1 << 30
|
||||
RUNNING = 1 << 29
|
||||
USER_FLAGS = ~(PRIV | WAITING | RUNNING)
|
||||
void make_priv ():
|
||||
__my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV)
|
||||
unsigned get_info (unsigned info):
|
||||
return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l
|
||||
void set_info (unsigned info, unsigned value, unsigned mask = ~0):
|
||||
call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask))
|
||||
void set_pc (unsigned pc):
|
||||
set_info (PC, pc)
|
||||
void set_sp (unsigned sp):
|
||||
set_info (SP, sp)
|
||||
void set_flags (unsigned value, unsigned mask):
|
||||
set_info (FLAGS, value, mask)
|
||||
unsigned get_pc ():
|
||||
return get_info (PC)
|
||||
unsigned get_sp ():
|
||||
return get_info (SP)
|
||||
unsigned get_flags ():
|
||||
return get_info (FLAGS)
|
||||
void run (bool run):
|
||||
set_flags (run ? RUNNING : 0, RUNNING)
|
||||
void wait (bool wait):
|
||||
set_flags (wait ? WAITING : 0, WAITING)
|
||||
inline unsigned use (Caps caps, unsigned slot = alloc_slot ())
|
||||
struct Cap::IMessage:
|
||||
Num data[2]
|
||||
Cap reply, arg
|
||||
Cap Cap::copy () const:
|
||||
return Cap (code | CAP_COPY)
|
||||
Cap::Cap () : code (CAP_NONE):
|
||||
Cap::Cap (unsigned c) : code (c):
|
||||
Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)):
|
||||
unsigned Cap::slot () const:
|
||||
return (code >> 16) & 0x7fff
|
||||
unsigned Cap::idx () const:
|
||||
return code & 0xffff
|
||||
void Cap::_invoke (IMessage const *i):
|
||||
__recv_data_t *r = &recv
|
||||
__asm__ volatile ("lw $v0, %1\n"
|
||||
"\tlw $a0, 0($v0)\n"
|
||||
"\tlw $a1, 4($v0)\n"
|
||||
"\tlw $a2, 8($v0)\n"
|
||||
"\tlw $a3, 12($v0)\n"
|
||||
"\tlw $t0, 16($v0)\n"
|
||||
"\tlw $t1, 20($v0)\n"
|
||||
"\tlw $v0, %2\n"
|
||||
"\tlw $t2, 24($v0)\n"
|
||||
"\tlw $t3, 28($v0)\n"
|
||||
"\tlw $v0, %0\n"
|
||||
"\tsyscall\n"
|
||||
"\tlw $v0, %2\n"
|
||||
"\tsw $a0, 0($v0)\n"
|
||||
"\tsw $a1, 4($v0)\n"
|
||||
"\tsw $a2, 8($v0)\n"
|
||||
"\tsw $a3, 12($v0)\n"
|
||||
"\tsw $t0, 16($v0)\n"
|
||||
"\tsw $t1, 20($v0)"
|
||||
:: "m"(code), "m"(i), "m"(r)
|
||||
: "memory", "v0", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3")
|
||||
void Cap::_call (IMessage *i):
|
||||
i->reply = *this
|
||||
my_call.copy ()._invoke (i)
|
||||
void Cap::invoke (Num d0, Num d1, Cap arg):
|
||||
IMessage i
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
i.reply = Cap (CAP_NONE)
|
||||
i.arg = arg
|
||||
_invoke (&i)
|
||||
Num Cap::call (Num d0, Num d1):
|
||||
IMessage i
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
_call (&i)
|
||||
return recv.data[0]
|
||||
Num Cap::icall (Num d0, Num d1):
|
||||
IMessage i
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
_call (&i)
|
||||
return recv.data[0]
|
||||
Num Cap::ocall (Cap c, Num d0, Num d1):
|
||||
IMessage i
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
i.arg = c
|
||||
_call (&i)
|
||||
return recv.data[0]
|
||||
Num Cap::iocall (Cap c, Num d0, Num d1):
|
||||
IMessage i
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
i.arg = c
|
||||
_call (&i)
|
||||
return recv.data[0]
|
||||
|
||||
struct Caps : public Cap:
|
||||
Caps (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Caps (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
// Not an operation; this capability can be used in Thread::USE_SLOT.
|
||||
USE = 1
|
||||
PRINT
|
||||
unsigned use (unsigned slot = alloc_slot ()):
|
||||
return __my_thread.use (*this, slot)
|
||||
void print (unsigned idx):
|
||||
invoke (CAP_MASTER_DIRECT | PRINT, idx)
|
||||
struct Receiver : public Cap:
|
||||
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Receiver (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
// Operations
|
||||
SET_OWNER = 1
|
||||
CREATE_CAPABILITY
|
||||
CREATE_CALL_CAPABILITY
|
||||
CREATE_ASYNC_CALL_CAPABILITY
|
||||
GET_REPLY_PROTECTED_DATA
|
||||
SET_REPLY_PROTECTED_DATA
|
||||
GET_ALARM
|
||||
SET_ALARM
|
||||
ADD_ALARM
|
||||
// Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability.
|
||||
REPLY
|
||||
// A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY.
|
||||
CALL
|
||||
// A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY.
|
||||
CALL_ASYNC
|
||||
void set_owner (Cap owner):
|
||||
ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
|
||||
Cap create_capability (Num protected_data):
|
||||
icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
|
||||
return get_arg ()
|
||||
Num get_reply_protected_data ():
|
||||
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
|
||||
void set_reply_protected_data (Num data):
|
||||
call (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data)
|
||||
unsigned get_alarm ():
|
||||
return call (CAP_MASTER_DIRECT | GET_ALARM).l
|
||||
unsigned add_alarm (unsigned data):
|
||||
return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
|
||||
void set_alarm (unsigned data):
|
||||
call (CAP_MASTER_DIRECT | SET_ALARM, data)
|
||||
static inline void sleep (unsigned value)
|
||||
Cap create_call_capability ():
|
||||
icall (CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
|
||||
return get_arg ()
|
||||
Cap create_async_call_capability ():
|
||||
icall (CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
|
||||
return get_arg ()
|
||||
|
||||
unsigned Thread::use (Caps caps, unsigned slot):
|
||||
ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot)
|
||||
return slot
|
||||
struct Thread : public Cap:
|
||||
Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Thread (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
// Info details are arch-specific.
|
||||
GET_INFO = 1
|
||||
SET_INFO
|
||||
USE_SLOT
|
||||
SCHEDULE
|
||||
PRIV_ALLOC_RANGE
|
||||
PRIV_PHYSICAL_ADDRESS
|
||||
PRIV_ALLOC_PHYSICAL
|
||||
PRIV_MAKE_PRIV
|
||||
PRIV_GET_TOP_MEMORY
|
||||
PRIV_REGISTER_INTERRUPT
|
||||
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
|
||||
SET_OWNER
|
||||
DBG_SEND
|
||||
PRIV_PANIC
|
||||
// These get/set_info are not arch-specific.
|
||||
enum info_type:
|
||||
PC = ~0
|
||||
SP = ~1
|
||||
FLAGS = ~2
|
||||
enum flags:
|
||||
PRIV = 1 << 31
|
||||
WAITING = 1 << 30
|
||||
RUNNING = 1 << 29
|
||||
USER_FLAGS = ~(PRIV | WAITING | RUNNING)
|
||||
void make_priv ():
|
||||
my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV)
|
||||
unsigned get_info (unsigned info):
|
||||
return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l
|
||||
void set_info (unsigned info, unsigned value, unsigned mask = ~0):
|
||||
call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask))
|
||||
void set_pc (unsigned pc):
|
||||
set_info (PC, pc)
|
||||
void set_sp (unsigned sp):
|
||||
set_info (SP, sp)
|
||||
void set_flags (unsigned value, unsigned mask):
|
||||
set_info (FLAGS, value, mask)
|
||||
unsigned get_pc ():
|
||||
return get_info (PC)
|
||||
unsigned get_sp ():
|
||||
return get_info (SP)
|
||||
unsigned get_flags ():
|
||||
return get_info (FLAGS)
|
||||
void run (bool run):
|
||||
set_flags (run ? RUNNING : 0, RUNNING)
|
||||
void wait (bool wait):
|
||||
set_flags (wait ? WAITING : 0, WAITING)
|
||||
inline unsigned use (Caps caps, unsigned slot = alloc_slot ())
|
||||
|
||||
struct Page : public Cap:
|
||||
Page (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Page (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
SHARE = 1
|
||||
GET_FLAGS
|
||||
SET_FLAGS
|
||||
// Not an operation; a capability with this bit cannot write to the page.
|
||||
READONLY = 8
|
||||
enum share_detail:
|
||||
// Operation details for PAGE_SHARE
|
||||
// Forget the source page during the operation. This makes it a move.
|
||||
FORGET
|
||||
// Make the target independent of the source (make a copy if needed).
|
||||
COPY
|
||||
// Make the target unwritable.
|
||||
//READONLY: use the value from request.
|
||||
enum flag_values:
|
||||
// This is a read-only flag, which is set if the Page is shared.
|
||||
SHARED = 1
|
||||
// When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them.
|
||||
PAYING = 2
|
||||
// Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems.
|
||||
FRAME = 4
|
||||
// A readonly page cannot be written to. This flag can not be reset while the frame is shared. The flag is already defined in request.
|
||||
//READONLY = 8
|
||||
// This is a read-only flag, saying if this is physical memory, which mustn't be freed.
|
||||
PHYSICAL = 0x10
|
||||
// This is a read-only flag, saying if this is uncachable memory.
|
||||
UNCACHED = 0x20
|
||||
void share (Cap target, unsigned flags):
|
||||
ocall (target, CAP_MASTER_DIRECT | SHARE, flags)
|
||||
unsigned get_flags ():
|
||||
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
|
||||
void set_flags (unsigned new_flags, unsigned mask):
|
||||
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
|
||||
unsigned physical_address ():
|
||||
return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
|
||||
void alloc_physical (unsigned address, bool cachable, bool freeable):
|
||||
__my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
|
||||
struct Caps : public Cap:
|
||||
Caps (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Caps (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
// Not an operation; this capability can be used in Thread::USE_SLOT.
|
||||
USE = 1
|
||||
SET
|
||||
PRINT
|
||||
unsigned use (unsigned slot = alloc_slot ()):
|
||||
return my_thread.use (*this, slot)
|
||||
void set (unsigned idx, Cap cap):
|
||||
ocall (cap, CAP_MASTER_DIRECT | SET, idx)
|
||||
void print (unsigned idx):
|
||||
invoke (CAP_MASTER_DIRECT | PRINT, idx)
|
||||
|
||||
struct Memory : public Cap:
|
||||
Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Memory (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
CREATE = 1
|
||||
DESTROY
|
||||
LIST
|
||||
MAP
|
||||
MAPPING
|
||||
GET_LIMIT
|
||||
SET_LIMIT
|
||||
Page create_page (Page ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
|
||||
return ret
|
||||
Thread create_thread (unsigned slots, Thread ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
|
||||
return ret
|
||||
Receiver create_receiver (Receiver ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
|
||||
return ret
|
||||
Memory create_memory (Memory ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
|
||||
return ret
|
||||
Caps create_caps (unsigned size, Caps ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
|
||||
return ret
|
||||
void destroy (Cap target):
|
||||
ocall (target, CAP_MASTER_DIRECT | DESTROY)
|
||||
// TODO: LIST
|
||||
void map (Cap page, unsigned address, bool readonly = false):
|
||||
if readonly:
|
||||
address |= Page::READONLY
|
||||
ocall (page, CAP_MASTER_DIRECT | MAP, address)
|
||||
Page mapping (void *address, Page ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
|
||||
return ret
|
||||
unsigned get_limit (unsigned limit):
|
||||
return call (CAP_MASTER_DIRECT | GET_LIMIT).l
|
||||
void set_limit (unsigned limit):
|
||||
call (CAP_MASTER_DIRECT | SET_LIMIT, limit)
|
||||
unsigned alloc_range (unsigned pages):
|
||||
return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l
|
||||
unsigned Thread::use (Caps caps, unsigned slot):
|
||||
ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot)
|
||||
return slot
|
||||
|
||||
struct Kernel:
|
||||
static void wait (Cap::OMessage *o, unsigned islot = ~0):
|
||||
struct Page : public Cap:
|
||||
Page (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Page (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
SHARE = 1
|
||||
GET_FLAGS
|
||||
SET_FLAGS
|
||||
// Not an operation; a capability with this bit cannot write to the page.
|
||||
READONLY = 8
|
||||
enum share_detail:
|
||||
// Operation details for PAGE_SHARE
|
||||
// Forget the source page during the operation. This makes it a move.
|
||||
FORGET
|
||||
// Make the target independent of the source (make a copy if needed).
|
||||
COPY
|
||||
// Make the target unwritable.
|
||||
//READONLY: use the value from request.
|
||||
enum flag_values:
|
||||
// This is a read-only flag, which is set if the Page is shared.
|
||||
SHARED = 1
|
||||
// When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them.
|
||||
PAYING = 2
|
||||
// Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems.
|
||||
FRAME = 4
|
||||
// A readonly page cannot be written to. This flag can not be reset while the frame is shared. The flag is already defined in request.
|
||||
//READONLY = 8
|
||||
// This is a read-only flag, saying if this is physical memory, which mustn't be freed.
|
||||
PHYSICAL = 0x10
|
||||
// This is a read-only flag, saying if this is uncachable memory.
|
||||
UNCACHED = 0x20
|
||||
void share (Cap target, unsigned flags):
|
||||
ocall (target, CAP_MASTER_DIRECT | SHARE, flags)
|
||||
unsigned get_flags ():
|
||||
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
|
||||
void set_flags (unsigned new_flags, unsigned mask):
|
||||
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
|
||||
unsigned physical_address ():
|
||||
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
|
||||
void alloc_physical (unsigned address, bool cachable, bool freeable):
|
||||
my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
|
||||
|
||||
struct Memory : public Cap:
|
||||
Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
Memory (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
CREATE = 1
|
||||
DESTROY
|
||||
LIST
|
||||
MAP
|
||||
MAPPING
|
||||
GET_LIMIT
|
||||
SET_LIMIT
|
||||
Page create_page ():
|
||||
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
|
||||
return get_arg ()
|
||||
Thread create_thread (unsigned slots):
|
||||
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
|
||||
return get_arg ()
|
||||
Receiver create_receiver ():
|
||||
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
|
||||
return get_arg ()
|
||||
Memory create_memory ():
|
||||
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
|
||||
return get_arg ()
|
||||
Caps create_caps (unsigned size):
|
||||
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
|
||||
return get_arg ()
|
||||
void destroy (Cap target):
|
||||
ocall (target, CAP_MASTER_DIRECT | DESTROY)
|
||||
// TODO: LIST
|
||||
void map (Cap page, unsigned address, bool readonly = false):
|
||||
if readonly:
|
||||
address |= Page::READONLY
|
||||
ocall (page, CAP_MASTER_DIRECT | MAP, address)
|
||||
Page mapping (void *address):
|
||||
icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
|
||||
return get_arg ()
|
||||
unsigned get_limit (unsigned limit):
|
||||
return call (CAP_MASTER_DIRECT | GET_LIMIT).l
|
||||
void set_limit (unsigned limit):
|
||||
call (CAP_MASTER_DIRECT | SET_LIMIT, limit)
|
||||
unsigned alloc_range (unsigned pages):
|
||||
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l
|
||||
|
||||
inline void wait ():
|
||||
Cap::IMessage i
|
||||
i.islot = islot
|
||||
i.num = 0
|
||||
i.first = 0
|
||||
i.oslot = ~0
|
||||
Cap cs[2]
|
||||
i.set = cs
|
||||
Cap ().copy ().invoke (&i, o)
|
||||
static void schedule ():
|
||||
__my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE)
|
||||
static void register_interrupt (unsigned num):
|
||||
__my_thread.ocall (__my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
|
||||
static void unregister_interrupt (unsigned num):
|
||||
__my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
|
||||
static Cap get_top_memory (Cap ret = Cap (0, alloc_cap ())):
|
||||
__my_thread.icall (ret, CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
|
||||
return ret
|
||||
Cap ().copy ()._invoke (&i)
|
||||
inline void schedule ():
|
||||
my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE)
|
||||
inline void register_interrupt (unsigned num):
|
||||
my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
|
||||
inline void unregister_interrupt (unsigned num):
|
||||
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
|
||||
inline Cap get_top_memory ():
|
||||
my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
|
||||
return get_arg ()
|
||||
inline void dbg_send (unsigned code, unsigned bits = 32):
|
||||
my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits))
|
||||
inline void panic (unsigned code):
|
||||
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code)
|
||||
|
||||
void Receiver::sleep (unsigned value, OMessage *ret, unsigned slot):
|
||||
__my_receiver.set_alarm (value)
|
||||
Kernel::wait (ret, slot)
|
||||
void Receiver::sleep (unsigned value):
|
||||
my_receiver.set_alarm (value)
|
||||
wait ()
|
||||
|
||||
// The start function has this prototype (there is no main function).
|
||||
Kernel::Num start ()
|
||||
|
||||
#if 1
|
||||
// Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing.
|
||||
|
43
kernel.hhp
43
kernel.hhp
@ -60,7 +60,7 @@ struct kCapRef:
|
||||
kCapRef (kCapsP c, unsigned i) : caps (c), index (i):
|
||||
kCapRef () : caps (NULL), index (~0):
|
||||
inline void clone (kCapRef source, bool copy)
|
||||
inline void set (kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
inline void set (kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
|
||||
struct kObject:
|
||||
kCapRef refs
|
||||
@ -80,20 +80,17 @@ bool kObject::is_free ():
|
||||
// Include architecture-specific parts.
|
||||
#include "arch.hh"
|
||||
|
||||
struct kMessage : public kObject:
|
||||
Num cap_protected
|
||||
Num data[2]
|
||||
kCapsP caps
|
||||
|
||||
struct kCapability : public kObject:
|
||||
struct Context:
|
||||
Num data[2]
|
||||
kCaps *caps
|
||||
Kernel::Num data[2]
|
||||
kCapRef reply
|
||||
kCapRef arg
|
||||
bool copy[2]
|
||||
kReceiverP target
|
||||
kCapRef parent
|
||||
kCapRef children
|
||||
kCapRef sibling_prev, sibling_next
|
||||
Num cap_protected
|
||||
Kernel::Num protected_data
|
||||
inline void invoke (kCapability::Context *c)
|
||||
void invalidate ()
|
||||
|
||||
@ -103,7 +100,7 @@ struct kThread : public kObject:
|
||||
kThread_arch arch
|
||||
unsigned flags
|
||||
kThreadP schedule_prev, schedule_next
|
||||
unsigned recv_slot
|
||||
unsigned recv_reply, recv_arg
|
||||
// caps is an array of slots pointers to kCapses.
|
||||
unsigned slots
|
||||
// TODO: handle freeing of capses which are in use.
|
||||
@ -114,9 +111,8 @@ struct kThread : public kObject:
|
||||
void wait ()
|
||||
void unwait ()
|
||||
bool is_waiting ():
|
||||
return flags & Thread::WAITING
|
||||
return flags & Kernel::Thread::WAITING
|
||||
kCapRef find_capability (unsigned code, bool *copy)
|
||||
void fill_slot (unsigned slot, kCaps *new_caps)
|
||||
|
||||
struct kReceiver : public kObject:
|
||||
kThreadP owner
|
||||
@ -131,15 +127,14 @@ struct kReceiver : public kObject:
|
||||
// The message queue. kMessages are added at the tail, and removed at the front.
|
||||
kMessageP messages
|
||||
kMessageP last_message
|
||||
Num recv_protected
|
||||
Num reply_protected_data
|
||||
Kernel::Num reply_protected_data
|
||||
bool protected_only
|
||||
// This limit is for messages stored in its address space. There is unlimited space if senders provide it.
|
||||
unsigned queue_limit
|
||||
void own (kThreadP o)
|
||||
void orphan ()
|
||||
bool try_deliver ()
|
||||
bool send_message (Num cap_protected, kCapability::Context *c)
|
||||
bool send_message (Kernel::Num protected_data, kCapability::Context *c)
|
||||
|
||||
struct kPage : public kObject:
|
||||
unsigned frame
|
||||
@ -154,9 +149,15 @@ struct kCaps : public kObject:
|
||||
kCapability caps[1]
|
||||
kCapability *cap (unsigned idx):
|
||||
return &caps[idx]
|
||||
void set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
void set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
void clone (unsigned index, kCapRef source, bool copy)
|
||||
|
||||
struct kMessage : public kObject:
|
||||
Kernel::Num protected_data
|
||||
Kernel::Num data[2]
|
||||
// This is a real Caps of two elements, not a link.
|
||||
kCaps caps
|
||||
|
||||
struct kMemory : public kObject:
|
||||
kFree *frees
|
||||
kPageP pages
|
||||
@ -203,7 +204,7 @@ extern "C":
|
||||
#define panic(n, m) panic_impl ((n), __LINE__, __PRETTY_FUNCTION__, (m))
|
||||
void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "")
|
||||
#ifndef NDEBUG
|
||||
EXTERN Num dbg_code
|
||||
EXTERN Kernel::Num dbg_code
|
||||
EXTERN kCapRef dbg_cap
|
||||
void dbg_log_char (unsigned ch)
|
||||
void dbg_log (char const *str)
|
||||
@ -241,11 +242,11 @@ unsigned phys_alloc (unsigned num)
|
||||
void phys_free (unsigned page, unsigned num)
|
||||
|
||||
// Defind in invoke.ccp
|
||||
void invoke (kReceiverP target, Num cap_protected, kCapability::Context *c, kCapability *self)
|
||||
void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context *c)
|
||||
|
||||
// Defined by architecture-specific files.
|
||||
void kThread_arch_init (kThread *thread)
|
||||
void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data)
|
||||
void kThread_arch_receive (kThread *thread, Kernel::Num protected_data, Kernel::Num *data)
|
||||
unsigned *kThread_arch_info (kThread *thread, unsigned num)
|
||||
void kMemory_arch_init (kMemory *mem)
|
||||
void kMemory_arch_free (kMemory *mem)
|
||||
@ -265,10 +266,10 @@ kCapability *kCapRef::deref ():
|
||||
return caps ? caps->cap (index) : NULL
|
||||
void kCapRef::clone (kCapRef source, bool copy):
|
||||
caps->clone (index, source, copy)
|
||||
void kCapRef::set (kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
void kCapRef::set (kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
caps->set (index, target, pdata, parent, parent_ptr)
|
||||
void kCapability::invoke (kCapability::Context *c):
|
||||
::invoke (target, cap_protected, c, this)
|
||||
::invoke (target, protected_data, c)
|
||||
|
||||
#define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0)
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -31,7 +31,7 @@ static void handle_exit ():
|
||||
schedule ()
|
||||
if !current:
|
||||
current = &idle
|
||||
if (current->flags & (Thread::RUNNING | Thread::WAITING)) != Thread::RUNNING:
|
||||
if (current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) != Kernel::Thread::RUNNING:
|
||||
panic (current->flags, "non-scheduled thread running")
|
||||
if !current:
|
||||
current = &idle
|
||||
@ -55,7 +55,7 @@ static void handle_exit ():
|
||||
asids[current->address_space->arch.asid] = (unsigned)current->address_space
|
||||
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
|
||||
directory = current->address_space->arch.directory
|
||||
if current->flags & Thread::PRIV:
|
||||
if current->flags & Kernel::Thread::PRIV:
|
||||
cp0_set (CP0_STATUS, 0x1000ff13)
|
||||
else:
|
||||
cp0_set (CP0_STATUS, 0x0000ff13)
|
||||
@ -68,7 +68,7 @@ kThread *tlb_refill ():
|
||||
if !directory:
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (ERR_NO_PAGE_DIRECTORY, addr)
|
||||
current->raise (Kernel::ERR_NO_PAGE_DIRECTORY, addr)
|
||||
handle_exit ()
|
||||
return current
|
||||
unsigned EntryHi
|
||||
@ -77,7 +77,7 @@ kThread *tlb_refill ():
|
||||
if !t:
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (ERR_NO_PAGE_TABLE, addr)
|
||||
current->raise (Kernel::ERR_NO_PAGE_TABLE, addr)
|
||||
else:
|
||||
// - 2 instead of - 1 means reset bit 0
|
||||
unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2)
|
||||
@ -104,7 +104,6 @@ kThread *interrupt ():
|
||||
kCapability::Context c
|
||||
for unsigned j = 0; j < 2; ++j:
|
||||
c.data[j] = 0
|
||||
c.caps = NULL
|
||||
arch_interrupt_receiver[i]->send_message (i, &c)
|
||||
arch_interrupt_receiver[i] = NULL
|
||||
if ipr & (1 << IRQ_OST0):
|
||||
@ -130,40 +129,23 @@ static void arch_invoke ():
|
||||
target = old_current->find_capability (old_current->arch.v[0], &must_wait)
|
||||
do_schedule = false
|
||||
kCapability::Context msg
|
||||
unsigned num = old_current->arch.s[2]
|
||||
unsigned first = old_current->arch.s[3]
|
||||
if num > 2:
|
||||
dpanic (0x23451234, "too many capabilities")
|
||||
num = 2
|
||||
if old_current->arch.s[1] < old_current->slots:
|
||||
msg.caps = old_current->caps[old_current->arch.s[1]]
|
||||
if msg.caps:
|
||||
for unsigned i = 0; i < num && first + i < msg.caps->size; ++i:
|
||||
unsigned code = old_current->arch.t[i]
|
||||
msg.caps->cap (first + i)->invalidate ()
|
||||
bool copy
|
||||
kCapRef t = old_current->find_capability (code, ©)
|
||||
if t.valid ():
|
||||
msg.caps->clone (first + i, t, copy)
|
||||
else:
|
||||
if num:
|
||||
dpanic (0x34566244, "num without caps")
|
||||
if old_current->arch.s[1] != ~0:
|
||||
dpanic (0x28849932, "non-~0 slot too high")
|
||||
msg.caps = NULL
|
||||
msg.reply = old_current->find_capability (old_current->arch.t[0], &msg.copy[0])
|
||||
msg.arg = old_current->find_capability (old_current->arch.t[1], &msg.copy[1])
|
||||
if must_wait:
|
||||
old_current->recv_slot = old_current->arch.s[0]
|
||||
bool dummy
|
||||
old_current->recv_reply = old_current->arch.t[2]
|
||||
old_current->recv_arg = old_current->arch.t[3]
|
||||
if !target.valid ():
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
return
|
||||
msg.data[0] = Num (old_current->arch.a[0], old_current->arch.a[1])
|
||||
msg.data[1] = Num (old_current->arch.a[2], old_current->arch.a[3])
|
||||
msg.data[0] = Kernel::Num (old_current->arch.a[0], old_current->arch.a[1])
|
||||
msg.data[1] = Kernel::Num (old_current->arch.a[2], old_current->arch.a[3])
|
||||
target->invoke (&msg)
|
||||
if do_schedule && !must_wait:
|
||||
// If the call was to schedule without wait, it isn't done yet.
|
||||
schedule ()
|
||||
else if old_current != current && (old_current->flags & (Thread::RUNNING | Thread::WAITING)) == Thread::RUNNING:
|
||||
else if old_current != current && (old_current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) == Kernel::Thread::RUNNING:
|
||||
// If the caller received an immediate reply from the kernel, it is no longer set as current. Don't let it lose its timeslice.
|
||||
current = old_current
|
||||
|
||||
@ -181,31 +163,31 @@ kThread *exception ():
|
||||
// TLB modification.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (ERR_WRITE_DENIED, addr)
|
||||
current->raise (Kernel::ERR_WRITE_DENIED, addr)
|
||||
break
|
||||
case 2:
|
||||
// TLB load or instruction fetch.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (ERR_UNMAPPED_READ, addr)
|
||||
current->raise (Kernel::ERR_UNMAPPED_READ, addr)
|
||||
break
|
||||
case 3:
|
||||
// TLB store.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (ERR_UNMAPPED_WRITE, addr)
|
||||
current->raise (Kernel::ERR_UNMAPPED_WRITE, addr)
|
||||
break
|
||||
case 4:
|
||||
// Address error load or instruction fetch.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (ERR_INVALID_ADDRESS_READ, addr)
|
||||
current->raise (Kernel::ERR_INVALID_ADDRESS_READ, addr)
|
||||
break
|
||||
case 5:
|
||||
// Address error store.
|
||||
unsigned addr
|
||||
cp0_get (CP0_BAD_V_ADDR, addr)
|
||||
current->raise (ERR_INVALID_ADDRESS_WRITE, addr)
|
||||
current->raise (Kernel::ERR_INVALID_ADDRESS_WRITE, addr)
|
||||
break
|
||||
case 6:
|
||||
// Bus error instruction fetch.
|
||||
@ -224,7 +206,7 @@ kThread *exception ():
|
||||
case 9:
|
||||
// Breakpoint.
|
||||
#if 0 || defined (NDEBUG)
|
||||
//current->raise (ERR_BREAKPOINT, 0)
|
||||
//current->raise (Kernel::ERR_BREAKPOINT, 0)
|
||||
#ifndef NDEBUG
|
||||
current->pc += 4
|
||||
#endif
|
||||
@ -250,19 +232,19 @@ kThread *exception ():
|
||||
break
|
||||
case 10:
|
||||
// Reserved instruction.
|
||||
current->raise (ERR_RESERVED_INSTRUCTION, 0)
|
||||
current->raise (Kernel::ERR_RESERVED_INSTRUCTION, 0)
|
||||
break
|
||||
case 11:
|
||||
// Coprocessor unusable.
|
||||
current->raise (ERR_COPROCESSOR_UNUSABLE, 0)
|
||||
current->raise (Kernel::ERR_COPROCESSOR_UNUSABLE, 0)
|
||||
break
|
||||
case 12:
|
||||
// Arithmetic overflow.
|
||||
current->raise (ERR_OVERFLOW, 0)
|
||||
current->raise (Kernel::ERR_OVERFLOW, 0)
|
||||
break
|
||||
case 13:
|
||||
// Trap.
|
||||
current->raise (ERR_TRAP, 0)
|
||||
current->raise (Kernel::ERR_TRAP, 0)
|
||||
break
|
||||
case 15:
|
||||
// Floating point exception.
|
||||
@ -270,7 +252,7 @@ kThread *exception ():
|
||||
break
|
||||
case 23:
|
||||
// Reference to WatchHi/WatchLo address.
|
||||
current->raise (ERR_WATCHPOINT, 0)
|
||||
current->raise (Kernel::ERR_WATCHPOINT, 0)
|
||||
break
|
||||
case 24:
|
||||
// Machine check.
|
||||
|
@ -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
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -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:
|
||||
|
17
schedule.ccp
17
schedule.ccp
@ -36,31 +36,30 @@ static void unrun_thread (kThread *thread):
|
||||
thread->schedule_next->schedule_prev = thread->schedule_prev
|
||||
|
||||
void kThread::run ():
|
||||
if flags & Thread::RUNNING:
|
||||
if flags & Kernel::Thread::RUNNING:
|
||||
return
|
||||
flags |= Thread::RUNNING
|
||||
flags |= Kernel::Thread::RUNNING
|
||||
if is_waiting ():
|
||||
return
|
||||
run_thread (this)
|
||||
|
||||
void kThread::unrun ():
|
||||
if !(flags & Thread::RUNNING):
|
||||
if !(flags & Kernel::Thread::RUNNING):
|
||||
return
|
||||
flags &= ~Thread::RUNNING
|
||||
flags &= ~Kernel::Thread::RUNNING
|
||||
if is_waiting ():
|
||||
return
|
||||
unrun_thread (this)
|
||||
|
||||
void kThread::unwait ():
|
||||
flags &= ~Thread::WAITING
|
||||
if flags & Thread::RUNNING:
|
||||
flags &= ~Kernel::Thread::WAITING
|
||||
if flags & Kernel::Thread::RUNNING:
|
||||
run_thread (this)
|
||||
|
||||
static void alarm_tick (kReceiver *recv):
|
||||
if !recv->alarm_count:
|
||||
// Send message and stop counting.
|
||||
kCapability::Context c
|
||||
c.caps = NULL
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
c.data[i] = 0
|
||||
recv->send_message (~0, &c)
|
||||
@ -74,9 +73,9 @@ static void alarm_tick (kReceiver *recv):
|
||||
--recv->alarm_count
|
||||
|
||||
void kThread::wait ():
|
||||
if flags & Thread::RUNNING:
|
||||
if flags & Kernel::Thread::RUNNING:
|
||||
unrun_thread (this)
|
||||
flags |= Thread::WAITING
|
||||
flags |= Kernel::Thread::WAITING
|
||||
// Try to receive a message from a kReceiver immediately.
|
||||
for kReceiver *r = receivers; r; r = r->next_owned:
|
||||
if r->try_deliver ():
|
||||
|
Loading…
Reference in New Issue
Block a user