1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-01 00:44:31 +03:00

new stuff almost working

This commit is contained in:
Bas Wijnen 2009-08-24 21:02:35 +02:00
parent ebdc68a9d8
commit 418f6c6594
18 changed files with 651 additions and 495 deletions

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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
View File

@ -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

View File

@ -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):

View File

@ -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 ()

View File

@ -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:

View File

@ -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,

View File

@ -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)

View File

@ -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.

View File

@ -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], &copy)
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, &copy)
if t.valid ():
msg.caps->clone (first + i, t, copy)
else:
if num:
dpanic (0x34566244, "num without caps")
if old_current->arch.s[1] != ~0:
dpanic (0x28849932, "non-~0 slot too high")
msg.caps = NULL
if 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)

View File

@ -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)

View File

@ -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