mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-01-30 18:51:05 +02:00
new stuff almost working
This commit is contained in:
parent
ebdc68a9d8
commit
418f6c6594
2
Makefile
2
Makefile
@ -16,7 +16,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Define some variables.
|
||||
CXXFLAGS = -Wno-unused-parameter -fno-strict-aliasing -fno-builtin -nostdinc $(ARCH_CXXFLAGS)
|
||||
CXXFLAGS = -Wno-unused-parameter -fno-strict-aliasing -fno-builtin -nostdinc $(ARCH_CXXFLAGS) -ggdb3
|
||||
CPPFLAGS = -O5 -fno-inline $(ARCH_CPPFLAGS)
|
||||
CC = $(CROSS)gcc
|
||||
LD = $(CROSS)ld
|
||||
|
18
alloc.ccp
18
alloc.ccp
@ -120,7 +120,7 @@ void *kMemory::search_free (unsigned size, void **first):
|
||||
void kMemory::free_obj (kObject *obj, kPointer *first):
|
||||
kFree *self = (kFree *)obj
|
||||
// Invalidate references.
|
||||
while self->refs:
|
||||
while self->refs.valid ():
|
||||
self->refs->invalidate ()
|
||||
// Free it from its list.
|
||||
if self->prev:
|
||||
@ -216,7 +216,7 @@ kReceiver *kMemory::alloc_receiver ():
|
||||
ret->last_message = NULL
|
||||
ret->reply_protected_data = ~0
|
||||
ret->protected_only = false
|
||||
ret->queue_limit = 0
|
||||
ret->queue_limit = ~0
|
||||
return ret
|
||||
|
||||
kCaps *kMemory::alloc_caps (unsigned size):
|
||||
@ -249,7 +249,7 @@ void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, k
|
||||
caps[index].parent = parent
|
||||
caps[index].children.reset ()
|
||||
caps[index].sibling_prev.reset ()
|
||||
if parent:
|
||||
if parent.valid ():
|
||||
caps[index].sibling_next = parent->children
|
||||
parent->children = kCapRef (this, index)
|
||||
else:
|
||||
@ -258,12 +258,12 @@ void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, k
|
||||
*parent_ptr = kCapRef (this, index)
|
||||
else:
|
||||
caps[index].sibling_next.reset ()
|
||||
if caps[index].sibling_next:
|
||||
if caps[index].sibling_next.valid ():
|
||||
caps[index].sibling_next->sibling_prev = kCapRef (this, index)
|
||||
|
||||
void kCaps::clone (unsigned index, kCapRef source, bool copy):
|
||||
if copy:
|
||||
if source->parent:
|
||||
if source->parent.valid ():
|
||||
set (index, source->target, source->cap_protected, source->parent)
|
||||
else if (unsigned)source->target & ~KERNEL_MASK:
|
||||
set (index, source->target, source->cap_protected, kCapRef (), &source->target->capabilities)
|
||||
@ -292,7 +292,7 @@ void kMemory::free_message (kReceiver *owner, kMessage *message):
|
||||
|
||||
void kMemory::free_receiver (kReceiver *receiver):
|
||||
receiver->orphan ()
|
||||
while receiver->capabilities:
|
||||
while receiver->capabilities.valid ():
|
||||
receiver->capabilities->invalidate ()
|
||||
while receiver->messages:
|
||||
free_message (receiver, receiver->messages)
|
||||
@ -319,20 +319,20 @@ void kReceiver::own (kThread *o):
|
||||
void kCapability::invalidate ():
|
||||
if !target:
|
||||
return
|
||||
if sibling_prev:
|
||||
if sibling_prev.valid ():
|
||||
sibling_prev->sibling_next = sibling_next
|
||||
else if (unsigned)target & ~KERNEL_MASK:
|
||||
target->capabilities = sibling_next
|
||||
else:
|
||||
((kObject *)cap_protected.l)->refs = sibling_next
|
||||
if sibling_next:
|
||||
if sibling_next.valid ():
|
||||
sibling_next->sibling_prev = sibling_prev
|
||||
parent.reset ()
|
||||
sibling_prev.reset ()
|
||||
sibling_next.reset ()
|
||||
kCapability *c = this
|
||||
while c:
|
||||
while c->children:
|
||||
while c->children.valid ():
|
||||
c = c->children.deref ()
|
||||
kCapability *next = c->sibling_next.deref ()
|
||||
if !next:
|
||||
|
@ -31,10 +31,8 @@ static list *__first_free_slot, *__first_free_cap
|
||||
Receiver __my_receiver
|
||||
Thread __my_thread
|
||||
Memory __my_memory
|
||||
Caps __my_caps
|
||||
Cap __my_call
|
||||
Cap __my_parent
|
||||
Caps __tmp_caps
|
||||
|
||||
void free_slot (unsigned slot):
|
||||
__slot_admin[slot].prev = NULL
|
||||
@ -59,16 +57,17 @@ unsigned alloc_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_SLOT.
|
||||
// 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 - __slot_admin
|
||||
return ret - __cap_admin
|
||||
|
||||
extern "C":
|
||||
void __main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
|
||||
@ -77,7 +76,7 @@ extern "C":
|
||||
__slot_admin = slot_admin
|
||||
__cap_admin = cap_admin
|
||||
__first_free_slot = NULL
|
||||
for unsigned i = 1; i < __slots; ++i:
|
||||
for unsigned i = 2; i < __slots; ++i:
|
||||
free_slot (i)
|
||||
__first_free_cap = NULL
|
||||
for unsigned i = 7; i < __caps; ++i:
|
||||
@ -85,10 +84,8 @@ extern "C":
|
||||
__my_receiver = Cap (0, __receiver_num)
|
||||
__my_thread = Cap (0, __thread_num)
|
||||
__my_memory = Cap (0, __memory_num)
|
||||
__my_caps = Cap (0, __caps_num)
|
||||
__my_call = Cap (0, __call_num)
|
||||
__my_parent = Cap (0, __parent_num)
|
||||
__tmp_caps = Cap (0, __tmp_num)
|
||||
Num ret = start ()
|
||||
__my_parent.invoke (~0, ret)
|
||||
__my_memory.destroy (__my_thread)
|
||||
|
@ -48,10 +48,11 @@ struct Keyboard : public Cap:
|
||||
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):
|
||||
invoke (cb, CAP_MASTER_DIRECT | SET_CB)
|
||||
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
||||
// Get a list of keys on this keyboard. The key codes start at zero with no gaps.
|
||||
void get_keys (List <String> ret):
|
||||
call (ret, CAP_MASTER_DIRECT | GET_KEYS)
|
||||
List <String> get_keys (List <String> ret = Cap (0, alloc_cap ())):
|
||||
icall (ret, CAP_MASTER_DIRECT | GET_KEYS)
|
||||
return ret
|
||||
|
||||
// Display interface.
|
||||
struct Display : public Cap:
|
||||
@ -64,18 +65,18 @@ struct Display : public Cap:
|
||||
// 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):
|
||||
invoke (cb, CAP_MASTER_DIRECT | EOF_CB)
|
||||
ocall (cb, CAP_MASTER_DIRECT | EOF_CB)
|
||||
// Create a framebuffer for the display. When not in use, it can be freed by the user.
|
||||
// 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 call (pages, Num (CAP_MASTER_DIRECT | CREATE_FB, 0), Num ((w << 16) | h, mode)).l
|
||||
return icall (pages, Num (CAP_MASTER_DIRECT | CREATE_FB, 0), 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):
|
||||
invoke (unuse_cb, Num (CAP_MASTER_DIRECT | USE_FB, addr), Num ((w << 16) | h, mode))
|
||||
ocall (unuse_cb, Num (CAP_MASTER_DIRECT | USE_FB, addr), Num ((w << 16) | h, mode))
|
||||
// Get information about the display.
|
||||
void get_info ():
|
||||
// TODO: Interface is to be designed.
|
||||
@ -93,13 +94,13 @@ struct File : public Cap:
|
||||
MAP_HANDLE
|
||||
// Get information about the file.
|
||||
Num get_info (unsigned type, Caps ret = Cap ()):
|
||||
return call (ret, Num (CAP_MASTER_DIRECT | INFO, type))
|
||||
return icall (ret, Num (CAP_MASTER_DIRECT | INFO, type))
|
||||
// Close a file. If this is a directory, it implicitly closes all files opened from it.
|
||||
void close ():
|
||||
invoke (CAP_MASTER_DIRECT | CLOSE)
|
||||
call (CAP_MASTER_DIRECT | CLOSE)
|
||||
// Map a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle.
|
||||
File map_handle (File ret):
|
||||
call (ret, CAP_MASTER_DIRECT | MAP_HANDLE)
|
||||
icall (ret, CAP_MASTER_DIRECT | MAP_HANDLE)
|
||||
|
||||
// Directory interface.
|
||||
struct Directory : public File:
|
||||
@ -116,19 +117,19 @@ struct Directory : public File:
|
||||
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):
|
||||
call (target, CAP_MASTER_DIRECT | GET_NAME, idx)
|
||||
icall (target, CAP_MASTER_DIRECT | GET_NAME, idx)
|
||||
// Get the file.
|
||||
void get_file (Num idx, File ret):
|
||||
call (ret, CAP_MASTER_DIRECT | GET_FILE, idx)
|
||||
icall (ret, CAP_MASTER_DIRECT | GET_FILE, idx)
|
||||
// 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 call (ret, Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
|
||||
return icall (ret, 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):
|
||||
call (ret, CAP_MASTER_DIRECT | CREATE_FILE)
|
||||
icall (ret, CAP_MASTER_DIRECT | CREATE_FILE)
|
||||
// Delete a file. After this, any index may map to a different file.
|
||||
void delete_file (Num idx):
|
||||
invoke (CAP_MASTER_DIRECT | DELETE_FILE, idx)
|
||||
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
|
||||
|
||||
// Stream interface.
|
||||
struct Stream : public File:
|
||||
@ -138,10 +139,10 @@ struct Stream : public File:
|
||||
WRITE
|
||||
// Try to read size bytes. Returns the number of bytes successfully read.
|
||||
Num read (Num size, String ret):
|
||||
return call (ret, CAP_MASTER_DIRECT | READ, size)
|
||||
return icall (ret, CAP_MASTER_DIRECT | READ, size)
|
||||
// Try to write size bytes. Returns the number of bytes successfully written.
|
||||
Num write (String s, Num size):
|
||||
return call (s, CAP_MASTER_DIRECT | WRITE, size)
|
||||
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
|
||||
|
||||
// Seekable file interface.
|
||||
struct Seekable : public File:
|
||||
@ -152,13 +153,13 @@ struct Seekable : public File:
|
||||
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 call (ret, Num (CAP_MASTER_DIRECT | READ, size), idx)
|
||||
return icall (ret, 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):
|
||||
return call (s, CAP_MASTER_DIRECT | WRITE, idx)
|
||||
return ocall (s, CAP_MASTER_DIRECT | WRITE, idx)
|
||||
// Truncate file to size idx. The file is extended with zeroes if it gets longer.
|
||||
void truncate (Num idx):
|
||||
invoke (CAP_MASTER_DIRECT | TRUNCATE, idx)
|
||||
call (CAP_MASTER_DIRECT | TRUNCATE, idx)
|
||||
|
||||
// Mappable file interface.
|
||||
struct Mappable : public Seekable:
|
||||
|
@ -58,15 +58,30 @@ enum cap_type:
|
||||
CAP_TOUCHPAD
|
||||
CAP_LOCKLEDS
|
||||
CAP_PWM
|
||||
NUM_EVENT_TYPES
|
||||
|
||||
static unsigned events
|
||||
static Caps event_caps
|
||||
|
||||
static void event (event_type type, unsigned data):
|
||||
Cap (events, type - 32).invoke (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)
|
||||
|
||||
static void set_cb (Cap cap, event_type type):
|
||||
cap.clone (Cap (events, type - 32))
|
||||
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)
|
||||
|
||||
class DevKeyboard:
|
||||
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
|
||||
@ -188,7 +203,7 @@ class Touchpad:
|
||||
else:
|
||||
gpio_irq_high (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
|
||||
event (TOUCHPAD_EVENT, 0x10000)
|
||||
event (TOUCHPAD_EVENT, 0 | Keyboard::RELEASE)
|
||||
if state & (1 << GPIO_TP_RIGHT):
|
||||
gpio_irq_low (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
|
||||
@ -196,7 +211,7 @@ class Touchpad:
|
||||
else:
|
||||
gpio_irq_high (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
|
||||
event (TOUCHPAD_EVENT, 0x10001)
|
||||
event (TOUCHPAD_EVENT, 1 | Keyboard::RELEASE)
|
||||
old_state = state
|
||||
// Ack interrupts.
|
||||
//GPIO_GPFR (GPIO_TP_LEFT_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
|
||||
@ -255,22 +270,18 @@ class Pwm:
|
||||
// TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything.
|
||||
|
||||
Num start ():
|
||||
Kernel::schedule ()
|
||||
map_gpio ()
|
||||
map_pwm0 ()
|
||||
|
||||
Caps e = __my_memory.create_caps (NUM_EVENT_TYPES - 32)
|
||||
events = e.use ()
|
||||
free_cap (e)
|
||||
event_caps = __my_memory.create_caps (NUM_EVENTS)
|
||||
events = event_caps.use ()
|
||||
|
||||
DevKeyboard kbd
|
||||
Touchpad tp
|
||||
Lockleds leds
|
||||
Pwm pwm
|
||||
|
||||
// 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)
|
||||
|
||||
Caps c = __my_memory.create_caps (4)
|
||||
unsigned init_slot = c.use ()
|
||||
__my_receiver.create_capability (CAP_KEYBOARD, Cap (init_slot, 0))
|
||||
@ -278,15 +289,23 @@ Num start ():
|
||||
__my_receiver.create_capability (CAP_LOCKLEDS, Cap (init_slot, 2))
|
||||
__my_receiver.create_capability (CAP_PWM, Cap (init_slot, 3))
|
||||
|
||||
__my_parent.invoke (c, INIT_SET_GPIO)
|
||||
__my_parent.ocall (c, INIT_SET_GPIO)
|
||||
free_cap (c)
|
||||
free_slot (init_slot)
|
||||
|
||||
if kbd.is_scanning ():
|
||||
__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)
|
||||
Kernel::wait (&msg, slot)
|
||||
switch (unsigned)msg.cap_protected.value ():
|
||||
case ~0:
|
||||
// Alarm.
|
||||
@ -302,16 +321,20 @@ Num start ():
|
||||
Kernel::register_interrupt (IRQ_GPIO0)
|
||||
break
|
||||
case CAP_KEYBOARD:
|
||||
set_cb (Cap (__tmp_slot, 0), KEYBOARD_EVENT)
|
||||
set_cb (Cap (slot, 1), KEYBOARD_EVENT)
|
||||
Cap (slot, 0).invoke ()
|
||||
kbd.send_initial ()
|
||||
break
|
||||
case CAP_TOUCHPAD:
|
||||
set_cb (Cap (__tmp_slot, 0), TOUCHPAD_EVENT)
|
||||
set_cb (Cap (slot, 1), TOUCHPAD_EVENT)
|
||||
Cap (slot, 0).invoke ()
|
||||
tp.send_initial ()
|
||||
break
|
||||
case CAP_LOCKLEDS:
|
||||
leds.set (msg.data[0].l)
|
||||
Cap (slot, 0).invoke ()
|
||||
break
|
||||
case CAP_PWM:
|
||||
pwm.set_backlight (msg.data[0].l)
|
||||
Cap (slot, 0).invoke ()
|
||||
break
|
||||
|
@ -30,31 +30,37 @@ enum type:
|
||||
|
||||
static void setup ():
|
||||
unsigned state = 0
|
||||
unsigned slot = 2
|
||||
unsigned slot = alloc_slot ()
|
||||
while true:
|
||||
Cap::OMessage msg
|
||||
Kernel::wait (&msg, slot)
|
||||
switch msg.data[0].value ():
|
||||
case INIT_SET_GPIO:
|
||||
kdebug ("gpio\n")
|
||||
kbd = Cap (slot, 0)
|
||||
tp = Cap (slot, 1)
|
||||
lockleds = Cap (slot, 2)
|
||||
pwm = Cap (slot, 3)
|
||||
++slot
|
||||
Caps caps = Cap (slot, 1)
|
||||
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)
|
||||
++state
|
||||
break
|
||||
case INIT_SET_LCD:
|
||||
kdebug ("lcd\n")
|
||||
lcd = Cap (slot, 0)
|
||||
++slot
|
||||
lcd = Cap (slot, 1).clone ()
|
||||
Cap (slot, 0).invoke ()
|
||||
++state
|
||||
break
|
||||
if state == 2:
|
||||
break
|
||||
kbd.set_cb (__my_receiver.create_capability (KBD).copy ())
|
||||
tp.set_cb (__my_receiver.create_capability (TP).copy ())
|
||||
pwm.invoke (1)
|
||||
Caps caps = __my_memory.create_caps (2)
|
||||
caps.use (slot)
|
||||
Cap kc = __my_receiver.create_capability (KBD, Cap (slot, 1))
|
||||
kbd.set_cb (kc)
|
||||
Cap tc = __my_receiver.create_capability (TP, Cap (slot, 0))
|
||||
tp.set_cb (tc)
|
||||
pwm.call (1)
|
||||
|
||||
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
|
||||
|
||||
@ -82,5 +88,5 @@ Num start ():
|
||||
leds |= 0x4
|
||||
if !(msg.data[0].l & Keyboard::RELEASE):
|
||||
leds |= 0x2
|
||||
lockleds.invoke (leds)
|
||||
lockleds.call (leds)
|
||||
break
|
||||
|
@ -20,9 +20,9 @@
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
|
||||
__asm__ volatile (".globl charset\ncharset:\n.incbin \"boot-programs/charset.data\"")
|
||||
// I'm too lazy to do this right. The address of charset is really the address of the array.
|
||||
extern unsigned charset
|
||||
__asm__ volatile (".section .rodata\n.globl charset\ncharset:\n.incbin \"boot-programs/charset.data\"\n.section .text")
|
||||
// charset is really the first character in the array. Its address is used as the start of the array.
|
||||
extern unsigned char const charset[127-32][6]
|
||||
|
||||
#define assert(x) do { while (!(x)) kdebug ("assertion failed " #x); } while (0)
|
||||
|
||||
@ -32,16 +32,18 @@ enum types:
|
||||
|
||||
// For now, support only 16 bpp.
|
||||
// Screen is 800x480 tft.
|
||||
unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2
|
||||
static unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2
|
||||
#define frame_size (v * h * Bpp)
|
||||
|
||||
static unsigned physical_descriptor
|
||||
|
||||
struct Descriptor:
|
||||
unsigned next
|
||||
unsigned frame
|
||||
unsigned id
|
||||
unsigned cmd
|
||||
|
||||
static void reset (unsigned physical_descriptor):
|
||||
static void reset ():
|
||||
LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16
|
||||
LCD_VSYNC = vs
|
||||
LCD_HSYNC = hs
|
||||
@ -74,11 +76,10 @@ static void putchar (unsigned x, unsigned y, unsigned ch, unsigned fg = 0xffff,
|
||||
if ch < 32 || ch > 126:
|
||||
ch = 127
|
||||
ch -= 32
|
||||
unsigned char *c = &((unsigned char *)&charset)[ch * 6]
|
||||
unsigned lookup[2] = { bg, fg }
|
||||
for unsigned k = 0; k < 6; ++k:
|
||||
for unsigned r = 0; r < 8; ++r:
|
||||
LCD_FRAMEBUFFER_BASE[(y * 8 + r) * 800 + x * 6 + k] = lookup[c[k] & (1 << r) ? 1 : 0]
|
||||
LCD_FRAMEBUFFER_BASE[(y * 8 + r) * 800 + x * 6 + k] = lookup[charset[ch][k] & (1 << r) ? 1 : 0]
|
||||
|
||||
static unsigned log_x = 1, log_y = 1
|
||||
static void inc_logx ():
|
||||
@ -126,12 +127,12 @@ Num start ():
|
||||
|
||||
Descriptor descriptor __attribute__ ((aligned (16)))
|
||||
unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
|
||||
unsigned physical = Kernel::alloc_range (__my_memory, pages)
|
||||
assert (physical)
|
||||
unsigned physical = __my_memory.alloc_range (pages)
|
||||
assert (physical & PAGE_MASK && ~physical)
|
||||
for unsigned i = 0; i < pages; ++i:
|
||||
Page p = __my_memory.create_page ()
|
||||
p.alloc_physical (physical + i * PAGE_SIZE, false, true)
|
||||
__my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, true)
|
||||
__my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE)
|
||||
free_cap (p)
|
||||
for unsigned y = 0; y < 480; ++y:
|
||||
unsigned g = (y << 6) / 480
|
||||
@ -150,7 +151,7 @@ Num start ():
|
||||
b = 0x1f
|
||||
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
|
||||
Page p = __my_memory.mapping (&descriptor)
|
||||
unsigned physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK)
|
||||
physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK)
|
||||
free_cap (p)
|
||||
descriptor.next = physical_descriptor
|
||||
descriptor.frame = physical
|
||||
@ -158,15 +159,16 @@ Num start ():
|
||||
descriptor.cmd = LCD_CMD_EOFINT | ((frame_size / 4) << LCD_CMD_LEN_BIT)
|
||||
unsigned dptr = (unsigned)&descriptor
|
||||
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
|
||||
reset (physical_descriptor)
|
||||
|
||||
Cap set_eof_cb = __my_receiver.create_capability (LCD_EOF_CB)
|
||||
__my_parent.invoke (set_eof_cb.copy (), INIT_SET_LCD)
|
||||
reset ()
|
||||
|
||||
Cap logcap = __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)
|
||||
|
||||
unsigned slot = alloc_slot ()
|
||||
Cap eof_cb (0, alloc_cap ())
|
||||
while true:
|
||||
Cap::OMessage msg
|
||||
Kernel::wait (&msg, slot)
|
||||
@ -174,10 +176,11 @@ Num start ():
|
||||
switch msg.cap_protected.value ():
|
||||
case IRQ_LCD:
|
||||
lcd_clr_eof ()
|
||||
Cap (slot, 0).invoke ()
|
||||
Cap (slot, 0) = Cap ()
|
||||
eof_cb.invoke ()
|
||||
break
|
||||
case LCD_EOF_CB:
|
||||
Cap (slot, 1).clone (eof_cb)
|
||||
Cap (slot, 0).invoke ()
|
||||
Kernel::register_interrupt (IRQ_LCD)
|
||||
break
|
||||
case LCD_LOG:
|
||||
|
262
invoke.ccp
262
invoke.ccp
@ -19,7 +19,7 @@
|
||||
#include "kernel.hh"
|
||||
|
||||
void kThread::raise (unsigned code, unsigned data):
|
||||
panic (code, "raise")
|
||||
dpanic (code, "raise")
|
||||
dbg_log ("raise ")
|
||||
dbg_log_num ((unsigned)current)
|
||||
dbg_log_char ('/')
|
||||
@ -48,16 +48,27 @@ kCapRef kThread::find_capability (unsigned code, bool *copy):
|
||||
unsigned num = c & 0xffff
|
||||
if slot >= slots || !caps[slot] || num >= caps[slot]->size:
|
||||
if c != CAP_NONE:
|
||||
panic (code, "debug")
|
||||
dpanic (code, "debug")
|
||||
dbg_log_num ((unsigned)old_current)
|
||||
dbg_log (": invalid capability ")
|
||||
dbg_log_num (code)
|
||||
dbg_log_char ('\n')
|
||||
dbg_log_num (num)
|
||||
dbg_log_char (':')
|
||||
dbg_log_num (slot)
|
||||
dbg_log (" > ")
|
||||
if caps[slot]:
|
||||
dbg_log_num (caps[slot]->size)
|
||||
else:
|
||||
dbg_log ("no caps")
|
||||
dbg_log_char ('\n')
|
||||
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.
|
||||
@ -90,8 +101,7 @@ bool kReceiver::send_message (Num cap_protected, kCapability::Context *c):
|
||||
if owner && owner->is_waiting () && (cap_protected.value () == reply_protected_data.value () || !protected_only):
|
||||
if protected_only:
|
||||
protected_only = false
|
||||
if owner->recv_slot < owner->slots:
|
||||
owner->fill_slot (owner->recv_slot, c->caps)
|
||||
owner->fill_slot (owner->recv_slot, c->caps)
|
||||
kThread_arch_receive (owner, cap_protected, recv_protected, c->data)
|
||||
owner->unwait ()
|
||||
return true
|
||||
@ -133,8 +143,10 @@ static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
|
||||
invoke (reply_target, reply_protected, &c, NULL)
|
||||
|
||||
static void reply_cap (unsigned target, Num cap_protected, kCapRef *ref):
|
||||
if reply:
|
||||
if reply.valid ():
|
||||
reply.set ((kReceiver *)target, cap_protected, kCapRef (), ref)
|
||||
else:
|
||||
dpanic (0x87677654, "no target to reply capability to")
|
||||
reply_num (0)
|
||||
|
||||
static void receiver_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c):
|
||||
@ -193,7 +205,7 @@ static void receiver_invoke (unsigned cmd, unsigned target, Num cap_protected, k
|
||||
return
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
break
|
||||
return
|
||||
reply_num (0)
|
||||
|
||||
static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c):
|
||||
@ -206,6 +218,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
if ret:
|
||||
reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x03311992, "out of memory creating receiver")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_MEMORY:
|
||||
@ -213,6 +226,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
if ret:
|
||||
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x13311992, "out of memory creating memory")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_THREAD:
|
||||
@ -220,6 +234,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
if ret:
|
||||
reply_cap (CAPTYPE_THREAD | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x23311992, "out of memory creating thread")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_PAGE:
|
||||
@ -227,6 +242,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
if ret:
|
||||
reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x33311992, "out of memory creating page")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
case CAPTYPE_CAPS:
|
||||
@ -234,6 +250,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
if ret:
|
||||
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs)
|
||||
else:
|
||||
dpanic (0x43311992, "out of memory creating caps")
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
default:
|
||||
@ -270,10 +287,12 @@ static void memory_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
case 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:
|
||||
dpanic (0x22993341, "Trying to map non-page")
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.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
|
||||
@ -350,10 +369,12 @@ static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
break
|
||||
case Thread::USE_SLOT:
|
||||
if c->data[1].l >= thread->slots || c->caps->size < 2:
|
||||
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):
|
||||
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)
|
||||
@ -362,71 +383,77 @@ static void thread_invoke (unsigned cmd, unsigned target, Num cap_protected, kCa
|
||||
case Thread::SCHEDULE:
|
||||
do_schedule = true
|
||||
return
|
||||
if !(thread->flags & Thread::PRIV):
|
||||
reply_num (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)
|
||||
break
|
||||
case 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:
|
||||
reply_num (~0)
|
||||
return
|
||||
((kThread *)c->caps->cap (1)->cap_protected.l)->flags |= Thread::PRIV
|
||||
break
|
||||
case Thread::PRIV_ALLOC_RANGE:
|
||||
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
|
||||
reply_num (~0)
|
||||
return
|
||||
kMemory *mem = (kMemory *)c->caps->cap (1)->cap_protected.l
|
||||
if !mem->use (c->data[1].l):
|
||||
reply_num (ERR_OUT_OF_MEMORY)
|
||||
return
|
||||
unsigned data = phys_alloc (c->data[1].l)
|
||||
if !data:
|
||||
mem->unuse (c->data[1].l)
|
||||
reply_num (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:
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l
|
||||
page->forget ()
|
||||
if !(c->data[1].l & 2):
|
||||
if page->flags & Page::PAYING:
|
||||
page->flags &= ~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:
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
page->flags |= Page::PAYING
|
||||
page->frame = c->data[1].l & PAGE_MASK
|
||||
page->flags |= Page::FRAME
|
||||
if !(c->data[1].l & 1):
|
||||
page->flags |= Page::UNCACHED
|
||||
if !(c->data[1].l & 2):
|
||||
page->flags |= 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:
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l
|
||||
reply_num (page->frame & ~0xc0000000)
|
||||
return
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
return
|
||||
if !(thread->flags & Thread::PRIV):
|
||||
reply_num (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)
|
||||
break
|
||||
case 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:
|
||||
reply_num (~0)
|
||||
return
|
||||
((kThread *)c->caps->cap (1)->cap_protected.l)->flags |= Thread::PRIV
|
||||
break
|
||||
case Thread::PRIV_ALLOC_RANGE:
|
||||
if c->caps->size < 2 || ((unsigned)c->caps->cap (1)->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
|
||||
if !mem->use (c->data[1].l):
|
||||
dpanic (0x34365435, "out of memory during alloc_range")
|
||||
reply_num (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)
|
||||
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:
|
||||
panic (0x21342134, "no page provided for alloc physical")
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l
|
||||
page->forget ()
|
||||
if !(c->data[1].l & 2):
|
||||
if page->flags & Page::PAYING:
|
||||
page->flags &= ~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:
|
||||
page->address_space->unuse ()
|
||||
else:
|
||||
page->flags |= Page::PAYING
|
||||
page->frame = c->data[1].l & PAGE_MASK
|
||||
page->flags |= Page::FRAME
|
||||
if !(c->data[1].l & 1):
|
||||
page->flags |= Page::UNCACHED
|
||||
if !(c->data[1].l & 2):
|
||||
page->flags |= 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:
|
||||
dpanic (0x99049380, "invalid page for physical address")
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *page = (kPage *)c->caps->cap (1)->cap_protected.l
|
||||
reply_num (page->frame & ~0xc0000000)
|
||||
return
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
return
|
||||
reply_num (0)
|
||||
return
|
||||
|
||||
@ -463,14 +490,15 @@ static void page_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapa
|
||||
// Cannot share without a target page.
|
||||
reply_num (~0)
|
||||
return
|
||||
if ((unsigned)c->caps->cap (0)->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
if ((unsigned)c->caps->cap (1)->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
||||
// FIXME: This makes it impossible to use a fake kPage capability.
|
||||
break
|
||||
kPage *t = (kPage *)c->caps->cap (0)->cap_protected.l
|
||||
reply_num (~0)
|
||||
return
|
||||
kPage *t = (kPage *)c->caps->cap (1)->cap_protected.l
|
||||
t->forget ()
|
||||
if c->data[0].h & Page::READONLY || cmd & Page::READONLY:
|
||||
t->flags |= Page::READONLY
|
||||
if !page->flags & Page::FRAME:
|
||||
if !(page->flags & Page::FRAME):
|
||||
break
|
||||
if c->data[0].h & Page::COPY:
|
||||
if ~t->flags & Page::PAYING:
|
||||
@ -577,21 +605,74 @@ static void page_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapa
|
||||
break
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
break
|
||||
return
|
||||
reply_num (0)
|
||||
|
||||
static void print_capref (kCapRef cap):
|
||||
dbg_log_num ((unsigned)cap.caps)
|
||||
dbg_log_char (':')
|
||||
dbg_log_num (cap.index)
|
||||
|
||||
static void print_cap (kCapRef cap, kCapRef self):
|
||||
if cap.deref () == self.deref ():
|
||||
dbg_log_char ('{')
|
||||
else:
|
||||
dbg_log_char ('[')
|
||||
dbg_log_num ((unsigned)cap.caps)
|
||||
dbg_log_char (':')
|
||||
dbg_log_num (cap.index)
|
||||
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
|
||||
print_cap (c, self)
|
||||
if cap.deref () == self.deref ():
|
||||
dbg_log_char ('}')
|
||||
else:
|
||||
dbg_log_char (']')
|
||||
|
||||
static void caps_invoke (unsigned cmd, unsigned target, Num cap_protected, kCapability::Context *c):
|
||||
kCaps *caps = (kCapsP)cap_protected.l
|
||||
switch cmd:
|
||||
case Caps::PRINT:
|
||||
if c->data[1].l >= caps->size:
|
||||
dpanic (0, "invalid caps for print")
|
||||
return
|
||||
kCapRef cap (caps, c->data[1].l)
|
||||
kCapRef orig (caps, c->data[1].l)
|
||||
while cap->parent.valid ():
|
||||
while cap->sibling_prev.valid ():
|
||||
if cap->parent.deref () != cap->sibling_prev->parent.deref ():
|
||||
dpanic (0, "parent problem in cap data")
|
||||
return
|
||||
if cap.deref () != cap->sibling_prev->sibling_next.deref ():
|
||||
dpanic (0, "prev error in cap data")
|
||||
return
|
||||
cap = cap->sibling_prev
|
||||
if cap->parent->children.deref () != cap.deref ():
|
||||
dpanic (0, "parent error in cap data")
|
||||
return
|
||||
cap = cap->parent
|
||||
while cap->sibling_prev.valid ():
|
||||
if cap->parent.deref () != cap->sibling_prev->parent.deref ():
|
||||
dpanic (0, "parent parent problem in cap data")
|
||||
return
|
||||
if cap.deref () != cap->sibling_prev->sibling_next.deref ():
|
||||
dpanic (0, "parent prev error in cap data")
|
||||
return
|
||||
cap = cap->sibling_prev
|
||||
while cap.valid ():
|
||||
print_cap (cap, orig)
|
||||
cap = cap->sibling_next
|
||||
dbg_log_char ('\n')
|
||||
return
|
||||
default:
|
||||
reply_num (ERR_INVALID_OPERATION)
|
||||
break
|
||||
return
|
||||
|
||||
static void kill_reply (kCapability *self):
|
||||
while self->parent:
|
||||
while self->parent.valid ():
|
||||
self = self->parent.deref ()
|
||||
while self->sibling_prev:
|
||||
while self->sibling_prev.valid ():
|
||||
self->sibling_prev->invalidate ()
|
||||
while self->sibling_next:
|
||||
while self->sibling_next.valid ():
|
||||
self->sibling_next->invalidate ()
|
||||
self->invalidate ()
|
||||
|
||||
@ -602,11 +683,14 @@ static void kernel_invoke (unsigned target, Num cap_protected, kCapability::Cont
|
||||
// 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.
|
||||
if !c->caps || c->caps->size == 0:
|
||||
// No caps, so no target to call.
|
||||
return
|
||||
reply_target = (kReceiver *)cap_protected.l
|
||||
reply_target->protected_only = target == (CAPTYPE_RECEIVER | Receiver::CALL)
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
if !c->caps || c->caps->size == 0:
|
||||
// No caps, so no target to call.
|
||||
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:
|
||||
@ -614,7 +698,7 @@ static void kernel_invoke (unsigned target, Num cap_protected, kCapability::Cont
|
||||
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:
|
||||
else if (unsigned)call_target == (CAPTYPE_RECEIVER | Receiver::REPLY):
|
||||
// Reply capability: destroy all before invoke.
|
||||
kill_reply (c->caps->cap (0))
|
||||
kReceiver *r = (kReceiver *)call_cap_protected.l
|
||||
@ -625,12 +709,16 @@ static void kernel_invoke (unsigned target, Num cap_protected, kCapability::Cont
|
||||
c->caps->cap (0)->invalidate ()
|
||||
kernel_invoke ((unsigned)call_target, call_cap_protected, c, NULL)
|
||||
return
|
||||
if target == CAPTYPE_RECEIVER | Receiver::REPLY:
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
if target == (CAPTYPE_RECEIVER | Receiver::REPLY):
|
||||
// This is a reply capability.
|
||||
kReceiver *r = (kReceiver *)cap_protected.l
|
||||
kill_reply (self)
|
||||
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:
|
||||
@ -665,12 +753,14 @@ static void kernel_invoke (unsigned target, Num cap_protected, kCapability::Cont
|
||||
void invoke (kReceiverP target, Num cap_protected, kCapability::Context *c, kCapability *self):
|
||||
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)
|
||||
return
|
||||
// This is a kernel capability. Use a function to allow optimized call capabilities.
|
||||
if !c->caps || c->caps->size < 1:
|
||||
reply_target = NULL
|
||||
else:
|
||||
reply_target = c->caps->cap (1)->target
|
||||
reply_protected = c->caps->cap (1)->cap_protected
|
||||
reply_target = c->caps->cap (0)->target
|
||||
reply_protected = c->caps->cap (0)->cap_protected
|
||||
kernel_invoke ((unsigned)target, cap_protected, c, self)
|
||||
|
212
iris.hhp
212
iris.hhp
@ -122,10 +122,10 @@ struct Memory
|
||||
#define __receiver_num 0
|
||||
#define __thread_num 1
|
||||
#define __memory_num 2
|
||||
#define __caps_num 3
|
||||
#define __call_num 4
|
||||
#define __parent_num 5
|
||||
#define __tmp_num 6
|
||||
#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.
|
||||
@ -139,15 +139,12 @@ extern Memory __my_memory
|
||||
extern Cap __my_call
|
||||
extern Cap __my_parent
|
||||
extern Caps __my_caps
|
||||
extern Caps __tmp_caps
|
||||
|
||||
unsigned alloc_slot ()
|
||||
unsigned alloc_cap ()
|
||||
void free_slot (unsigned slot)
|
||||
void free_cap (Cap cap)
|
||||
|
||||
#define __tmp_slot 1
|
||||
|
||||
struct Cap:
|
||||
unsigned code
|
||||
inline Cap copy () const
|
||||
@ -160,11 +157,12 @@ struct Cap:
|
||||
struct OMessage
|
||||
inline void invoke (IMessage const *i, OMessage *o)
|
||||
inline void call (IMessage *i, OMessage *o)
|
||||
inline void invoke (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot)
|
||||
inline void invoke (Num d0 = 0, Num d1 = 0)
|
||||
inline Num call (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
|
||||
inline Num call (Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
|
||||
inline void clone (Cap target)
|
||||
inline Num icall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
|
||||
inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
|
||||
inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0, unsigned oslot = __tmp_slot, unsigned islot = ~0)
|
||||
inline Cap clone (Cap target = Cap (0, alloc_cap ()))
|
||||
|
||||
struct Cap::IMessage:
|
||||
Num data[2]
|
||||
@ -182,34 +180,15 @@ 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
|
||||
return (code >> 16) & 0x7fff
|
||||
unsigned Cap::idx () const:
|
||||
return code & 0xffff
|
||||
void Cap::invoke (IMessage const *i, OMessage *o):
|
||||
switch i->num:
|
||||
default:
|
||||
__asm__ volatile ("lw $t9, %0" :: "m"(i->set[9].code) : "t9")
|
||||
case 9:
|
||||
__asm__ volatile ("lw $t8, %0" :: "m"(i->set[8].code) : "t8")
|
||||
case 8:
|
||||
__asm__ volatile ("lw $t7, %0" :: "m"(i->set[7].code) : "t7")
|
||||
case 7:
|
||||
__asm__ volatile ("lw $t6, %0" :: "m"(i->set[6].code) : "t6")
|
||||
case 6:
|
||||
__asm__ volatile ("lw $t5, %0" :: "m"(i->set[5].code) : "t5")
|
||||
case 5:
|
||||
__asm__ volatile ("lw $t4, %0" :: "m"(i->set[4].code) : "t4")
|
||||
case 4:
|
||||
__asm__ volatile ("lw $t3, %0" :: "m"(i->set[3].code) : "t3")
|
||||
case 3:
|
||||
__asm__ volatile ("lw $t2, %0" :: "m"(i->set[2].code) : "t2")
|
||||
case 2:
|
||||
__asm__ volatile ("lw $t1, %0" :: "m"(i->set[1].code) : "t1")
|
||||
case 1:
|
||||
__asm__ volatile ("lw $t0, %0" :: "m"(i->set[0].code) : "t0")
|
||||
case 0:
|
||||
break
|
||||
__asm__ volatile ("lw $v0, %2\n"
|
||||
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"
|
||||
@ -228,49 +207,24 @@ void Cap::invoke (IMessage const *i, OMessage *o):
|
||||
"\tsw $s0, 16($v0)\n"
|
||||
"\tsw $s1, 20($v0)\n"
|
||||
"\tsw $s2, 24($v0)\n"
|
||||
"\tsw $s3, 28($v0)\n"
|
||||
"\tsw $s3, 28($v0)"
|
||||
: "=m"(o)
|
||||
: "m"(code), "m"(i)
|
||||
: "memory", "v0", "s0", "s1", "s2", "s3", "a0", "a1", "a2", "a3")
|
||||
: "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 (Cap c, Num d0, Num d1, unsigned oslot):
|
||||
IMessage i
|
||||
OMessage o
|
||||
i.islot = ~0
|
||||
i.oslot = oslot
|
||||
Cap cs[2]
|
||||
cs[0] = c
|
||||
i.set = cs
|
||||
i.num = 2
|
||||
i.first = 0
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
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 (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
|
||||
invoke (&i, &o)
|
||||
return o.data[0]
|
||||
Num Cap::call (Num d0, Num d1, unsigned oslot, unsigned islot):
|
||||
IMessage i
|
||||
OMessage o
|
||||
@ -282,13 +236,57 @@ Num Cap::call (Num d0, Num d1, unsigned oslot, unsigned islot):
|
||||
i.first = 0
|
||||
i.data[0] = d0
|
||||
i.data[1] = d1
|
||||
invoke (&i, &o)
|
||||
call (&i, &o)
|
||||
return o.data[0]
|
||||
void Cap::clone (Cap target):
|
||||
Num Cap::icall (Cap c, Num d0, Num d1, unsigned oslot, unsigned islot):
|
||||
IMessage i
|
||||
OMessage o
|
||||
Cap c = this->copy ()
|
||||
i.set = &c
|
||||
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
|
||||
@ -296,6 +294,7 @@ void Cap::clone (Cap target):
|
||||
i.data[0] = 0
|
||||
i.data[1] = 0
|
||||
Cap ().invoke (&i, &o)
|
||||
return target
|
||||
|
||||
struct Receiver : public Cap:
|
||||
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
@ -318,26 +317,26 @@ struct Receiver : public Cap:
|
||||
// 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):
|
||||
invoke (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
|
||||
ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
|
||||
Cap create_capability (unsigned protected_data, Cap ret = Cap (0, alloc_cap ())):
|
||||
call (ret, CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
|
||||
icall (ret, CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
|
||||
return ret
|
||||
Num get_reply_protected_data ():
|
||||
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
|
||||
void set_reply_protected_data (Num data):
|
||||
invoke (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, 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):
|
||||
invoke (CAP_MASTER_DIRECT | SET_ALARM, data)
|
||||
call (CAP_MASTER_DIRECT | SET_ALARM, data)
|
||||
static inline void sleep (unsigned value, OMessage *ret, unsigned slot = __tmp_slot)
|
||||
Cap create_call_capability (Cap ret = Cap (0, alloc_cap ())):
|
||||
call (ret, CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
|
||||
icall (ret, CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
|
||||
return ret
|
||||
Cap create_async_call_capability (Cap ret = Cap (0, alloc_cap ())):
|
||||
call (ret, CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
|
||||
icall (ret, CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
|
||||
return ret
|
||||
|
||||
struct Thread : public Cap:
|
||||
@ -368,11 +367,11 @@ struct Thread : public Cap:
|
||||
RUNNING = 1 << 29
|
||||
USER_FLAGS = ~(PRIV | WAITING | RUNNING)
|
||||
void make_priv ():
|
||||
__my_thread.invoke (*this, CAP_MASTER_DIRECT | PRIV_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):
|
||||
invoke (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask))
|
||||
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):
|
||||
@ -397,12 +396,14 @@ struct Caps : public Cap:
|
||||
enum request:
|
||||
// Not an operation; this capability can be used in Thread::USE_SLOT.
|
||||
USE = 1
|
||||
PRINT
|
||||
unsigned use (unsigned slot = alloc_slot ()):
|
||||
__my_thread.use (*this, slot)
|
||||
return slot
|
||||
return __my_thread.use (*this, slot)
|
||||
void print (unsigned idx):
|
||||
invoke (CAP_MASTER_DIRECT | PRINT, idx)
|
||||
|
||||
unsigned Thread::use (Caps caps, unsigned slot):
|
||||
invoke (caps, CAP_MASTER_DIRECT | USE_SLOT, slot)
|
||||
ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot)
|
||||
return slot
|
||||
|
||||
struct Page : public Cap:
|
||||
@ -436,15 +437,15 @@ struct Page : public Cap:
|
||||
// This is a read-only flag, saying if this is uncachable memory.
|
||||
UNCACHED = 0x20
|
||||
void share (Cap target, unsigned flags):
|
||||
invoke (target, CAP_MASTER_DIRECT | SHARE, 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):
|
||||
invoke (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
|
||||
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
|
||||
unsigned physical_address ():
|
||||
return __my_thread.call (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
|
||||
return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
|
||||
void alloc_physical (unsigned address, bool cachable, bool freeable):
|
||||
__my_thread.invoke (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
|
||||
__my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
|
||||
|
||||
struct Memory : public Cap:
|
||||
Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
|
||||
@ -458,52 +459,56 @@ struct Memory : public Cap:
|
||||
GET_LIMIT
|
||||
SET_LIMIT
|
||||
Page create_page (Page ret = Cap (0, alloc_cap ())):
|
||||
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
|
||||
return ret
|
||||
Thread create_thread (unsigned slots, Thread ret = Cap (0, alloc_cap ())):
|
||||
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
|
||||
return ret
|
||||
Receiver create_receiver (Receiver ret = Cap (0, alloc_cap ())):
|
||||
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
|
||||
return ret
|
||||
Memory create_memory (Memory ret = Cap (0, alloc_cap ())):
|
||||
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
|
||||
return ret
|
||||
Caps create_caps (unsigned size, Caps ret = Cap (0, alloc_cap ())):
|
||||
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
|
||||
icall (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
|
||||
return ret
|
||||
void destroy (Cap target):
|
||||
invoke (target, CAP_MASTER_DIRECT | DESTROY)
|
||||
ocall (target, CAP_MASTER_DIRECT | DESTROY)
|
||||
// TODO: LIST
|
||||
void map (Cap page, unsigned address, bool readonly):
|
||||
void map (Cap page, unsigned address, bool readonly = false):
|
||||
if readonly:
|
||||
address |= Page::READONLY
|
||||
invoke (page, CAP_MASTER_DIRECT | MAP, address)
|
||||
ocall (page, CAP_MASTER_DIRECT | MAP, address)
|
||||
Page mapping (void *address, Page ret = Cap (0, alloc_cap ())):
|
||||
call (ret, CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
|
||||
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):
|
||||
invoke (CAP_MASTER_DIRECT | SET_LIMIT, limit)
|
||||
call (CAP_MASTER_DIRECT | SET_LIMIT, limit)
|
||||
unsigned alloc_range (unsigned pages):
|
||||
return __my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l
|
||||
|
||||
struct Kernel:
|
||||
static void wait (Cap::OMessage *o, unsigned islot = __tmp_slot):
|
||||
static void wait (Cap::OMessage *o, unsigned islot = ~0):
|
||||
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.invoke (__my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
|
||||
__my_thread.ocall (__my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
|
||||
static void unregister_interrupt (unsigned num):
|
||||
__my_thread.invoke (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
|
||||
static Cap get_top_memory ():
|
||||
__my_thread.call (__tmp_slot, CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
|
||||
return Cap (__tmp_slot, 0)
|
||||
static unsigned alloc_range (Cap memory, unsigned pages):
|
||||
__my_thread.call (memory, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages)
|
||||
__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
|
||||
|
||||
void Receiver::sleep (unsigned value, OMessage *ret, unsigned slot):
|
||||
__my_receiver.set_alarm (value)
|
||||
@ -516,6 +521,9 @@ void Receiver::sleep (unsigned value, OMessage *ret, unsigned slot):
|
||||
#define kdebug_char(c) do {} while (0)
|
||||
#endif
|
||||
#define kdebug(str) do { const char *s = (str); while (*s) { kdebug_char (*s); ++s; } } while (0)
|
||||
#define __stringify2(x) #x
|
||||
#define __stringify(x) __stringify2 (x)
|
||||
#define kdebug_line() do { kdebug (__stringify (__LINE__)); kdebug_char ('\n'); } while (0)
|
||||
|
||||
static void kdebug_num (unsigned n):
|
||||
unsigned i
|
||||
|
29
kernel.hhp
29
kernel.hhp
@ -51,7 +51,7 @@ struct kCapRef:
|
||||
kCapsP caps
|
||||
unsigned index
|
||||
inline kCapability *deref ()
|
||||
operator bool ():
|
||||
bool valid ():
|
||||
return deref () != NULL
|
||||
kCapability *operator-> ():
|
||||
return deref ()
|
||||
@ -167,7 +167,7 @@ struct kMemory : public kObject:
|
||||
unsigned limit, used
|
||||
kMemory_arch arch
|
||||
|
||||
inline bool map (kPage *page, unsigned address, bool write)
|
||||
inline bool map (kPage *page, unsigned address, bool readonly)
|
||||
inline void unmap (kPage *page, unsigned address)
|
||||
inline kPage *get_mapping (unsigned address, bool *readonly)
|
||||
|
||||
@ -199,15 +199,26 @@ struct kMemory : public kObject:
|
||||
|
||||
// Functions which can be called from assembly must not be mangled.
|
||||
extern "C":
|
||||
// Panic. n is sent over caps led. message is currently ignored.
|
||||
// Panic. n is sent over caps led. message is sent to dbg_caps (when in use).
|
||||
#define panic(n, m) panic_impl ((n), __LINE__, __PRETTY_FUNCTION__, (m))
|
||||
void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "")
|
||||
EXTERN unsigned dbg_code
|
||||
#ifndef NDEBUG
|
||||
EXTERN Num dbg_code
|
||||
EXTERN kCapRef dbg_cap
|
||||
void dbg_log_char (unsigned ch)
|
||||
void dbg_log (char const *str)
|
||||
void dbg_log_num (unsigned num)
|
||||
|
||||
#define panic(n, m) panic_impl ((n), __LINE__, __PRETTY_FUNCTION__, (m))
|
||||
void dbg_send (unsigned num, unsigned bits)
|
||||
void check (unsigned num, char const *msg)
|
||||
#define dpanic(n, msg) panic (n, msg)
|
||||
#else
|
||||
#define dbg_log_char(x) do {} while (0)
|
||||
#define dbg_log(x) do {} while (0)
|
||||
#define dbg_log_num(n) do {} while (0)
|
||||
#define dbg_send(n, m) do {} while (0)
|
||||
#define check (n, x) do {} while (0)
|
||||
#define dpanic(n, x) do {} while (0)
|
||||
#endif
|
||||
|
||||
/// Defined in schedule.ccp
|
||||
void schedule ()
|
||||
@ -220,7 +231,7 @@ EXTERN kMemory idle_memory
|
||||
EXTERN kPage idle_page
|
||||
EXTERN kThreadP first_scheduled
|
||||
EXTERN kThreadP current, old_current
|
||||
EXTERN bool do_schedule
|
||||
EXTERN bool do_schedule, must_wait
|
||||
|
||||
// Defined in memory.ccp
|
||||
unsigned init_memory (unsigned mem)
|
||||
@ -244,8 +255,8 @@ kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly)
|
||||
void kPage_arch_update_mapping (kPage *page)
|
||||
void arch_register_interrupt (unsigned num, kReceiverP r)
|
||||
|
||||
bool kMemory::map (kPage *page, unsigned address, bool write):
|
||||
return kMemory_arch_map (this, page, address, write)
|
||||
bool kMemory::map (kPage *page, unsigned address, bool readonly = false):
|
||||
return kMemory_arch_map (this, page, address, readonly)
|
||||
void kMemory::unmap (kPage *page, unsigned address):
|
||||
kMemory_arch_unmap (this, page, address)
|
||||
kPage *kMemory::get_mapping (unsigned address, bool *readonly):
|
||||
|
51
memory.ccp
51
memory.ccp
@ -29,6 +29,12 @@ unsigned phys_alloc (unsigned num):
|
||||
void phys_free (unsigned page, unsigned num):
|
||||
// Not supported.
|
||||
|
||||
#ifndef NDEBUG
|
||||
void check_impl (kObject *o, unsigned num, char const *msg):
|
||||
for ; o; o = o->next:
|
||||
if (unsigned)o >= (unsigned)free_begin && (unsigned)o < (unsigned)free_end:
|
||||
panic (num, msg)
|
||||
#endif
|
||||
#else
|
||||
|
||||
struct kFreePages:
|
||||
@ -51,20 +57,20 @@ unsigned phys_alloc (unsigned num):
|
||||
continue
|
||||
if choice && choice->num < p->num:
|
||||
continue
|
||||
if p->num == num:
|
||||
if p->prev:
|
||||
p->prev->next = p->next
|
||||
else:
|
||||
first_free = p->next
|
||||
if p->next:
|
||||
p->next->prev = p->prev
|
||||
clear_page ((unsigned)p, num)
|
||||
return (unsigned)p
|
||||
choice = p
|
||||
if !choice:
|
||||
// TODO: reorganizing may work to allow allocation.
|
||||
dbg_log ("range memory allocation failed")
|
||||
dpanic (0x03948859, "range memory allocation failed")
|
||||
return 0
|
||||
if choice->num == num:
|
||||
if choice->prev:
|
||||
choice->prev->next = choice->next
|
||||
else:
|
||||
first_free = choice->next
|
||||
if choice->next:
|
||||
choice->next->prev = choice->prev
|
||||
clear_page ((unsigned)choice, num)
|
||||
return (unsigned)choice
|
||||
choice->num -= num
|
||||
unsigned ret = (unsigned)choice + (choice->num << PAGE_BITS)
|
||||
clear_page (ret, num)
|
||||
@ -122,6 +128,28 @@ void phys_free (unsigned page, unsigned num):
|
||||
n->next->prev = n
|
||||
p->next = n
|
||||
n->num = num
|
||||
|
||||
#ifndef NDEBUG
|
||||
void check_impl (kObject *o, unsigned num, char const *msg):
|
||||
for ; o; o = (kObject *)o->next:
|
||||
for kFreePages *p = first_free; p; p = p->next:
|
||||
if (unsigned)o >= (unsigned)p && (unsigned)o < (unsigned)p + p->num * PAGE_SIZE:
|
||||
panic (num, msg)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
void check_memory (kMemory *mem, unsigned num, char const *msg):
|
||||
check_impl (mem->pages, num, msg)
|
||||
check_impl (mem->threads, num, msg)
|
||||
check_impl (mem->receivers, num, msg)
|
||||
check_impl (mem->capses, num, msg)
|
||||
check_impl (mem->memories, num, msg)
|
||||
for kMemory *m = mem->memories; m; m = (kMemory *)m->next:
|
||||
check_memory (m, num, msg)
|
||||
|
||||
void check (unsigned num, char const *msg):
|
||||
check_memory (&top_memory, num, msg)
|
||||
#endif
|
||||
|
||||
unsigned raw_zalloc ():
|
||||
@ -132,7 +160,8 @@ void raw_pfree (unsigned page):
|
||||
|
||||
unsigned kMemory::zalloc ():
|
||||
if !use ():
|
||||
dbg_log ("limit reached: allocation not allowed")
|
||||
dpanic (0x34638920, "limit reached: allocation not allowed")
|
||||
dbg_log ("limit reached: allocation not allowed\n")
|
||||
return NULL
|
||||
return raw_zalloc ()
|
||||
|
||||
|
@ -21,96 +21,85 @@
|
||||
|
||||
void kThread_arch_init (kThread *thread):
|
||||
thread->arch.at = 0
|
||||
thread->arch.v0 = 0
|
||||
thread->arch.v1 = 0
|
||||
thread->arch.a0 = 0
|
||||
thread->arch.a1 = 0
|
||||
thread->arch.a2 = 0
|
||||
thread->arch.a3 = 0
|
||||
thread->arch.t0 = 0
|
||||
thread->arch.t1 = 0
|
||||
thread->arch.t2 = 0
|
||||
thread->arch.t3 = 0
|
||||
thread->arch.t4 = 0
|
||||
thread->arch.t5 = 0
|
||||
thread->arch.t6 = 0
|
||||
thread->arch.t7 = 0
|
||||
thread->arch.t8 = 0
|
||||
thread->arch.t9 = 0
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
thread->arch.v[i] = 0
|
||||
thread->arch.k[i] = 0
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
thread->arch.a[i] = 0
|
||||
for unsigned i = 0; i < 10; ++i:
|
||||
thread->arch.t[i] = 0
|
||||
thread->arch.gp = 0
|
||||
thread->arch.fp = 0
|
||||
thread->arch.ra = 0
|
||||
thread->arch.hi = 0
|
||||
thread->arch.lo = 0
|
||||
thread->arch.k0 = 0
|
||||
thread->arch.k1 = 0
|
||||
|
||||
void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data):
|
||||
thread->arch.a0 = data[0].l
|
||||
thread->arch.a1 = data[0].h
|
||||
thread->arch.a2 = data[1].l
|
||||
thread->arch.a3 = data[1].h
|
||||
thread->arch.s0 = cap_protected.l
|
||||
thread->arch.s1 = cap_protected.h
|
||||
thread->arch.s2 = recv_protected.l
|
||||
thread->arch.s3 = recv_protected.h
|
||||
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
|
||||
|
||||
unsigned *kThread_arch_info (kThread *thread, unsigned num):
|
||||
switch num:
|
||||
case 1:
|
||||
return &thread->arch.at
|
||||
case 2:
|
||||
return &thread->arch.v0
|
||||
return &thread->arch.v[0]
|
||||
case 3:
|
||||
return &thread->arch.v1
|
||||
return &thread->arch.v[1]
|
||||
case 4:
|
||||
return &thread->arch.a0
|
||||
return &thread->arch.a[0]
|
||||
case 5:
|
||||
return &thread->arch.a1
|
||||
return &thread->arch.a[1]
|
||||
case 6:
|
||||
return &thread->arch.a2
|
||||
return &thread->arch.a[2]
|
||||
case 7:
|
||||
return &thread->arch.a3
|
||||
return &thread->arch.a[3]
|
||||
case 8:
|
||||
return &thread->arch.t0
|
||||
return &thread->arch.t[0]
|
||||
case 9:
|
||||
return &thread->arch.t1
|
||||
return &thread->arch.t[1]
|
||||
case 10:
|
||||
return &thread->arch.t2
|
||||
return &thread->arch.t[2]
|
||||
case 11:
|
||||
return &thread->arch.t3
|
||||
return &thread->arch.t[3]
|
||||
case 12:
|
||||
return &thread->arch.t4
|
||||
return &thread->arch.t[4]
|
||||
case 13:
|
||||
return &thread->arch.t5
|
||||
return &thread->arch.t[5]
|
||||
case 14:
|
||||
return &thread->arch.t6
|
||||
return &thread->arch.t[6]
|
||||
case 15:
|
||||
return &thread->arch.t7
|
||||
return &thread->arch.t[7]
|
||||
case 16:
|
||||
return &thread->arch.s0
|
||||
return &thread->arch.s[0]
|
||||
case 17:
|
||||
return &thread->arch.s1
|
||||
return &thread->arch.s[1]
|
||||
case 18:
|
||||
return &thread->arch.s2
|
||||
return &thread->arch.s[2]
|
||||
case 19:
|
||||
return &thread->arch.s3
|
||||
return &thread->arch.s[3]
|
||||
case 20:
|
||||
return &thread->arch.s4
|
||||
return &thread->arch.s[4]
|
||||
case 21:
|
||||
return &thread->arch.s5
|
||||
return &thread->arch.s[5]
|
||||
case 22:
|
||||
return &thread->arch.s6
|
||||
return &thread->arch.s[6]
|
||||
case 23:
|
||||
return &thread->arch.s7
|
||||
return &thread->arch.s[7]
|
||||
case 24:
|
||||
return &thread->arch.t8
|
||||
return &thread->arch.t[8]
|
||||
case 25:
|
||||
return &thread->arch.t9
|
||||
return &thread->arch.t[9]
|
||||
case 26:
|
||||
return &thread->arch.k0
|
||||
return &thread->arch.k[0]
|
||||
case 27:
|
||||
return &thread->arch.k1
|
||||
return &thread->arch.k[1]
|
||||
case 28:
|
||||
return &thread->arch.gp
|
||||
case 29:
|
||||
@ -205,6 +194,7 @@ static unsigned make_entry_lo (kPage *page, bool readonly):
|
||||
|
||||
bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address, bool readonly):
|
||||
if address >= 0x80000000:
|
||||
panic (0x32134293, "trying to map to kernel address")
|
||||
return false
|
||||
address &= PAGE_MASK
|
||||
if !mem->arch.directory:
|
||||
|
@ -72,47 +72,23 @@
|
||||
#define SAVE_PC (6 * 4)
|
||||
#define SAVE_SP (SAVE_PC + 4)
|
||||
#define SAVE_AT (SAVE_SP + 4)
|
||||
#define SAVE_V0 (SAVE_AT + 4)
|
||||
#define SAVE_V1 (SAVE_V0 + 4)
|
||||
#define SAVE_A0 (SAVE_V1 + 4)
|
||||
#define SAVE_A1 (SAVE_A0 + 4)
|
||||
#define SAVE_A2 (SAVE_A1 + 4)
|
||||
#define SAVE_A3 (SAVE_A2 + 4)
|
||||
#define SAVE_T0 (SAVE_A3 + 4)
|
||||
#define SAVE_T1 (SAVE_T0 + 4)
|
||||
#define SAVE_T2 (SAVE_T1 + 4)
|
||||
#define SAVE_T3 (SAVE_T2 + 4)
|
||||
#define SAVE_T4 (SAVE_T3 + 4)
|
||||
#define SAVE_T5 (SAVE_T4 + 4)
|
||||
#define SAVE_T6 (SAVE_T5 + 4)
|
||||
#define SAVE_T7 (SAVE_T6 + 4)
|
||||
#define SAVE_T8 (SAVE_T7 + 4)
|
||||
#define SAVE_T9 (SAVE_T8 + 4)
|
||||
#define SAVE_S0 (SAVE_T9 + 4)
|
||||
#define SAVE_S1 (SAVE_S0 + 4)
|
||||
#define SAVE_S2 (SAVE_S1 + 4)
|
||||
#define SAVE_S3 (SAVE_S2 + 4)
|
||||
#define SAVE_S4 (SAVE_S3 + 4)
|
||||
#define SAVE_S5 (SAVE_S4 + 4)
|
||||
#define SAVE_S6 (SAVE_S5 + 4)
|
||||
#define SAVE_S7 (SAVE_S6 + 4)
|
||||
#define SAVE_GP (SAVE_S7 + 4)
|
||||
#define SAVE_V (SAVE_AT + 4)
|
||||
#define SAVE_A (SAVE_V + 2 * 4)
|
||||
#define SAVE_T (SAVE_A + 4 * 4)
|
||||
#define SAVE_S (SAVE_T + 10 * 4)
|
||||
#define SAVE_GP (SAVE_S + 8 * 4)
|
||||
#define SAVE_FP (SAVE_GP + 4)
|
||||
#define SAVE_RA (SAVE_FP + 4)
|
||||
#define SAVE_HI (SAVE_RA + 4)
|
||||
#define SAVE_LO (SAVE_HI + 4)
|
||||
#define SAVE_K0 (SAVE_LO + 4)
|
||||
#define SAVE_K1 (SAVE_K0 + 4)
|
||||
#define SAVE_K (SAVE_LO + 4)
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
void flush_tlb (unsigned asid)
|
||||
|
||||
struct kThread_arch:
|
||||
unsigned at, v0, v1, a0, a1, a2, a3
|
||||
unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
|
||||
unsigned s0, s1, s2, s3, s4, s5, s6, s7
|
||||
unsigned gp, fp, ra, hi, lo, k0, k1
|
||||
unsigned at, v[2], a[4], t[10], s[8], gp, fp, ra, hi, lo, k[2]
|
||||
|
||||
// The following is used for page mapping.
|
||||
// Each Memory has a two directories with 0x400 entries,
|
||||
|
109
mips/entry.S
109
mips/entry.S
@ -118,49 +118,48 @@ start_idle: // 280
|
||||
// TODO: save only fragile registers now, the rest on task switch.
|
||||
kernel_exit:
|
||||
#ifndef NDEBUG
|
||||
// Allow interrupts to set EPC and friends.
|
||||
// Interrupts were enabled in the kernel; set them to usermode setting again.
|
||||
mfc0 $k0, $CP0_STATUS
|
||||
ori $k0, $k0, 0xff13
|
||||
mtc0 $k0, $CP0_STATUS
|
||||
#endif
|
||||
sw $v0, -0xd8c($zero)
|
||||
lw $k0, SAVE_PC($v0)
|
||||
mtc0 $k0, $CP0_EPC
|
||||
lw $k0, SAVE_LO($v0)
|
||||
lw $k1, SAVE_HI($v0)
|
||||
mtlo $k0
|
||||
mthi $k1
|
||||
lw $v1, SAVE_V1($v0)
|
||||
lw $a0, SAVE_A0($v0)
|
||||
lw $a1, SAVE_A1($v0)
|
||||
lw $a2, SAVE_A2($v0)
|
||||
lw $a3, SAVE_A3($v0)
|
||||
lw $t0, SAVE_T0($v0)
|
||||
lw $t1, SAVE_T1($v0)
|
||||
lw $t2, SAVE_T2($v0)
|
||||
lw $t3, SAVE_T3($v0)
|
||||
lw $t4, SAVE_T4($v0)
|
||||
lw $t5, SAVE_T5($v0)
|
||||
lw $t6, SAVE_T6($v0)
|
||||
lw $t7, SAVE_T7($v0)
|
||||
lw $t8, SAVE_T8($v0)
|
||||
lw $t9, SAVE_T9($v0)
|
||||
lw $s0, SAVE_S0($v0)
|
||||
lw $s1, SAVE_S1($v0)
|
||||
lw $s2, SAVE_S2($v0)
|
||||
lw $s3, SAVE_S3($v0)
|
||||
lw $s4, SAVE_S4($v0)
|
||||
lw $s5, SAVE_S5($v0)
|
||||
lw $s6, SAVE_S6($v0)
|
||||
lw $s7, SAVE_S7($v0)
|
||||
lw $v1, SAVE_V + 1 * 4($v0)
|
||||
lw $a0, SAVE_A + 0 * 4($v0)
|
||||
lw $a1, SAVE_A + 1 * 4($v0)
|
||||
lw $a2, SAVE_A + 2 * 4($v0)
|
||||
lw $a3, SAVE_A + 3 * 4($v0)
|
||||
lw $t0, SAVE_T + 0 * 4($v0)
|
||||
lw $t1, SAVE_T + 1 * 4($v0)
|
||||
lw $t2, SAVE_T + 2 * 4($v0)
|
||||
lw $t3, SAVE_T + 3 * 4($v0)
|
||||
lw $t4, SAVE_T + 4 * 4($v0)
|
||||
lw $t5, SAVE_T + 5 * 4($v0)
|
||||
lw $t6, SAVE_T + 6 * 4($v0)
|
||||
lw $t7, SAVE_T + 7 * 4($v0)
|
||||
lw $t8, SAVE_T + 8 * 4($v0)
|
||||
lw $t9, SAVE_T + 9 * 4($v0)
|
||||
lw $s0, SAVE_S + 0 * 4($v0)
|
||||
lw $s1, SAVE_S + 1 * 4($v0)
|
||||
lw $s2, SAVE_S + 2 * 4($v0)
|
||||
lw $s3, SAVE_S + 3 * 4($v0)
|
||||
lw $s4, SAVE_S + 4 * 4($v0)
|
||||
lw $s5, SAVE_S + 5 * 4($v0)
|
||||
lw $s6, SAVE_S + 6 * 4($v0)
|
||||
lw $s7, SAVE_S + 7 * 4($v0)
|
||||
lw $fp, SAVE_FP($v0)
|
||||
lw $ra, SAVE_RA($v0)
|
||||
lw $at, SAVE_AT($v0)
|
||||
lw $k0, SAVE_K0($v0)
|
||||
lw $k1, SAVE_V0($v0)
|
||||
lw $k0, SAVE_K + 0 * 4($v0)
|
||||
lw $k1, SAVE_V + 0 * 4($v0)
|
||||
sw $k1, -0xd90($zero)
|
||||
lw $k1, SAVE_K1($v0)
|
||||
sw $v0, -0xd8c($zero)
|
||||
|
||||
lw $k1, SAVE_K + 1 * 4($v0)
|
||||
lw $sp, SAVE_SP($v0)
|
||||
lw $gp, SAVE_GP($v0)
|
||||
lw $v0, -0xd90($zero)
|
||||
@ -175,36 +174,36 @@ save_regs:
|
||||
sw $sp, SAVE_SP($k0)
|
||||
sw $fp, SAVE_FP($k0)
|
||||
|
||||
sw $k1, SAVE_K1($k0)
|
||||
sw $k1, SAVE_K + 4($k0)
|
||||
lw $k1, -0xd90($zero)
|
||||
sw $k1, SAVE_K0($k0)
|
||||
sw $k1, SAVE_K + 0($k0)
|
||||
|
||||
lw $k1, -0xd88($zero)
|
||||
sw $k1, SAVE_RA($k0)
|
||||
sw $v0, SAVE_V0($k0)
|
||||
sw $v1, SAVE_V1($k0)
|
||||
sw $a0, SAVE_A0($k0)
|
||||
sw $a1, SAVE_A1($k0)
|
||||
sw $a2, SAVE_A2($k0)
|
||||
sw $a3, SAVE_A3($k0)
|
||||
sw $t0, SAVE_T0($k0)
|
||||
sw $t1, SAVE_T1($k0)
|
||||
sw $t2, SAVE_T2($k0)
|
||||
sw $t3, SAVE_T3($k0)
|
||||
sw $t4, SAVE_T4($k0)
|
||||
sw $t5, SAVE_T5($k0)
|
||||
sw $t6, SAVE_T6($k0)
|
||||
sw $t7, SAVE_T7($k0)
|
||||
sw $t8, SAVE_T8($k0)
|
||||
sw $t9, SAVE_T9($k0)
|
||||
sw $s0, SAVE_S0($k0)
|
||||
sw $s1, SAVE_S1($k0)
|
||||
sw $s2, SAVE_S2($k0)
|
||||
sw $s3, SAVE_S3($k0)
|
||||
sw $s4, SAVE_S4($k0)
|
||||
sw $s5, SAVE_S5($k0)
|
||||
sw $s6, SAVE_S6($k0)
|
||||
sw $s7, SAVE_S7($k0)
|
||||
sw $v0, SAVE_V + 0 * 4($k0)
|
||||
sw $v1, SAVE_V + 1 * 4($k0)
|
||||
sw $a0, SAVE_A + 0 * 4($k0)
|
||||
sw $a1, SAVE_A + 1 * 4($k0)
|
||||
sw $a2, SAVE_A + 2 * 4($k0)
|
||||
sw $a3, SAVE_A + 3 * 4($k0)
|
||||
sw $t0, SAVE_T + 0 * 4($k0)
|
||||
sw $t1, SAVE_T + 1 * 4($k0)
|
||||
sw $t2, SAVE_T + 2 * 4($k0)
|
||||
sw $t3, SAVE_T + 3 * 4($k0)
|
||||
sw $t4, SAVE_T + 4 * 4($k0)
|
||||
sw $t5, SAVE_T + 5 * 4($k0)
|
||||
sw $t6, SAVE_T + 6 * 4($k0)
|
||||
sw $t7, SAVE_T + 7 * 4($k0)
|
||||
sw $t8, SAVE_T + 8 * 4($k0)
|
||||
sw $t9, SAVE_T + 9 * 4($k0)
|
||||
sw $s0, SAVE_S + 0 * 4($k0)
|
||||
sw $s1, SAVE_S + 1 * 4($k0)
|
||||
sw $s2, SAVE_S + 2 * 4($k0)
|
||||
sw $s3, SAVE_S + 3 * 4($k0)
|
||||
sw $s4, SAVE_S + 4 * 4($k0)
|
||||
sw $s5, SAVE_S + 5 * 4($k0)
|
||||
sw $s6, SAVE_S + 6 * 4($k0)
|
||||
sw $s7, SAVE_S + 7 * 4($k0)
|
||||
mfhi $v0
|
||||
mflo $v1
|
||||
sw $v0, SAVE_HI($k0)
|
||||
|
@ -22,6 +22,10 @@
|
||||
#include "../kernel.hh"
|
||||
#include <elf.h>
|
||||
|
||||
#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.
|
||||
idle.prev = NULL
|
||||
@ -111,7 +115,7 @@ static void init_threads ():
|
||||
for unsigned i = 0; i < NUM_THREADS; ++i:
|
||||
kMemory *mem = top_memory.alloc_memory ()
|
||||
assert (mem)
|
||||
kThread *thread = mem->alloc_thread (3)
|
||||
kThread *thread = mem->alloc_thread (NUM_SLOTS)
|
||||
kPage **pages = (kPage **)mem->zalloc ()
|
||||
Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i]
|
||||
for unsigned j = 0; j < SELFMAG; ++j:
|
||||
@ -174,7 +178,7 @@ static void init_threads ():
|
||||
panic (0x02220022, "out of memory");
|
||||
return
|
||||
page->flags = Page::PAYING | Page::FRAME
|
||||
if !mem->map (page, p, true):
|
||||
if !mem->map (page, p):
|
||||
panic (0x33557799, "unable to map initial bss page")
|
||||
return
|
||||
else:
|
||||
@ -195,10 +199,13 @@ static void init_threads ():
|
||||
kPage *stackpage = mem->alloc_page ()
|
||||
stackpage->frame = mem->zalloc ()
|
||||
stackpage->flags = Page::PAYING | Page::FRAME
|
||||
if !stackpage || !mem->map (stackpage, 0x7ffff000, true):
|
||||
if !stackpage || !mem->map (stackpage, 0x7ffff000):
|
||||
panic (0x13151719, "unable to map initial stack page")
|
||||
return
|
||||
thread->caps[0] = mem->alloc_caps (16)
|
||||
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
|
||||
@ -220,7 +227,10 @@ static void init_threads ():
|
||||
|
||||
// Initialize the kernel, finish by falling into the idle task.
|
||||
void init (unsigned mem):
|
||||
#ifndef NDEBUG
|
||||
dbg_code = 0
|
||||
#endif
|
||||
must_wait = false
|
||||
// Disable interrupts and set interrupt vectors to normal.
|
||||
cp0_set0 (CP0_STATUS)
|
||||
// Initialize kernel variables to empty.
|
||||
|
@ -25,6 +25,8 @@ void arch_flush_cache ():
|
||||
__asm__ volatile ("lw $k0, %0; cache 0, 0($k0); cache 1, 0($k0)" :: "m"(line))
|
||||
|
||||
static void handle_exit ():
|
||||
// Set must_wait to false, so random threads are not set to waiting when the kernel invokes something (such as a dbg_cap).
|
||||
must_wait = false
|
||||
if !current || (current == &idle):
|
||||
schedule ()
|
||||
if !current:
|
||||
@ -35,6 +37,7 @@ static void handle_exit ():
|
||||
current = &idle
|
||||
if old_current == current:
|
||||
return
|
||||
//dbg_send ((unsigned)current >> 12, 3)
|
||||
arch_flush_cache ()
|
||||
if current != &idle:
|
||||
if (kMemory *)asids[current->address_space->arch.asid] != current->address_space:
|
||||
@ -124,40 +127,40 @@ void flush_tlb (unsigned asid):
|
||||
|
||||
static void arch_invoke ():
|
||||
kCapRef target
|
||||
bool wait
|
||||
target = old_current->find_capability (old_current->arch.v0, &wait)
|
||||
target = old_current->find_capability (old_current->arch.v[0], &must_wait)
|
||||
do_schedule = false
|
||||
kCapability::Context msg
|
||||
unsigned num = old_current->arch.s2
|
||||
unsigned first = old_current->arch.s3
|
||||
if num:
|
||||
if num > 10:
|
||||
num = 10
|
||||
bool copy
|
||||
if old_current->arch.s1 < old_current->slots:
|
||||
msg.caps = old_current->caps[old_current->arch.s1]
|
||||
if msg.caps && first < msg.caps->size:
|
||||
for unsigned i = first; i < num && i < msg.caps->size; ++i:
|
||||
msg.caps->cap (i)->invalidate ()
|
||||
kCapRef t = old_current->find_capability ((&old_current->arch.t0)[i], ©)
|
||||
if t:
|
||||
msg.caps->clone (i, t, copy)
|
||||
else:
|
||||
msg.caps = NULL
|
||||
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
|
||||
if wait:
|
||||
old_current->recv_slot = old_current->arch.s0
|
||||
old_current->wait ()
|
||||
if !target:
|
||||
if (old_current->arch.v0 & ~CAP_COPY) != ~CAP_COPY:
|
||||
panic (old_current->arch.v0, "debug")
|
||||
// There must be no action here.
|
||||
if must_wait:
|
||||
old_current->recv_slot = old_current->arch.s[0]
|
||||
if !target.valid ():
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
return
|
||||
msg.data[0] = Num (old_current->arch.a0, old_current->arch.a1)
|
||||
msg.data[1] = Num (old_current->arch.a2, old_current->arch.a3)
|
||||
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])
|
||||
target->invoke (&msg)
|
||||
if do_schedule && !wait:
|
||||
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:
|
||||
@ -216,28 +219,35 @@ kThread *exception ():
|
||||
// Syscall.
|
||||
current->pc += 4
|
||||
arch_invoke ()
|
||||
//check (0x88392883, "check error")
|
||||
break
|
||||
case 9:
|
||||
// Breakpoint.
|
||||
#if 0
|
||||
current->raise (ERR_BREAKPOINT, 0)
|
||||
#if 0 || defined (NDEBUG)
|
||||
//current->raise (ERR_BREAKPOINT, 0)
|
||||
#ifndef NDEBUG
|
||||
current->pc += 4
|
||||
#endif
|
||||
#else
|
||||
current->pc += 4
|
||||
if current->arch.a0:
|
||||
if dbg_cap:
|
||||
panic (0, "Break instruction while log capability was already set")
|
||||
if current->arch.a[0]:
|
||||
if dbg_cap.valid ():
|
||||
dpanic (0, "Break instruction while log capability was already set")
|
||||
break
|
||||
bool dummy
|
||||
dbg_cap = current->find_capability (current->arch.a1, &dummy)
|
||||
if !dbg_cap:
|
||||
panic (0, "no log capability provided")
|
||||
dbg_cap = current->find_capability (current->arch.a[1], &dummy)
|
||||
if !dbg_cap.valid ():
|
||||
dpanic (0, "no log capability provided")
|
||||
break
|
||||
dbg_log ("debug capability registered. thread = ")
|
||||
dbg_log_num ((unsigned)current)
|
||||
dbg_log_char ('\n')
|
||||
break
|
||||
if dbg_cap:
|
||||
dbg_log_char (current->arch.a1)
|
||||
if dbg_cap.valid ():
|
||||
dbg_log_char (current->arch.a[1])
|
||||
break
|
||||
break
|
||||
#endif
|
||||
break
|
||||
case 10:
|
||||
// Reserved instruction.
|
||||
current->raise (ERR_RESERVED_INSTRUCTION, 0)
|
||||
|
@ -140,9 +140,9 @@
|
||||
static void __map_io (unsigned physical, unsigned mapping):
|
||||
Page p = __my_memory.create_page ()
|
||||
// false means not cachable; false means don't free when done.
|
||||
p.alloc_physical (physical, 0, 0)
|
||||
// true means writable.
|
||||
__my_memory.map (p, mapping, true)
|
||||
p.alloc_physical (physical, false, false)
|
||||
__my_memory.map (p, mapping)
|
||||
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)
|
||||
|
47
panic.ccp
47
panic.ccp
@ -19,18 +19,14 @@
|
||||
#define ARCH
|
||||
#include "kernel.hh"
|
||||
|
||||
#if 0
|
||||
void dbg_log_char (unsigned ch):
|
||||
if !dbg_cap:
|
||||
if !dbg_cap.valid ():
|
||||
return
|
||||
Capability::Context c
|
||||
c->recv_memory = NULL
|
||||
c->caps = NULL
|
||||
kCapability::Context c
|
||||
c.caps = NULL
|
||||
c.data[0] = ch
|
||||
c.data[1] = 0
|
||||
dbg_cap->invoke (&c)
|
||||
if dbg_cap->target->owner:
|
||||
current = dbg_cap->target->owner
|
||||
|
||||
void dbg_log (char const *str):
|
||||
while *str:
|
||||
@ -42,26 +38,27 @@ void dbg_log_num (unsigned num):
|
||||
dbg_log_char (encode[(num >> (4 * (7 - i))) & 0xf])
|
||||
return
|
||||
|
||||
#if 1 || defined (NDEBUG)
|
||||
void panic_impl (unsigned n, unsigned line, char const *name, char const *message):
|
||||
Thread *who = current
|
||||
// Stop all threads.
|
||||
while first_scheduled:
|
||||
first_scheduled->unrun ()
|
||||
for Receiver *r = first_alarm; r; r = r->next_alarm:
|
||||
for kReceiver *r = first_alarm; r; r = r->next_alarm:
|
||||
if r->owner:
|
||||
r->owner->unrun ()
|
||||
for unsigned i = 0; i < 32; ++i:
|
||||
if arch_interrupt_receiver[i] && arch_interrupt_receiver[i]->owner:
|
||||
arch_interrupt_receiver[i]->owner->unrun ()
|
||||
#ifndef NDEBUG
|
||||
// If a log capability is registered, run its owner.
|
||||
if dbg_cap && dbg_cap->target->owner:
|
||||
if dbg_cap.valid () && dbg_cap->target->owner:
|
||||
dbg_cap->target->owner->run ()
|
||||
// Use the (now running) log thread to display the message.
|
||||
dbg_log ("Panic: current = ")
|
||||
dbg_log_num ((unsigned)who)
|
||||
if who:
|
||||
dbg_log ("Panic: caller = ")
|
||||
dbg_log_num ((unsigned)old_current)
|
||||
if old_current:
|
||||
dbg_log_char ('@')
|
||||
dbg_log_num ((unsigned)who->pc)
|
||||
dbg_log_num (old_current->pc)
|
||||
dbg_log ("; ")
|
||||
dbg_log (name)
|
||||
dbg_log_char (':')
|
||||
@ -72,6 +69,15 @@ void panic_impl (unsigned n, unsigned line, char const *name, char const *messag
|
||||
dbg_log_num (n)
|
||||
dbg_log_char ('\n')
|
||||
// If no log capability is registered, the machine just hangs.
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
void dbg_send (unsigned num, unsigned bits):
|
||||
dbg_log ("Warning: ")
|
||||
dbg_log_num (num)
|
||||
dbg_log_char ('/')
|
||||
dbg_log_num (bits)
|
||||
dbg_log_char ('\n')
|
||||
#endif
|
||||
#else
|
||||
void delay (unsigned ms):
|
||||
for unsigned t = 0; t < 8000 * ms; ++t:
|
||||
@ -89,12 +95,9 @@ void set_leds (bool a, bool b):
|
||||
else:
|
||||
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
|
||||
|
||||
void dbg_log_char (unsigned ch):
|
||||
void dbg_log (char const *str):
|
||||
void dbg_log_num (unsigned num):
|
||||
static void send (unsigned n):
|
||||
for unsigned i = 0; i < 32; ++i:
|
||||
bool v = n & (1 << 31)
|
||||
void dbg_send (unsigned n, unsigned bits):
|
||||
for unsigned i = 0; i < bits; ++i:
|
||||
bool v = n & (1 << (bits - 1))
|
||||
set_leds (v, !v)
|
||||
delay (350)
|
||||
set_leds (false, false)
|
||||
@ -107,7 +110,7 @@ static void send (unsigned n):
|
||||
void panic_impl (unsigned n, unsigned line, char const *name, char const *message):
|
||||
unsigned epc
|
||||
cp0_get (CP0_EPC, epc)
|
||||
send (epc)
|
||||
dbg_send (epc, 32)
|
||||
while true:
|
||||
send (n)
|
||||
dbg_send (n, 32)
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user