mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-11-16 20:44:05 +02:00
688 lines
20 KiB
Plaintext
688 lines
20 KiB
Plaintext
#pypp 0
|
|
// Iris: micro-kernel for a capability-based operating system.
|
|
// iris.hhp: header file for userspace programs.
|
|
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#ifndef __IRIS_HHP
|
|
#define __IRIS_HHP
|
|
|
|
// Without the standard library, we don't have this definition.
|
|
// I preferred ((void*)0), but C++ has too strict type-checking to
|
|
// make that work.
|
|
#ifndef NULL
|
|
#define NULL 0
|
|
#endif
|
|
|
|
// Number of clock interrupts per second.
|
|
#define HZ 100
|
|
|
|
#define PAGE_BITS (12)
|
|
#define PAGE_SIZE (1 << PAGE_BITS)
|
|
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
|
|
|
#define KERNEL_MASK 0xfff
|
|
#define CAPTYPE_MASK 0xe00
|
|
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
|
|
#define CAPTYPE_INVALID 0x000
|
|
#define CAPTYPE_RECEIVER 0x200
|
|
#define CAPTYPE_MEMORY 0x400
|
|
#define CAPTYPE_THREAD 0x600
|
|
#define CAPTYPE_PAGE 0x800
|
|
#define CAPTYPE_CAPS 0xa00
|
|
#define CAPTYPE_LIST 0xc00
|
|
#define CAPTYPE_LISTITEM 0xe00
|
|
|
|
// All kernel capabilities have a master capability, which can create others.
|
|
#define CAP_MASTER 0
|
|
|
|
// Create, invoke and forget, with masked data set to 0.
|
|
#define CAP_MASTER_DIRECT 0
|
|
// Master capabilities can create others.
|
|
#define CAP_MASTER_CREATE (1 << 31)
|
|
|
|
#define __caps_num 0
|
|
#define __receiver_num 1
|
|
#define __thread_num 2
|
|
#define __memory_num 3
|
|
#define __call_num 4
|
|
#define __parent_num 5
|
|
|
|
// If this flag is set in a capability, it is copied instead of mapped.
|
|
// If it is set in the target capability, the Thread waits after the request.
|
|
#define CAP_COPY ((unsigned)0x80000000)
|
|
// This constant signifies that no capability is passed.
|
|
#define CAP_NONE (~CAP_COPY)
|
|
|
|
namespace Iris:
|
|
struct Parent
|
|
enum Exception_code:
|
|
NO_ERROR
|
|
ERR_WRITE_DENIED
|
|
ERR_UNMAPPED_READ
|
|
ERR_UNMAPPED_WRITE
|
|
ERR_INVALID_ADDRESS_READ
|
|
ERR_INVALID_ADDRESS_WRITE
|
|
ERR_RESERVED_INSTRUCTION
|
|
ERR_COPROCESSOR_UNUSABLE
|
|
ERR_OVERFLOW
|
|
ERR_TRAP
|
|
ERR_WATCHPOINT
|
|
ERR_BREAKPOINT
|
|
ERR_NO_PAGE_DIRECTORY
|
|
ERR_NO_PAGE_TABLE
|
|
ERR_OUT_OF_MEMORY
|
|
// The following are not raised, but returned.
|
|
ERR_INVALID_OPERATION
|
|
ERR_INVALID_ARGUMENT
|
|
NUM_EXCEPTION_CODES
|
|
|
|
#ifndef NDEBUG
|
|
static const char *exception_name[NUM_EXCEPTION_CODES] = {
|
|
"no error",
|
|
"write denied",
|
|
"unmapped read",
|
|
"unmapped write",
|
|
"invalid address read",
|
|
"invalid address write",
|
|
"reserved instruction",
|
|
"coprocessor unusable",
|
|
"overflow",
|
|
"trap",
|
|
"watchpoint",
|
|
"breakpoint",
|
|
"no page directory",
|
|
"no page table",
|
|
"out of memory",
|
|
"invalid operation"
|
|
}
|
|
#endif
|
|
|
|
struct Num:
|
|
unsigned l, h
|
|
Num (unsigned long long n = 0) : l (n), h (n >> 32):
|
|
Num (unsigned ll, unsigned hh) : l (ll), h (hh):
|
|
unsigned long long value () const:
|
|
return ((unsigned long long)h << 32) | l
|
|
unsigned &low ():
|
|
return l
|
|
unsigned &high ():
|
|
return h
|
|
unsigned const &low () const:
|
|
return l
|
|
unsigned const &high () const:
|
|
return h
|
|
|
|
struct Cap
|
|
struct Caps
|
|
struct Receiver
|
|
struct Thread
|
|
struct Page
|
|
struct Memory
|
|
struct List
|
|
|
|
void print_caps ()
|
|
unsigned alloc_slot ()
|
|
Cap alloc_cap ()
|
|
void free_slot (unsigned slot)
|
|
void free_cap (Cap cap)
|
|
extern bool enable_debug
|
|
|
|
struct Cap:
|
|
unsigned code
|
|
inline Cap copy () const
|
|
inline Cap ()
|
|
explicit inline Cap (unsigned c)
|
|
inline Cap (unsigned slot, unsigned idx)
|
|
inline unsigned slot () const
|
|
inline unsigned idx () const
|
|
struct IMessage
|
|
inline void invoke (Num d0 = 0, Num d1 = 0, Cap arg = Cap (CAP_NONE))
|
|
inline Num call (Num d0 = 0, Num d1 = 0)
|
|
inline Num icall (Num d0 = 0, Num d1 = 0)
|
|
inline Num ocall (Cap c, Num d0 = 0, Num d1 = 0)
|
|
inline Num iocall (Cap c, Num d0 = 0, Num d1 = 0)
|
|
inline void _invoke (IMessage const *i)
|
|
inline void _call (IMessage *i)
|
|
|
|
struct __recv_data_t:
|
|
Num data[2]
|
|
Num protected_data
|
|
Cap reply, arg
|
|
|
|
extern Caps my_caps
|
|
extern Receiver my_receiver
|
|
extern Thread my_thread
|
|
extern Memory my_memory
|
|
extern Cap my_call
|
|
extern Parent my_parent
|
|
extern __recv_data_t recv
|
|
|
|
inline Cap get_reply ():
|
|
Cap ret = recv.reply
|
|
recv.reply = alloc_cap ()
|
|
return ret
|
|
inline Cap get_arg ():
|
|
Cap ret = recv.arg
|
|
recv.arg = alloc_cap ()
|
|
return ret
|
|
inline void set_recv_arg (Cap c):
|
|
free_cap (recv.arg)
|
|
recv.arg = c
|
|
|
|
struct Cap::IMessage:
|
|
Num data[2]
|
|
Cap reply, arg
|
|
Cap Cap::copy () const:
|
|
return Cap (code | CAP_COPY)
|
|
Cap::Cap () : code (CAP_NONE):
|
|
Cap::Cap (unsigned c) : code (c):
|
|
Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)):
|
|
unsigned Cap::slot () const:
|
|
return (code >> 16) & 0x7fff
|
|
unsigned Cap::idx () const:
|
|
return code & 0xffff
|
|
void Cap::_invoke (IMessage const *i):
|
|
__recv_data_t *r = &recv
|
|
__asm__ volatile ("lw $v0, %1\n"
|
|
"\tlw $a0, 0($v0)\n"
|
|
"\tlw $a1, 4($v0)\n"
|
|
"\tlw $a2, 8($v0)\n"
|
|
"\tlw $a3, 12($v0)\n"
|
|
"\tlw $t0, 16($v0)\n"
|
|
"\tlw $t1, 20($v0)\n"
|
|
"\tlw $v0, %2\n"
|
|
"\tlw $t2, 24($v0)\n"
|
|
"\tlw $t3, 28($v0)\n"
|
|
"\tlw $v0, %0\n"
|
|
"\tsyscall\n"
|
|
"\tlw $v0, %2\n"
|
|
"\tsw $a0, 0($v0)\n"
|
|
"\tsw $a1, 4($v0)\n"
|
|
"\tsw $a2, 8($v0)\n"
|
|
"\tsw $a3, 12($v0)\n"
|
|
"\tsw $t0, 16($v0)\n"
|
|
"\tsw $t1, 20($v0)"
|
|
:: "m"(code), "m"(i), "m"(r)
|
|
: "memory", "v0", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3")
|
|
void Cap::_call (IMessage *i):
|
|
i->reply = *this
|
|
my_call.copy ()._invoke (i)
|
|
void Cap::invoke (Num d0, Num d1, Cap arg):
|
|
IMessage i
|
|
i.data[0] = d0
|
|
i.data[1] = d1
|
|
i.reply = Cap (CAP_NONE)
|
|
i.arg = arg
|
|
_invoke (&i)
|
|
Num Cap::call (Num d0, Num d1):
|
|
IMessage i
|
|
i.data[0] = d0
|
|
i.data[1] = d1
|
|
i.arg = Cap (CAP_NONE)
|
|
_call (&i)
|
|
return recv.data[0]
|
|
Num Cap::icall (Num d0, Num d1):
|
|
IMessage i
|
|
i.data[0] = d0
|
|
i.data[1] = d1
|
|
i.arg = Cap (CAP_NONE)
|
|
_call (&i)
|
|
return recv.data[0]
|
|
Num Cap::ocall (Cap c, Num d0, Num d1):
|
|
IMessage i
|
|
i.data[0] = d0
|
|
i.data[1] = d1
|
|
i.arg = c
|
|
_call (&i)
|
|
return recv.data[0]
|
|
Num Cap::iocall (Cap c, Num d0, Num d1):
|
|
IMessage i
|
|
i.data[0] = d0
|
|
i.data[1] = d1
|
|
i.arg = c
|
|
_call (&i)
|
|
return recv.data[0]
|
|
|
|
struct Receiver : public Cap:
|
|
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
|
|
Receiver (Cap c = Cap ()) : Cap (c):
|
|
enum request:
|
|
// Operations
|
|
SET_OWNER = CAPTYPE_RECEIVER + 1
|
|
CREATE_CAPABILITY
|
|
CREATE_CALL_CAPABILITY
|
|
CREATE_ASYNC_CALL_CAPABILITY
|
|
GET_PROTECTED
|
|
GET_REPLY_PROTECTED_DATA
|
|
SET_REPLY_PROTECTED_DATA
|
|
GET_ALARM
|
|
SET_ALARM
|
|
ADD_ALARM
|
|
// Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability.
|
|
REPLY
|
|
// A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY.
|
|
CALL
|
|
// A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY.
|
|
CALL_ASYNC
|
|
void set_owner (Cap owner):
|
|
ocall (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
|
|
Cap create_capability (Num protected_data):
|
|
icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
|
|
return get_arg ()
|
|
Num get_protected (Cap target):
|
|
return ocall (target, CAP_MASTER_DIRECT | GET_PROTECTED)
|
|
Num get_reply_protected_data ():
|
|
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
|
|
void set_reply_protected_data (Num data):
|
|
call (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data)
|
|
unsigned get_alarm ():
|
|
return call (CAP_MASTER_DIRECT | GET_ALARM).l
|
|
unsigned add_alarm (unsigned data):
|
|
return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
|
|
void set_alarm (unsigned data):
|
|
call (CAP_MASTER_DIRECT | SET_ALARM, data)
|
|
inline void sleep (unsigned value)
|
|
Cap create_call_capability ():
|
|
icall (CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
|
|
return get_arg ()
|
|
Cap create_async_call_capability ():
|
|
icall (CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
|
|
return get_arg ()
|
|
|
|
struct Thread : public Cap:
|
|
Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
|
|
Thread (Cap c = Cap ()) : Cap (c):
|
|
enum request:
|
|
// Info details are arch-specific.
|
|
GET_INFO = CAPTYPE_THREAD + 1
|
|
SET_INFO
|
|
USE_SLOT
|
|
GET_CAPS
|
|
SCHEDULE
|
|
PRIV_ALLOC_RANGE
|
|
PRIV_PHYSICAL_ADDRESS
|
|
PRIV_ALLOC_PHYSICAL
|
|
PRIV_MAKE_PRIV
|
|
PRIV_GET_TOP_MEMORY
|
|
PRIV_REGISTER_INTERRUPT
|
|
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
|
|
SET_OWNER
|
|
DBG_SEND
|
|
PRIV_REBOOT
|
|
PRIV_POWEROFF
|
|
PRIV_SUSPEND
|
|
PRIV_BOOT
|
|
PRIV_PANIC
|
|
// These get/set_info are not arch-specific.
|
|
enum info_type:
|
|
PC = ~0
|
|
SP = ~1
|
|
FLAGS = ~2
|
|
// These are arch-specific.
|
|
AT = 1
|
|
V0
|
|
V1
|
|
A0
|
|
A1
|
|
A2
|
|
A3
|
|
T0
|
|
T1
|
|
T2
|
|
T3
|
|
T4
|
|
T5
|
|
T6
|
|
T7
|
|
S0
|
|
S1
|
|
S2
|
|
S3
|
|
S4
|
|
S5
|
|
S6
|
|
S7
|
|
T8
|
|
T9
|
|
K0
|
|
K1
|
|
GP
|
|
SP_
|
|
FP
|
|
RA
|
|
enum flags:
|
|
PRIV = 1 << 31
|
|
WAITING = 1 << 30
|
|
RUNNING = 1 << 29
|
|
USER_FLAGS = ~(PRIV | WAITING | RUNNING)
|
|
void make_priv ():
|
|
my_thread.ocall (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV)
|
|
unsigned get_info (unsigned info):
|
|
return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l
|
|
void set_info (unsigned info, unsigned value, unsigned mask = ~0):
|
|
call (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask))
|
|
void set_pc (unsigned pc):
|
|
set_info (PC, pc)
|
|
void set_sp (unsigned sp):
|
|
set_info (SP, sp)
|
|
void set_flags (unsigned set, unsigned reset = 0):
|
|
set_info (FLAGS, set, set | reset)
|
|
unsigned get_pc ():
|
|
return get_info (PC)
|
|
unsigned get_sp ():
|
|
return get_info (SP)
|
|
unsigned get_flags ():
|
|
return get_info (FLAGS)
|
|
void run (bool run = true):
|
|
set_flags (run ? RUNNING : 0, run ? 0 : RUNNING)
|
|
void wait (bool wait):
|
|
set_flags (wait ? WAITING : 0, wait ? 0 : WAITING)
|
|
inline unsigned use (Caps caps, unsigned slot = alloc_slot ())
|
|
inline Caps get_caps (unsigned slot)
|
|
unsigned get_num_caps ():
|
|
return call (CAP_MASTER_DIRECT | GET_CAPS, ~0).l
|
|
|
|
struct Caps : public Cap:
|
|
Caps (unsigned slot, unsigned idx) : Cap (slot, idx):
|
|
Caps (Cap c = Cap ()) : Cap (c):
|
|
enum request:
|
|
// Not an operation; this capability can be used in Thread::USE_SLOT.
|
|
USE = CAPTYPE_CAPS + 1
|
|
GET
|
|
GET_SIZE
|
|
SET
|
|
TRUNCATE
|
|
PRINT
|
|
unsigned use (unsigned slot = alloc_slot ()):
|
|
return my_thread.use (*this, slot)
|
|
Cap get (unsigned idx):
|
|
call (CAP_MASTER_DIRECT | GET, idx)
|
|
return get_arg ()
|
|
unsigned get_size ():
|
|
return call (CAP_MASTER_DIRECT | GET_SIZE).l
|
|
void set (unsigned idx, Cap cap):
|
|
ocall (cap, CAP_MASTER_DIRECT | SET, idx)
|
|
void truncate (unsigned new_size):
|
|
call (CAP_MASTER_DIRECT | TRUNCATE, new_size)
|
|
void print (unsigned idx):
|
|
invoke (CAP_MASTER_DIRECT | PRINT, idx)
|
|
|
|
Caps Thread::get_caps (unsigned slot):
|
|
call (CAP_MASTER_DIRECT | GET_CAPS, slot)
|
|
return get_arg ()
|
|
|
|
unsigned Thread::use (Caps caps, unsigned slot):
|
|
ocall (caps, CAP_MASTER_DIRECT | USE_SLOT, slot)
|
|
return slot
|
|
|
|
struct Page : public Cap:
|
|
Page (unsigned slot, unsigned idx) : Cap (slot, idx):
|
|
Page (Cap c = Cap ()) : Cap (c):
|
|
enum request:
|
|
SHARE = CAPTYPE_PAGE + 1
|
|
GET_FLAGS
|
|
SET_FLAGS
|
|
// Not an operation; a capability with this bit cannot write to the page.
|
|
READONLY = 8
|
|
enum share_detail:
|
|
// Operation details for PAGE_SHARE
|
|
// Forget the source page during the operation. This makes it a move.
|
|
FORGET = 1
|
|
// Make the target independent of the source (make a copy if needed).
|
|
COPY = 2
|
|
// Make the target unwritable.
|
|
//READONLY: use the value from request.
|
|
enum flag_values:
|
|
// This is a read-only flag, which is set if the Page is shared.
|
|
SHARED = 1
|
|
// When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them.
|
|
PAYING = 2
|
|
// Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems.
|
|
FRAME = 4
|
|
// A readonly page cannot be written to. This flag can not be reset while the frame is shared. The flag is already defined in request.
|
|
//READONLY = 8
|
|
// If this flag is set, the page is or will be mapped read-only.
|
|
MAPPED_READONLY = 0x10
|
|
// This is a read-only flag, saying if this is physical memory, which mustn't be freed.
|
|
PHYSICAL = 0x20
|
|
// This is a read-only flag, saying if this is uncachable memory.
|
|
UNCACHED = 0x40
|
|
void share (Cap target, unsigned flags = 0):
|
|
ocall (target, Num (CAP_MASTER_DIRECT | SHARE, flags))
|
|
unsigned get_flags ():
|
|
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
|
|
bool set_flags (unsigned set, unsigned reset = 0):
|
|
call (CAP_MASTER_DIRECT | SET_FLAGS, Num (set, set | reset))
|
|
return recv.data[0].l == NO_ERROR
|
|
unsigned long physical_address ():
|
|
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
|
|
void alloc_physical (unsigned long address, bool cachable, bool freeable):
|
|
my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
|
|
|
|
struct Listitem : public Cap:
|
|
Listitem (Cap c = Cap ()) : Cap (c):
|
|
enum request:
|
|
CLEAR = CAPTYPE_LISTITEM + 1
|
|
SET_CAP
|
|
ADD
|
|
LIST
|
|
// Remove the listitem from its list.
|
|
void clear ():
|
|
call (CAP_MASTER_DIRECT | CLEAR)
|
|
// Set the capability of an item.
|
|
void set_cap (Cap c):
|
|
call (CAP_MASTER_DIRECT | SET_CAP, c.code)
|
|
// To add a listitem to a list, the listitem capability must be of type ADD or MASTER.
|
|
// A list iterator must be of type LIST or MASTER
|
|
|
|
struct List : public Cap:
|
|
List (Cap c = Cap ()) : Cap (c):
|
|
enum request:
|
|
GET_NEXT = CAPTYPE_LIST + 1
|
|
SET_CB
|
|
ADD_ITEM
|
|
GET_INFO
|
|
SET_INFO
|
|
GET_CAP
|
|
// Get the next listitem from the given one. Use this to loop over all listitems.
|
|
Listitem get_next (Listitem current = Listitem ()):
|
|
iocall (current, CAP_MASTER_DIRECT | GET_NEXT)
|
|
if recv.data[0].l:
|
|
return Cap ()
|
|
return get_arg ()
|
|
// Set the callback. This is called when an item is removed from the list.
|
|
// When called, data[0] is 0 when the list is now empty; 1 otherwise. data[1] is the removed item's info.
|
|
void set_cb (Cap cb):
|
|
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
|
// Add an item to the front of the list.
|
|
void add_item (Listitem item):
|
|
ocall (item, CAP_MASTER_DIRECT | ADD_ITEM)
|
|
// Return item info.
|
|
Num get_info (Listitem item):
|
|
return ocall (item, CAP_MASTER_DIRECT | GET_INFO)
|
|
// Set item info.
|
|
void set_info (Listitem item, Num info):
|
|
ocall (item, CAP_MASTER_DIRECT | SET_INFO, info)
|
|
// Get item capability.
|
|
Cap get_cap (Listitem item):
|
|
iocall (item, CAP_MASTER_DIRECT | GET_CAP)
|
|
return get_arg ()
|
|
|
|
struct Memory : public Cap:
|
|
Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
|
|
Memory (Cap c = Cap ()) : Cap (c):
|
|
enum request:
|
|
CREATE = CAPTYPE_MEMORY + 1
|
|
DESTROY
|
|
LIST
|
|
MAP
|
|
MAPPING
|
|
GET_LIMIT
|
|
SET_LIMIT
|
|
Page create_page ():
|
|
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
|
|
return get_arg ()
|
|
Thread create_thread (unsigned slots):
|
|
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
|
|
return get_arg ()
|
|
Receiver create_receiver ():
|
|
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
|
|
return get_arg ()
|
|
Memory create_memory ():
|
|
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
|
|
return get_arg ()
|
|
Caps create_caps (unsigned size):
|
|
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
|
|
return get_arg ()
|
|
List create_list ():
|
|
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_LIST))
|
|
return get_arg ()
|
|
Listitem create_listitem ():
|
|
icall (Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_LISTITEM))
|
|
return get_arg ()
|
|
void destroy (Cap target):
|
|
ocall (target, CAP_MASTER_DIRECT | DESTROY)
|
|
// TODO: LIST
|
|
bool map (Cap page, unsigned long address):
|
|
return ocall (page, CAP_MASTER_DIRECT | MAP, address).l == NO_ERROR
|
|
bool unmap (Cap page):
|
|
return map (page, ~0)
|
|
Page mapping (void *address):
|
|
icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned long)address))
|
|
return get_arg ()
|
|
unsigned get_limit ():
|
|
return call (CAP_MASTER_DIRECT | GET_LIMIT).l
|
|
void set_limit (unsigned limit):
|
|
call (CAP_MASTER_DIRECT | SET_LIMIT, limit)
|
|
unsigned alloc_range (unsigned pages):
|
|
return my_thread.ocall (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages).l
|
|
|
|
inline void wait ():
|
|
Cap::IMessage i
|
|
Cap ().copy ()._invoke (&i)
|
|
inline void schedule ():
|
|
my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE)
|
|
inline void register_interrupt (unsigned num):
|
|
my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
|
|
inline void unregister_interrupt (unsigned num):
|
|
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
|
|
inline unsigned wait_for_interrupt ():
|
|
my_receiver.set_reply_protected_data (0)
|
|
Cap ().call ()
|
|
unsigned ret = recv.data[0].l
|
|
my_receiver.set_reply_protected_data (~0)
|
|
return ret
|
|
inline Cap get_top_memory ():
|
|
my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
|
|
return get_arg ()
|
|
inline void dbg_send (unsigned code, unsigned bits = 32):
|
|
my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits))
|
|
inline void reboot ():
|
|
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT)
|
|
inline void poweroff ():
|
|
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_POWEROFF)
|
|
inline void suspend ():
|
|
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_SUSPEND)
|
|
inline void boot (unsigned address, unsigned arg):
|
|
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_BOOT, Iris::Num (address, arg))
|
|
|
|
void Receiver::sleep (unsigned value):
|
|
set_alarm (value)
|
|
Cap ().call ()
|
|
inline void sleep (unsigned value):
|
|
my_receiver.sleep (value)
|
|
|
|
// The start function has this prototype (there is no main function).
|
|
Iris::Num start ()
|
|
|
|
#ifndef __KERNEL__
|
|
#if 1
|
|
// Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing.
|
|
#define kdebug_char(_c) do { unsigned _d = (_c); __asm__ volatile ("move $a0, $zero\nlw $a1, %0\nbreak" :: "m"(_d) : "a0", "a1", "memory"); } while (0)
|
|
#else
|
|
#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 (__FILE__ ":"); kdebug (__PRETTY_FUNCTION__); kdebug (":"); kdebug (__stringify (__LINE__)); kdebug_char ('\n'); } while (0)
|
|
|
|
static void kdebug_num (unsigned n, unsigned digits = 8):
|
|
unsigned i
|
|
char const *encode = "0123456789abcdef"
|
|
for i = 0; i < digits; ++i:
|
|
kdebug_char (encode[(n >> (4 * ((digits - 1) - i))) & 0xf])
|
|
|
|
namespace Iris:
|
|
inline void panic (unsigned code, char const *message = NULL):
|
|
if message:
|
|
kdebug_num (code)
|
|
kdebug_char ('\n')
|
|
kdebug (message)
|
|
kdebug_char ('\n')
|
|
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code)
|
|
if code == 0xdeaddead:
|
|
return
|
|
while true:
|
|
wait ()
|
|
|
|
inline void debug_num (unsigned num, unsigned base):
|
|
char const *encode = "0123456789abcdef"
|
|
unsigned digits = 1
|
|
unsigned power = 1
|
|
while power <= num / base:
|
|
power *= base
|
|
++digits
|
|
for unsigned i = 0; i < digits; ++i:
|
|
unsigned d = num / power
|
|
kdebug_char (encode[d])
|
|
num -= d * power
|
|
power /= base
|
|
|
|
inline void debug (const char *f, ...):
|
|
unsigned *last = (unsigned *)&f
|
|
while *f:
|
|
if *f == '%':
|
|
++f
|
|
switch *f:
|
|
case '%':
|
|
kdebug_char ('%')
|
|
break
|
|
case 'd':
|
|
++last
|
|
debug_num (*last, 10)
|
|
break
|
|
case 'x':
|
|
++last
|
|
debug_num (*last, 0x10)
|
|
break
|
|
case 's':
|
|
++last
|
|
kdebug ((char *)*last)
|
|
break
|
|
case 'c':
|
|
++last
|
|
kdebug_char (*last)
|
|
break
|
|
default:
|
|
panic (*f, "invalid character in dbg format string")
|
|
else:
|
|
kdebug_char (*f)
|
|
++f
|
|
|
|
#endif
|
|
#endif
|