mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
new directory organization
This commit is contained in:
521
include/devices.hhp
Normal file
521
include/devices.hhp
Normal file
@@ -0,0 +1,521 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/devices.hhp: interfaces for core devices.
|
||||
// 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_DEVICES_HH
|
||||
#define __IRIS_DEVICES_HH
|
||||
|
||||
#include "iris.hh"
|
||||
|
||||
namespace Iris:
|
||||
// Caplist interface.
|
||||
template <typename _T> //
|
||||
struct Caplist : public Caps:
|
||||
Caplist (Caps c = Cap ()) : Caps (c):
|
||||
Caplist <_T> create (unsigned size, Memory mem = my_memory):
|
||||
return Caplist <_T> (mem.create_caps (size))
|
||||
void set (unsigned idx, _T value):
|
||||
return Caps::set (idx, value)
|
||||
_T get (unsigned idx):
|
||||
return _T (Caps::get (idx))
|
||||
|
||||
struct _Locker_base:
|
||||
enum request:
|
||||
LOCK_RO = 0x2001
|
||||
UNLOCK_RO
|
||||
SET_CHANGE_CB
|
||||
NUM
|
||||
template <typename _T> //
|
||||
struct Locker : public _Locker_base, public _T:
|
||||
// Lock the object for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
|
||||
void lock_ro ():
|
||||
_T::call (CAP_MASTER_DIRECT | LOCK_RO)
|
||||
// Release a read-only lock.
|
||||
void unlock_ro ():
|
||||
_T::call (CAP_MASTER_DIRECT | UNLOCK_RO)
|
||||
// Register a callback when the backing store is changed.
|
||||
// The cb is invoked with data[0] set to the position of the first change and data[1] set to the length of the changed part.
|
||||
// The accuracy of this is not guaranteed. Servers which only want to provide an event should set data[0] == 0, data[1] == ~0.
|
||||
// The change invoke must happen before this function's reply is sent.
|
||||
void set_change_cb (Listitem cb):
|
||||
_T::ocall (cb, CAP_MASTER_DIRECT | SET_CHANGE_CB)
|
||||
Locker ():
|
||||
Locker (Cap c) : _T (c):
|
||||
|
||||
struct _WLocker_base:
|
||||
enum request:
|
||||
LOCK = _Locker_base::NUM
|
||||
UNLOCK
|
||||
NUM
|
||||
template <typename _T> //
|
||||
struct WLocker : public _WLocker_base, public _T:
|
||||
// Lock the object. Write operations can only be done when the object is locked.
|
||||
void lock ():
|
||||
_T::call (CAP_MASTER_DIRECT | LOCK)
|
||||
// Unlock the object. Write operations can only be done when the object is locked.
|
||||
void unlock ():
|
||||
_T::call (CAP_MASTER_DIRECT | UNLOCK)
|
||||
WLocker ():
|
||||
WLocker (Cap c) : _T (c):
|
||||
|
||||
/// A short block of data with a size and content. Any character can be stored in it (including '\0').
|
||||
struct _String : public Cap:
|
||||
_String (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
GET_SIZE = _WLocker_base::NUM
|
||||
GET_CHARS
|
||||
ID
|
||||
/// Get the size of the string.
|
||||
Num get_size ():
|
||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||
/// Get exactly 16 characters. There is no alignment requirement.
|
||||
char *get_chars (Num idx, char buffer[16]):
|
||||
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
|
||||
unsigned *b = (unsigned *)buffer
|
||||
b[0] = recv.data[0].l
|
||||
b[1] = recv.data[0].h
|
||||
b[2] = recv.data[1].l
|
||||
b[3] = recv.data[1].h
|
||||
return buffer
|
||||
typedef Locker <_String> String
|
||||
|
||||
/// A block of data with a size and content. Any character can be stored in it (including '\0').
|
||||
struct _Block : public Cap:
|
||||
_Block (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
GET_SIZE = _String::ID
|
||||
GET_ALIGN_BITS
|
||||
GET_BLOCK
|
||||
ID
|
||||
/// Get the size of the block.
|
||||
Num get_size ():
|
||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||
/// Get the number of bits that page accesses must be aligned to. Cannot be more than PAGE_BITS.
|
||||
unsigned get_align_bits ():
|
||||
return call (CAP_MASTER_DIRECT | GET_ALIGN_BITS).l
|
||||
/// Helper function for get_block.
|
||||
static Page _create_paying_page ():
|
||||
Page ret = my_memory.create_page ()
|
||||
ret.set_flags (Page::PAYING)
|
||||
return ret
|
||||
/// Get a block from the block; place it at offset on page. This need not be implemented for blocks smaller than PAGE_SIZE. All arguments must be aligned. If size is PAGE_SIZE, the caller may lose the frame in the transaction.
|
||||
Cap get_block (Num idx, unsigned size = PAGE_SIZE, unsigned offset = 0, Page ret = _create_paying_page ()):
|
||||
ocall (ret, Iris::Num (CAP_MASTER_DIRECT | GET_BLOCK, size << 16 | offset), idx)
|
||||
return ret
|
||||
typedef Locker <_Block> Block
|
||||
|
||||
/// A writable String.
|
||||
struct _WString : public String:
|
||||
_WString (Cap c = Cap ()) : String (c):
|
||||
enum request:
|
||||
TRUNCATE = _Block::ID
|
||||
SET_CHARS
|
||||
ID
|
||||
/// Set the size of the string. Strings may have a limit to this setting.
|
||||
void truncate (Num size):
|
||||
call (CAP_MASTER_DIRECT | TRUNCATE, size)
|
||||
/// Set exactly 4 characters. If the size is shorter than idx + 4, the extra characters are ignored.
|
||||
void set_chars (Num idx, char buffer[4]):
|
||||
call (Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
|
||||
typedef WLocker <_WString> WString
|
||||
|
||||
/// A writable Block.
|
||||
struct _WBlock : public Block:
|
||||
_WBlock (Cap c = Cap ()) : Block (c):
|
||||
enum request:
|
||||
TRUNCATE = _WString::TRUNCATE
|
||||
SET_BLOCK = _WString::ID
|
||||
ID
|
||||
/// Set the size of the block. This setting may have a limited range, or not be supported at all.
|
||||
void truncate (Num size):
|
||||
call (CAP_MASTER_DIRECT | TRUNCATE, size)
|
||||
/// Overwrite a block from the block with data at offset on the page. All arguments must be aligned. If size is PAGE_SIZE, the caller may lose the frame in the transaction. Only the specified part of the page is used for overwriting data.
|
||||
void set_block (Num idx, Page page, unsigned size = PAGE_SIZE, unsigned offset = 0):
|
||||
ocall (page, Iris::Num (CAP_MASTER_DIRECT | SET_BLOCK, size << 16 | offset), idx)
|
||||
typedef WLocker <_WBlock> WBlock
|
||||
|
||||
// This interface allows another kernel to be booted by Iris.
|
||||
struct Boot : public Cap:
|
||||
Boot (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
BOOT = _WBlock::ID
|
||||
ID
|
||||
// Boot a new kernel.
|
||||
void boot (String code, unsigned load, unsigned entry):
|
||||
ocall (code, CAP_MASTER_DIRECT | BOOT, Iris::Num (load, entry))
|
||||
|
||||
// Every process which wants to be switchable through a terminal must implement this interface.
|
||||
struct Device : public Cap:
|
||||
Device (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
RESET = Boot::ID
|
||||
ID
|
||||
// Reset the device. This is called by the terminal while switching owners.
|
||||
void reset ():
|
||||
call (CAP_MASTER_DIRECT | RESET)
|
||||
|
||||
struct Event : public Device:
|
||||
Event (Cap c = Cap ()) : Device (c):
|
||||
enum request:
|
||||
SET_CB = Device::ID
|
||||
ID
|
||||
// Set the event callback. Pending event emit to the new callback immediately.
|
||||
void set_cb (Cap cb):
|
||||
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
||||
|
||||
struct Elfrun : public Cap:
|
||||
Elfrun (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
RUN_BLOCK = Event::ID
|
||||
RUN_CAPS
|
||||
ID
|
||||
enum arg_pos:
|
||||
PARENT_MEMORY
|
||||
DATA
|
||||
PARENT
|
||||
Caps run_block (Memory parent_memory, Block data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32):
|
||||
Caps caps = my_memory.create_caps (3)
|
||||
caps.set (PARENT_MEMORY, parent_memory)
|
||||
caps.set (DATA, data)
|
||||
caps.set (PARENT, parent)
|
||||
iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_BLOCK, Num (num_slots, num_caps))
|
||||
Caps ret = get_arg ()
|
||||
my_memory.destroy (caps)
|
||||
free_cap (caps)
|
||||
return ret
|
||||
Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32):
|
||||
Caps caps = my_memory.create_caps (3)
|
||||
caps.set (PARENT_MEMORY, parent_memory)
|
||||
caps.set (DATA, data)
|
||||
caps.set (PARENT, parent)
|
||||
iocall (caps.copy (), Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Num (num_slots, num_caps))
|
||||
Caps ret = get_arg ()
|
||||
my_memory.destroy (caps)
|
||||
free_cap (caps)
|
||||
return ret
|
||||
|
||||
// Interface for talking to the parent process.
|
||||
struct Parent : public Cap:
|
||||
Parent (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
GET_CAPABILITY = Elfrun::ID
|
||||
PROVIDE_CAPABILITY
|
||||
WAIT
|
||||
GET_MEMORY
|
||||
PROVIDE_MEMORY
|
||||
INIT_DONE
|
||||
EXIT
|
||||
ID
|
||||
// Get a handle.
|
||||
template <typename _T> _T get_capability (unsigned num = 0):
|
||||
icall (Num (CAP_MASTER_DIRECT | GET_CAPABILITY, num), _T::ID)
|
||||
return get_arg ()
|
||||
// Provide a device handle.
|
||||
template <typename _T> void provide_capability (Cap cap, unsigned num = 0):
|
||||
ocall (cap, Num (CAP_MASTER_DIRECT | PROVIDE_CAPABILITY, num), _T::ID)
|
||||
// Wait until a device is used by the caller again.
|
||||
template <typename _T> void wait (unsigned num = 0):
|
||||
call (Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
|
||||
// Get memory paid for by another thread, which cannot be inspected or changed by that thread. The memory can be inspected and changed by the user (owning both threads). The call will fail when the threads are not owned by the same user.
|
||||
Memory get_memory (Cap target):
|
||||
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY)
|
||||
return get_arg ()
|
||||
// Get a handle that another thread can use to call get_memory on. The actual limit on the created memory is floor(limit, thread address space limit).
|
||||
Cap provide_memory (unsigned limit):
|
||||
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
|
||||
return get_arg ()
|
||||
// Signal the parent that the initialisation phase is over.
|
||||
void init_done (Num stage = 0):
|
||||
call (CAP_MASTER_DIRECT | INIT_DONE, stage)
|
||||
// Exit the program. The parent does not reply, but kills the process.
|
||||
void exit (Num code):
|
||||
call (CAP_MASTER_DIRECT | EXIT, code)
|
||||
|
||||
// Keyboard interface.
|
||||
struct Keyboard : public Event:
|
||||
Keyboard (Cap c = Cap ()) : Event (c):
|
||||
enum request:
|
||||
GET_NUM_KEYS = Parent::ID
|
||||
GET_KEYS
|
||||
ID
|
||||
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
|
||||
enum constant:
|
||||
RELEASE = 1 << 31
|
||||
// Get the number of keys on the keyboard.
|
||||
unsigned get_num_keys ():
|
||||
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
|
||||
// Get the keycodes for the keys. The reply sends 4 key codes (32 bit each).
|
||||
void get_keys (unsigned first):
|
||||
call (CAP_MASTER_DIRECT | GET_KEYS, first)
|
||||
|
||||
// Buzzer interface.
|
||||
struct Buzzer : public Device:
|
||||
Buzzer (Cap c = Cap ()) : Device (c):
|
||||
enum request:
|
||||
BEEP = Keyboard::ID
|
||||
STOP
|
||||
ID
|
||||
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted.
|
||||
void beep (unsigned freq, unsigned ms, unsigned volume, Cap cb = Cap ()):
|
||||
ocall (cb, Num (CAP_MASTER_DIRECT | BEEP, volume), Num (freq, ms))
|
||||
// Abort current beep, if any.
|
||||
void stop ():
|
||||
call (CAP_MASTER_DIRECT | STOP)
|
||||
|
||||
// Display interface.
|
||||
struct Display : public Device:
|
||||
Display (Cap c = Cap ()) : Device (c):
|
||||
enum request:
|
||||
SET_EOF_CB = Buzzer::ID
|
||||
MAP_FB
|
||||
UNMAP_FB
|
||||
GET_INFO
|
||||
ID
|
||||
// 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):
|
||||
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
|
||||
// Map the framebuffer into memory.
|
||||
Caps map_fb (unsigned address, Memory mem = my_memory, bool use = true):
|
||||
iocall (mem, Num (CAP_MASTER_DIRECT | MAP_FB, use ? 1 : 0), address)
|
||||
return get_arg ()
|
||||
void unmap_fb (Caps caps):
|
||||
ocall (caps, CAP_MASTER_DIRECT | UNMAP_FB)
|
||||
// Get information about the display.
|
||||
void get_info ():
|
||||
// TODO: Interface is to be designed.
|
||||
panic (0, "using undefined interface Display::get_info ()")
|
||||
|
||||
// Font interface.
|
||||
// This can be used to turn a Display into a tty
|
||||
struct Font : public Cap:
|
||||
Font (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
SET_DISPLAY = Display::ID
|
||||
LOAD_FONT
|
||||
SETUP
|
||||
AT
|
||||
WRITE
|
||||
GET_POS
|
||||
GET_SIZE
|
||||
ID
|
||||
// Connect this font to new Display.
|
||||
void set_display (Display d):
|
||||
ocall (d, CAP_MASTER_DIRECT | SET_DISPLAY)
|
||||
// Load new glyphs.
|
||||
void load_font (String font):
|
||||
ocall (font, CAP_MASTER_DIRECT | LOAD_FONT)
|
||||
// Set some things up, like colours.
|
||||
void setup ():
|
||||
// TODO: Interface is to be designed.
|
||||
panic (0, "using undefined interface Font::setup ()")
|
||||
// Set new cursor position.
|
||||
void at (int x, int y, bool delta_x = false, bool delta_y = false):
|
||||
call (Num (CAP_MASTER_DIRECT | AT, delta_x + 2 * delta_y), Num (x, y))
|
||||
// Write one glyph to the display.
|
||||
void write (char c):
|
||||
call (CAP_MASTER_DIRECT | WRITE, c)
|
||||
// Write some glyphs to the display.
|
||||
void write (char const *text):
|
||||
for char const *t = text; *t; ++t:
|
||||
invoke (CAP_MASTER_DIRECT | WRITE, *t)
|
||||
// Write some glyphs to the display.
|
||||
void write (char const *text, unsigned size):
|
||||
for unsigned t = 0; t < size; ++t:
|
||||
invoke (CAP_MASTER_DIRECT | WRITE, text[t])
|
||||
void get_pos (unsigned &x, unsigned &y):
|
||||
call (CAP_MASTER_DIRECT | GET_POS)
|
||||
x = recv.data[0].l
|
||||
y = recv.data[1].l
|
||||
// Determine the size of a character.
|
||||
void get_size (unsigned c, unsigned &width, unsigned &height, unsigned &baseline):
|
||||
Num ret = call (CAP_MASTER_DIRECT | GET_SIZE, c)
|
||||
width = recv.data[1].l
|
||||
height = ret.h
|
||||
baseline = ret.l
|
||||
void write (unsigned num, unsigned base = 10):
|
||||
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
|
||||
write (encode[d])
|
||||
num -= d * power
|
||||
power /= base
|
||||
void printf (char const *f, ...):
|
||||
unsigned *last = (unsigned *)&f
|
||||
while *f:
|
||||
if *f == '\r':
|
||||
at (0, 0, false, true)
|
||||
else if *f == '\n':
|
||||
at (0, 16, false, true)
|
||||
else if *f == '%':
|
||||
++f
|
||||
switch *f:
|
||||
case '%':
|
||||
write ('%')
|
||||
break
|
||||
case 'd':
|
||||
++last
|
||||
write (*last)
|
||||
break
|
||||
case 'x':
|
||||
++last
|
||||
write (*last, 0x10)
|
||||
break
|
||||
case 's':
|
||||
++last
|
||||
write ((char *)*last)
|
||||
break
|
||||
case 'c':
|
||||
++last
|
||||
write ((char)*last)
|
||||
break
|
||||
default:
|
||||
panic (*f, "invalid code character in dbg format string")
|
||||
else:
|
||||
write (*f)
|
||||
++f
|
||||
|
||||
// Numerical setting, such as a display backlight.
|
||||
struct Setting : public Device:
|
||||
Setting (Cap c = Cap ()) : Device (c):
|
||||
enum request:
|
||||
SET = Font::ID
|
||||
GET_RANGE
|
||||
ID
|
||||
// Set a new value.
|
||||
void set (unsigned value):
|
||||
call (CAP_MASTER_DIRECT | SET, value)
|
||||
// Get the maximum value for this setting. Using a higher value with SET gives undefined results.
|
||||
unsigned get_range ():
|
||||
return call (CAP_MASTER_DIRECT | GET_RANGE).l
|
||||
|
||||
// File system interface.
|
||||
// filesystem-related interfaces: directory, stream, seekable.
|
||||
// Normal files implement stream and/or seekable. Directories implement directory.
|
||||
// Seekable is not a class, it is identical to [W]String.
|
||||
|
||||
// Directory interface.
|
||||
struct _Directory : public Cap:
|
||||
_Directory (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
GET_SIZE = Setting::ID
|
||||
GET_NAME
|
||||
GET_FILE_RO
|
||||
GET_FILE_INFO
|
||||
ID
|
||||
// Get the number of entries in this directory.
|
||||
Num get_size ():
|
||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||
// Get the filename.
|
||||
String get_name (Num idx):
|
||||
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
|
||||
return get_arg ()
|
||||
// Get the file.
|
||||
Cap get_file_ro (Num idx):
|
||||
icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
|
||||
return get_arg ()
|
||||
// Get file info. TODO: define possible types.
|
||||
Num get_file_info (Num idx, unsigned type):
|
||||
return icall (Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
|
||||
typedef Locker <_Directory> Directory
|
||||
|
||||
struct _WDirectory : public Directory:
|
||||
_WDirectory (Cap c = Cap ()) : Directory (c):
|
||||
enum request:
|
||||
GET_FILE = _Directory::ID
|
||||
CREATE_FILE
|
||||
DELETE_FILE
|
||||
ID
|
||||
// Get the file.
|
||||
Cap get_file (Num idx):
|
||||
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
|
||||
return get_arg ()
|
||||
// Create a new file. After this, any index may map to a different file.
|
||||
Cap create_file (String name):
|
||||
icall (CAP_MASTER_DIRECT | CREATE_FILE)
|
||||
return get_arg ()
|
||||
// Delete a file. After this, any index may map to a different file.
|
||||
void delete_file (Num idx):
|
||||
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
|
||||
typedef WLocker <_WDirectory> WDirectory
|
||||
|
||||
// Stream interface.
|
||||
struct Stream : public Cap:
|
||||
Stream (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
READ = _WDirectory::ID
|
||||
WRITE
|
||||
ID
|
||||
// Try to read size bytes. Returns the number of bytes successfully read.
|
||||
Num read (Num size, bool block):
|
||||
return icall (Num (CAP_MASTER_DIRECT | READ, block), size)
|
||||
// Try to write size bytes. Returns the number of bytes successfully written.
|
||||
Num write (String s, Num size):
|
||||
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
|
||||
|
||||
struct UI : public Cap:
|
||||
UI (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
GET_STATE = Stream::ID
|
||||
EVENT
|
||||
EXIT
|
||||
ID
|
||||
enum constant:
|
||||
INPUT = 1 << 31
|
||||
void get_state (Cap cap):
|
||||
ocall (cap, CAP_MASTER_DIRECT | GET_STATE)
|
||||
void event (unsigned code, Iris::Num value = 0):
|
||||
call (Num (CAP_MASTER_DIRECT | EVENT, code), value)
|
||||
void exit ():
|
||||
call (CAP_MASTER_DIRECT | EXIT)
|
||||
|
||||
struct RTC : public Cap:
|
||||
RTC (Cap c = Cap ()) : Cap (c):
|
||||
enum request:
|
||||
SETUP = UI::ID
|
||||
GET_TIME
|
||||
SET_TIME
|
||||
GET_ALARM
|
||||
UNSET_ALARM
|
||||
SET_ALARM
|
||||
ID
|
||||
void setup (unsigned hz, unsigned adjc):
|
||||
call (CAP_MASTER_DIRECT | SETUP, Num (hz, adjc))
|
||||
unsigned get_time ():
|
||||
return call (CAP_MASTER_DIRECT | GET_TIME).l
|
||||
unsigned set_time (unsigned time):
|
||||
return call (CAP_MASTER_DIRECT | SET_TIME, time).l
|
||||
unsigned get_alarm ():
|
||||
return call (CAP_MASTER_DIRECT | GET_ALARM).l
|
||||
unsigned unset_alarm ():
|
||||
return call (CAP_MASTER_DIRECT | UNSET_ALARM).l
|
||||
unsigned set_alarm (unsigned time, Cap cb):
|
||||
return ocall (cb, CAP_MASTER_DIRECT | SET_ALARM, time).l
|
||||
|
||||
// TODO.
|
||||
// Sound interface.
|
||||
// Usb interfaces (port, device).
|
||||
// Pointer interface. (Only movement; buttons follow keyboard interface.)
|
||||
// Network interface.
|
||||
// Camera interface.
|
||||
|
||||
#endif
|
||||
687
include/iris.hhp
Normal file
687
include/iris.hhp
Normal file
@@ -0,0 +1,687 @@
|
||||
#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
|
||||
359
include/kernel.hhp
Normal file
359
include/kernel.hhp
Normal file
@@ -0,0 +1,359 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// kernel.hhp: Header for all kernel sources.
|
||||
// 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 _KERNEL_HH
|
||||
#define _KERNEL_HH
|
||||
|
||||
// Include definitions which are shared with user space.
|
||||
#define __KERNEL__
|
||||
|
||||
// Normally define all variables in this file as extern.
|
||||
// Exactly once (in data.ccp), EXTERN is predefined empty.
|
||||
// That results in space being allocated in its object file.
|
||||
#ifndef EXTERN
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
struct kPage
|
||||
struct kThread
|
||||
struct kMessage
|
||||
struct kReceiver
|
||||
struct kCapability
|
||||
struct kCaps
|
||||
struct kMemory
|
||||
struct kList
|
||||
struct kListitem
|
||||
|
||||
// Some functions which must be defined early.
|
||||
#ifndef NDEBUG
|
||||
void kdebug (unsigned ch)
|
||||
void kdebug (char const *str)
|
||||
void kdebug_num (unsigned num, unsigned digits = 8)
|
||||
#else
|
||||
#define kdebug(x) do {} while (0)
|
||||
#define kdebug_num(n) do {} while (0)
|
||||
#endif
|
||||
|
||||
#include "iris.hh"
|
||||
|
||||
typedef kPage *kPageP
|
||||
typedef kThread *kThreadP
|
||||
typedef kMessage *kMessageP
|
||||
typedef kReceiver *kReceiverP
|
||||
typedef kCapability *kCapabilityP
|
||||
typedef kCaps *kCapsP
|
||||
typedef kMemory *kMemoryP
|
||||
typedef kList *kListP
|
||||
typedef kListitem *kListitemP
|
||||
typedef void *kPointer
|
||||
|
||||
struct kCapRef:
|
||||
kCapsP caps
|
||||
unsigned index
|
||||
inline kCapability *deref ()
|
||||
bool valid ():
|
||||
return deref () != NULL
|
||||
kCapability *operator-> ():
|
||||
return deref ()
|
||||
void reset ():
|
||||
caps = NULL
|
||||
kCapRef (kCapsP c, unsigned i) : caps (c), index (i):
|
||||
kCapRef () : caps (NULL), index (~0):
|
||||
inline void clone (kCapRef source, bool copy)
|
||||
inline void set (kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
|
||||
struct kObject:
|
||||
kCapRef refs
|
||||
kMemoryP address_space
|
||||
// Next and previous object of the same type in any page.
|
||||
kPointer prev, next
|
||||
inline bool is_free ()
|
||||
|
||||
struct kFree : public kObject:
|
||||
// This marker is ~0. No other kernel structure may allow this value
|
||||
// at this point. It is used to recognize free chunks.
|
||||
unsigned marker
|
||||
|
||||
bool kObject::is_free ():
|
||||
return ((kFree *)this)->marker == ~0
|
||||
|
||||
// Include architecture-specific parts.
|
||||
#include "arch.hh"
|
||||
|
||||
struct kCapability : public kObject:
|
||||
struct Context:
|
||||
Iris::Num data[2]
|
||||
kCapRef reply
|
||||
kCapRef arg
|
||||
bool copy[2]
|
||||
kReceiverP target
|
||||
kCapRef parent
|
||||
kCapRef children
|
||||
kCapRef sibling_prev, sibling_next
|
||||
Iris::Num protected_data
|
||||
inline void invoke (kCapability::Context *c)
|
||||
void invalidate ()
|
||||
|
||||
struct _slot_data:
|
||||
kThreadP thread
|
||||
unsigned index
|
||||
|
||||
// The order of the members is defined in arch.hh. It must be first an object which cannot be ~0, then
|
||||
// pc, sp and arch. After that everything is allowed.
|
||||
struct kThread : public kObject:
|
||||
kReceiverP receivers
|
||||
unsigned pc, sp
|
||||
kThread_arch arch
|
||||
unsigned flags
|
||||
kThreadP schedule_prev, schedule_next
|
||||
unsigned recv_reply, recv_arg
|
||||
// slot[] is an array of slots pointers to kCapses.
|
||||
unsigned slots
|
||||
#ifndef NDEBUG
|
||||
unsigned id
|
||||
#endif
|
||||
struct caps_store:
|
||||
_slot_data prev, next
|
||||
kCapsP caps
|
||||
caps_store slot[1]
|
||||
void unset_slot (unsigned s)
|
||||
void raise (unsigned code, unsigned data)
|
||||
void run ()
|
||||
void unrun ()
|
||||
void wait ()
|
||||
void unwait ()
|
||||
bool is_waiting ():
|
||||
return flags & Iris::Thread::WAITING
|
||||
kCapRef find_capability (unsigned code, bool *copy)
|
||||
|
||||
struct kReceiver : public kObject:
|
||||
kThreadP owner
|
||||
kReceiverP prev_owned, next_owned
|
||||
kReceiverP prev_alarm, next_alarm
|
||||
unsigned alarm_count
|
||||
// random is used like the tlb random register to find invalid caps to store the message to.
|
||||
unsigned random
|
||||
kCapsP caps
|
||||
// These are capabilities which call this receiver on invoke.
|
||||
kCapRef capabilities
|
||||
// The message queue. kMessages are added at the tail, and removed at the front.
|
||||
kMessageP messages
|
||||
kMessageP last_message
|
||||
Iris::Num reply_protected_data
|
||||
bool protected_only
|
||||
// This limit is for messages stored in its address space. There is unlimited space if senders provide it.
|
||||
unsigned queue_limit, queue_use
|
||||
void own (kThreadP o)
|
||||
void orphan ()
|
||||
bool try_deliver ()
|
||||
bool send_message (Iris::Num protected_data, kCapability::Context *c)
|
||||
void check (unsigned line)
|
||||
|
||||
struct kPage : public kObject:
|
||||
unsigned frame
|
||||
unsigned flags
|
||||
unsigned mapping
|
||||
kPageP share_prev, share_next
|
||||
kPage_arch arch
|
||||
void forget ()
|
||||
void check_payment ()
|
||||
|
||||
struct kCaps : public kObject:
|
||||
_slot_data first_slot
|
||||
unsigned size
|
||||
kCapability caps[1]
|
||||
inline kCapability *cap (unsigned idx)
|
||||
void set (unsigned index, kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
|
||||
void clone (unsigned index, kCapRef source, bool copy)
|
||||
void init (unsigned size)
|
||||
|
||||
// The 8 comes from the size of the admin data in a free page. When changing that, this must be changed as well.
|
||||
#define MAX_NUM_CAPS ((PAGE_SIZE - 8 - sizeof (kCaps)) / sizeof (kCapability) + 1)
|
||||
|
||||
struct kMessage : public kObject:
|
||||
Iris::Num protected_data
|
||||
Iris::Num data[2]
|
||||
// This is a real Caps of two elements, not a link.
|
||||
kCaps caps
|
||||
|
||||
struct kList : public kObject:
|
||||
kListitemP first_listitem
|
||||
// This is a real Caps of one element, not a link.
|
||||
kCaps owner
|
||||
|
||||
struct kListitem : public kObject:
|
||||
kListP list
|
||||
kListitemP prev_item, next_item
|
||||
Iris::Num info
|
||||
// This is a real Caps of one element, not a link.
|
||||
kCaps target
|
||||
void add (kList *l)
|
||||
|
||||
struct kMemory : public kObject:
|
||||
kFree *frees
|
||||
kPageP pages
|
||||
kThreadP threads
|
||||
kReceiverP receivers
|
||||
kCapsP capses
|
||||
kListP lists
|
||||
kListitemP listitems
|
||||
kMemoryP memories
|
||||
unsigned limit, used
|
||||
kMemory_arch arch
|
||||
|
||||
inline bool map (kPage *page, unsigned address)
|
||||
inline void unmap (kPage *page)
|
||||
inline kPage *get_mapping (unsigned address)
|
||||
|
||||
// Allocation of pages.
|
||||
bool use (unsigned num = 1)
|
||||
void unuse (unsigned num = 1)
|
||||
unsigned palloc ()
|
||||
unsigned zalloc ()
|
||||
void pfree (unsigned page)
|
||||
void zfree (unsigned page)
|
||||
|
||||
// Allocation routines for kernel structures
|
||||
void *search_free (unsigned size, void **first)
|
||||
kPage *alloc_page ()
|
||||
kThread *alloc_thread (unsigned size)
|
||||
kMessage *alloc_message (kReceiver *target)
|
||||
kReceiver *alloc_receiver ()
|
||||
kCaps *alloc_caps (unsigned size)
|
||||
kList *alloc_list ()
|
||||
kListitem *alloc_listitem ()
|
||||
kMemory *alloc_memory ()
|
||||
|
||||
void free_page (kPage *page)
|
||||
void free_thread (kThread *thread)
|
||||
void free_message (kReceiver *owner, kMessage *message)
|
||||
void free_receiver (kReceiver *receiver)
|
||||
void free_caps (kCaps *page)
|
||||
void free_list (kList *list)
|
||||
void free_listitem (kListitem *listitem)
|
||||
void free_memory (kMemory *mem)
|
||||
|
||||
void free_obj (kObject *obj, void **first)
|
||||
void check (unsigned line)
|
||||
void print (unsigned line, unsigned indent)
|
||||
|
||||
// Functions which can be called from assembly must not be mangled.
|
||||
extern "C":
|
||||
// Panic. n is sent over caps led. message is sent to dbg_caps (when in use).
|
||||
#define panic(n, m) panic_impl ((n), __stringify (__LINE__), __PRETTY_FUNCTION__, (m))
|
||||
void panic_impl (unsigned n, char const *line, char const *name, char const *message = "")
|
||||
#ifndef NDEBUG
|
||||
EXTERN Iris::Num dbg_code
|
||||
EXTERN unsigned dbg_buffer[32]
|
||||
EXTERN unsigned dbg_buffer_head
|
||||
static void dbg_push (unsigned n):
|
||||
dbg_buffer[dbg_buffer_head++] = n
|
||||
if dbg_buffer_head == 32:
|
||||
dbg_buffer_head = 0
|
||||
EXTERN kCapRef dbg_cap
|
||||
void dbg_send (unsigned num, unsigned bits)
|
||||
void check (unsigned num, char const *msg)
|
||||
#define dbg_check() ::check (__LINE__, __FILE__)
|
||||
void print_free ()
|
||||
void check_impl (kObject *o, unsigned num, char const *msg)
|
||||
bool check_free (kObject *o, unsigned size)
|
||||
#define dpanic(n, msg) panic (n, msg)
|
||||
#define dbg_print() top_memory.print (__LINE__, 0)
|
||||
#else
|
||||
#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 ()
|
||||
void timer_interrupt ()
|
||||
|
||||
EXTERN kMemory top_memory
|
||||
EXTERN kReceiverP first_alarm
|
||||
EXTERN kThread idle
|
||||
EXTERN kMemory idle_memory
|
||||
EXTERN kPage idle_page
|
||||
EXTERN kThreadP first_scheduled
|
||||
EXTERN kThreadP current, old_current
|
||||
EXTERN bool do_schedule, must_wait
|
||||
// reply_caps is the source of a receiver-generated reply capability.
|
||||
// replied_caps is the source of kernel-generated capabilities which are used as arguments in a reply.
|
||||
// reply_target is the target receiver for kernel replies.
|
||||
// reply_protected is the protected data for the kernel reply.
|
||||
EXTERN kCaps reply_caps, replied_caps
|
||||
EXTERN kReceiver *reply_target
|
||||
EXTERN Iris::Num reply_protected
|
||||
|
||||
// Defined in memory.ccp
|
||||
unsigned init_memory (unsigned mem)
|
||||
unsigned raw_zalloc ()
|
||||
void raw_pfree (unsigned page)
|
||||
unsigned phys_alloc (unsigned num)
|
||||
void phys_free (unsigned page, unsigned num)
|
||||
|
||||
// Defind in invoke.ccp
|
||||
void invoke (kReceiverP target, Iris::Num protected_data, kCapability::Context *c)
|
||||
|
||||
// Defined by architecture-specific files.
|
||||
void kThread_arch_init (kThread *thread)
|
||||
void kThread_arch_receive (kThread *thread, Iris::Num protected_data, Iris::Num *data)
|
||||
unsigned *kThread_arch_info (kThread *thread, unsigned num)
|
||||
void kMemory_arch_init (kMemory *mem)
|
||||
void kMemory_arch_free (kMemory *mem)
|
||||
bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address)
|
||||
void kMemory_arch_unmap (kMemory *mem, kPage *page)
|
||||
kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address)
|
||||
void kPage_arch_init (kPage *page)
|
||||
void kPage_arch_update_mapping (kPage *page)
|
||||
void arch_register_interrupt (unsigned num, kReceiverP r)
|
||||
void arch_reboot ()
|
||||
void arch_poweroff ()
|
||||
void arch_suspend ()
|
||||
void arch_boot (unsigned address, unsigned arg)
|
||||
void arch_uncache_page (unsigned page)
|
||||
|
||||
#define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } 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 ('\n'); } while (0)
|
||||
|
||||
bool kMemory::map (kPage *page, unsigned address):
|
||||
return kMemory_arch_map (this, page, address)
|
||||
void kMemory::unmap (kPage *page):
|
||||
page->forget ()
|
||||
kMemory_arch_unmap (this, page)
|
||||
kPage *kMemory::get_mapping (unsigned address):
|
||||
return kMemory_arch_get_mapping (this, address)
|
||||
kCapability *kCapRef::deref ():
|
||||
return caps ? caps->cap (index) : NULL
|
||||
void kCapRef::clone (kCapRef source, bool copy):
|
||||
caps->clone (index, source, copy)
|
||||
void kCapRef::set (kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr):
|
||||
if valid ():
|
||||
deref ()->invalidate ()
|
||||
caps->set (index, target, pdata, parent, parent_ptr)
|
||||
void kCapability::invoke (kCapability::Context *c):
|
||||
::invoke (target, protected_data, c)
|
||||
kCapability *kCaps::cap (unsigned idx):
|
||||
if idx >= size:
|
||||
dpanic (idx, "invalid capability requested")
|
||||
return NULL
|
||||
return &caps[idx]
|
||||
|
||||
#endif
|
||||
147
include/keys.hhp
Normal file
147
include/keys.hhp
Normal file
@@ -0,0 +1,147 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/keys.hhp: Keycode definitions.
|
||||
// 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 __KEYS_HH
|
||||
#define __KEYS_HH
|
||||
|
||||
namespace Key:
|
||||
enum codes:
|
||||
N0 = '0'
|
||||
N1 = '1'
|
||||
N2 = '2'
|
||||
N3 = '3'
|
||||
N4 = '4'
|
||||
N5 = '5'
|
||||
N6 = '6'
|
||||
N7 = '7'
|
||||
N8 = '8'
|
||||
N9 = '9'
|
||||
A = 'a'
|
||||
B = 'b'
|
||||
C = 'c'
|
||||
D = 'd'
|
||||
E = 'e'
|
||||
F = 'f'
|
||||
G = 'g'
|
||||
H = 'h'
|
||||
I = 'i'
|
||||
J = 'j'
|
||||
K = 'k'
|
||||
L = 'l'
|
||||
M = 'm'
|
||||
N = 'n'
|
||||
O = 'o'
|
||||
P = 'p'
|
||||
Q = 'q'
|
||||
R = 'r'
|
||||
S = 's'
|
||||
T = 't'
|
||||
U = 'u'
|
||||
V = 'v'
|
||||
W = 'w'
|
||||
X = 'x'
|
||||
Y = 'y'
|
||||
Z = 'z'
|
||||
ESCAPE = 27
|
||||
ENTER = '\n'
|
||||
TAB = '\t'
|
||||
COMMA = ','
|
||||
PERIOD = '.'
|
||||
SLASH = '/'
|
||||
BACKSLASH = '\\'
|
||||
SEMICOLON = ';'
|
||||
QUOTE = '\''
|
||||
BACKQUOTE = '`'
|
||||
OPEN_BRACKET = '['
|
||||
CLOSE_BRACKET = ']'
|
||||
MINUS = '-'
|
||||
EQUALS = '='
|
||||
BACKSPACE = 8
|
||||
HOME = 11
|
||||
DELETE = 127
|
||||
SPACE = ' '
|
||||
KP_0 = 0x100
|
||||
KP_1
|
||||
KP_2
|
||||
KP_3
|
||||
KP_4
|
||||
KP_5
|
||||
KP_6
|
||||
KP_7
|
||||
KP_8
|
||||
KP_9
|
||||
KP_PERIOD = '.' + 0x100
|
||||
KP_ENTER = '\n' + 0x100
|
||||
KP_PLUS = '+' + 0x100
|
||||
KP_MINUS = '-' + 0x100
|
||||
KP_MULTIPLY = '*' + 0x100
|
||||
KP_DIVIDE = '/' + 0x100
|
||||
FN = 0x200
|
||||
F1
|
||||
F2
|
||||
F3
|
||||
F4
|
||||
F5
|
||||
F6
|
||||
F7
|
||||
F8
|
||||
F9
|
||||
F10
|
||||
F11
|
||||
F12
|
||||
F13
|
||||
F14
|
||||
F15
|
||||
F16
|
||||
F17
|
||||
F18
|
||||
F19
|
||||
F20
|
||||
F21
|
||||
F22
|
||||
F23
|
||||
F24
|
||||
POWER_OFF
|
||||
SLEEP
|
||||
WAKE_UP
|
||||
VOLUME_UP
|
||||
VOLUME_DOWN
|
||||
UP
|
||||
DOWN
|
||||
LEFT
|
||||
RIGHT
|
||||
INSERT
|
||||
END
|
||||
PAGE_UP
|
||||
PAGE_DOWN
|
||||
PRINT_SCREEN
|
||||
PAUSE
|
||||
CAPS_LOCK
|
||||
NUM_LOCK
|
||||
SCROLL_LOCK
|
||||
LEFT_SHIFT
|
||||
RIGHT_SHIFT
|
||||
LEFT_CONTROL
|
||||
RIGHT_CONTROL
|
||||
LEFT_ALT
|
||||
RIGHT_ALT
|
||||
LEFT_LOGO
|
||||
RIGHT_LOGO
|
||||
MENU
|
||||
SPECIAL
|
||||
#endif
|
||||
116
include/ui.hhp
Normal file
116
include/ui.hhp
Normal file
@@ -0,0 +1,116 @@
|
||||
#pypp 0
|
||||
#include <iris.hh>
|
||||
#include <devices.hh>
|
||||
|
||||
template <unsigned I, unsigned O> //
|
||||
class UI:
|
||||
struct in_base:
|
||||
UI <I, O> *ui
|
||||
unsigned my_index
|
||||
void (*handle) (in_base *self, void (*cb)(unsigned))
|
||||
void (*send) (in_base *self, Iris::Cap c)
|
||||
in_base () : ui (NULL), my_index (0), handle (NULL), send (NULL):
|
||||
struct out_base:
|
||||
UI <I, O> *ui
|
||||
unsigned my_index
|
||||
void (*send) (out_base *self, Iris::Cap c)
|
||||
out_base () : ui (NULL), my_index (0), send (NULL):
|
||||
|
||||
public:
|
||||
|
||||
void init (Iris::Cap my_cap):
|
||||
Iris::my_parent.provide_capability <Iris::UI> (my_cap)
|
||||
template <typename _T> //
|
||||
class in : public in_base:
|
||||
friend class UI <I, O>
|
||||
_T my_data
|
||||
static void send_impl (in_base *self, Iris::Cap c):
|
||||
c.invoke (self->my_index | Iris::UI::INPUT, reinterpret_cast <in <_T> *> (self)->my_data)
|
||||
static void handle_impl (in_base *self, void (*cb)(unsigned)):
|
||||
in *me = reinterpret_cast <in *> (self)
|
||||
if me->my_data == Iris::recv.data[1].l:
|
||||
return
|
||||
me->my_data = Iris::recv.data[1].l
|
||||
cb (me->my_index)
|
||||
public:
|
||||
void init ():
|
||||
this->send = &send_impl
|
||||
this->handle = &handle_impl
|
||||
operator _T () const:
|
||||
return my_data
|
||||
class in_event : public in_base:
|
||||
friend class UI <I, O>
|
||||
static void send_impl (in_base *self, Iris::Cap c):
|
||||
c.invoke (self->my_index | Iris::UI::INPUT)
|
||||
static void handle_impl (in_base *self, void (*cb)(unsigned)):
|
||||
cb (self->my_index)
|
||||
public:
|
||||
void init ():
|
||||
this->send = &send_impl
|
||||
this->handle = &handle_impl
|
||||
template <typename _T> //
|
||||
class out : public out_base:
|
||||
friend class UI <I, O>
|
||||
_T my_data
|
||||
static void send_impl (out_base *self, Iris::Cap c):
|
||||
c.invoke (self->my_index, reinterpret_cast <out <_T> *> (self)->my_data)
|
||||
public:
|
||||
void init ():
|
||||
this->send = &send_impl
|
||||
out <_T> &operator= (_T const &t):
|
||||
if !this->ui || my_data == t:
|
||||
return *this
|
||||
my_data = t
|
||||
send_impl (this, this->ui->cap)
|
||||
return *this
|
||||
operator _T () const:
|
||||
return my_data
|
||||
class out_event : public out_base:
|
||||
friend class UI <I, O>
|
||||
public:
|
||||
static void send_impl (out_base *self, Iris::Cap c):
|
||||
// Don't send an event. This is only for listing the state.
|
||||
void operator() ():
|
||||
if !this->ui:
|
||||
return
|
||||
this->ui->cap.invoke (this->my_index)
|
||||
void init ():
|
||||
this->send = &send_impl
|
||||
void add_in (in_base *obj, unsigned code):
|
||||
ins[code] = obj
|
||||
obj->ui = this
|
||||
obj->my_index = code
|
||||
void add_out (out_base *obj, unsigned code):
|
||||
outs[code] = obj
|
||||
obj->ui = this
|
||||
obj->my_index = code
|
||||
bool event (void (*cb)(unsigned)):
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::UI::EXIT:
|
||||
Iris::recv.reply.invoke ()
|
||||
return false
|
||||
case Iris::UI::GET_STATE:
|
||||
if cap.code != CAP_NONE:
|
||||
Iris::free_cap (cap)
|
||||
cap = Iris::get_arg ()
|
||||
Iris::recv.reply.invoke ()
|
||||
for unsigned i = 0; i < I; ++i:
|
||||
ins[i]->send (ins[i], cap)
|
||||
for unsigned i = 0; i < O; ++i:
|
||||
outs[i]->send (outs[i], cap)
|
||||
break
|
||||
case Iris::UI::EVENT:
|
||||
Iris::Cap r = Iris::get_reply ()
|
||||
if Iris::recv.data[0].h >= I:
|
||||
Iris::panic (Iris::recv.data[0].h, "invalid input requested by ui")
|
||||
ins[Iris::recv.data[0].h]->handle (ins[Iris::recv.data[0].h], cb)
|
||||
r.invoke ()
|
||||
Iris::free_cap (r)
|
||||
break
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid request for ui")
|
||||
return true
|
||||
private:
|
||||
in_base *ins[I]
|
||||
out_base *outs[O]
|
||||
Iris::Cap cap
|
||||
Reference in New Issue
Block a user