mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-29 02:39:53 +02:00
fix bugs; work on userspace
This commit is contained in:
parent
906f487b01
commit
afb496f20b
97
alloc.ccp
97
alloc.ccp
@ -308,6 +308,8 @@ void kMemory::free_thread (kThread *thread):
|
||||
free_obj (thread, (void **)&threads)
|
||||
|
||||
void kMemory::free_message (kReceiver *owner, kMessage *message):
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
message->caps.cap (i)->invalidate ()
|
||||
if !message->next:
|
||||
owner->last_message = (kMessageP)message->prev
|
||||
free_obj (message, (void **)&owner->messages)
|
||||
@ -405,3 +407,98 @@ void kPage::forget ():
|
||||
frame = 0
|
||||
flags &= ~(Kernel::Page::FRAME | Kernel::Page::SHARED | Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
|
||||
kPage_arch_update_mapping (this)
|
||||
|
||||
static void check_receiver (kReceiver *r, kCapRef cap, unsigned line):
|
||||
if (unsigned)cap->target & ~KERNEL_MASK:
|
||||
if cap->target != r:
|
||||
dpanic (line, "consistency bug in capabilities")
|
||||
else:
|
||||
if cap->protected_data.l != (unsigned)r:
|
||||
dbg_log ("Buggy: ")
|
||||
dbg_log_num ((unsigned)r)
|
||||
dbg_log (" ")
|
||||
dbg_log_num ((unsigned)cap.caps)
|
||||
dbg_log (" ")
|
||||
dbg_log_num ((unsigned)cap.caps->address_space)
|
||||
dbg_log (" ")
|
||||
dbg_log_num ((unsigned)cap.deref ())
|
||||
dbg_log (" ")
|
||||
dbg_log_num ((unsigned)cap->target)
|
||||
dbg_log ("/")
|
||||
dbg_log_num (cap->protected_data.l)
|
||||
dbg_log ("\n")
|
||||
dpanic (line, "consistency bug in kernel capabilities")
|
||||
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
|
||||
check_receiver (r, c, line)
|
||||
|
||||
void kReceiver::check (unsigned line):
|
||||
for kCapRef cap = capabilities; cap.valid (); cap = cap->sibling_next:
|
||||
check_receiver (this, cap, line)
|
||||
|
||||
void kMemory::check (unsigned line):
|
||||
for kReceiver *r = receivers; r; r = (kReceiver *)r->next:
|
||||
r->check (line)
|
||||
for kMemory *m = memories; m; m = (kMemory *)m->next:
|
||||
m->check (line)
|
||||
|
||||
static void print_obj (kObject *o):
|
||||
for kObject *obj = o; o; o = (kObject *)o->next:
|
||||
dbg_log_num ((unsigned)o)
|
||||
dbg_log ("->")
|
||||
dbg_log ("NULL\n")
|
||||
|
||||
void kMemory::print (unsigned line, unsigned indent):
|
||||
if indent == 0:
|
||||
print_free ()
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
dbg_log_char ('\t')
|
||||
++indent
|
||||
dbg_log ("Memory ")
|
||||
dbg_log_num ((unsigned)this)
|
||||
dbg_log ("\n")
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
dbg_log_char ('\t')
|
||||
dbg_log ("frees: ")
|
||||
for kFree *f = frees; f; f = (kFree *)f->next:
|
||||
dbg_log_num ((unsigned)f)
|
||||
dbg_log (":")
|
||||
unsigned n = (unsigned)NEXT (f)
|
||||
if n:
|
||||
n -= (unsigned)f
|
||||
if n >= PAGE_SIZE:
|
||||
dpanic (0, "invalid kFree")
|
||||
dbg_log_num (n, 3)
|
||||
dbg_log ("->")
|
||||
dbg_log ("NULL\n")
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
dbg_log_char ('\t')
|
||||
dbg_log ("pages: ")
|
||||
print_obj (pages)
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
dbg_log_char ('\t')
|
||||
dbg_log ("threads: ")
|
||||
print_obj (threads)
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
dbg_log_char ('\t')
|
||||
dbg_log ("receivers: ")
|
||||
for kReceiver *r = receivers; r; r = (kReceiver *)r->next:
|
||||
dbg_log_num ((unsigned)r)
|
||||
dbg_log ("(")
|
||||
for kMessage *m = r->messages; m; m = (kMessage *)m->next:
|
||||
dbg_log_num ((unsigned)m)
|
||||
dbg_log ("->")
|
||||
dbg_log ("NULL)->")
|
||||
dbg_log ("NULL\n")
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
dbg_log_char ('\t')
|
||||
dbg_log ("capses: ")
|
||||
print_obj (capses)
|
||||
for kMemory *m = memories; m; m = (kMemory *)m->next:
|
||||
m->print (line, indent)
|
||||
|
||||
void check_impl (kObject *o, unsigned num, char const *msg):
|
||||
for ; o; o = (kObject *)o->next:
|
||||
unsigned n = (unsigned)NEXT (o)
|
||||
unsigned size = n ? n - (unsigned)o : PAGE_SIZE - ((unsigned)o & PAGE_MASK)
|
||||
if !check_free (o, size):
|
||||
panic (num, msg)
|
||||
|
@ -23,10 +23,9 @@
|
||||
class DevBuzzer:
|
||||
static unsigned const pwm = 4
|
||||
Kernel::Cap event
|
||||
bool is_active, is_beeping
|
||||
bool is_beeping
|
||||
public:
|
||||
DevBuzzer ():
|
||||
is_active = false
|
||||
is_beeping = false
|
||||
gpio_as_pwm4 ()
|
||||
tcu_stop_counter (pwm)
|
||||
@ -38,8 +37,8 @@ class DevBuzzer:
|
||||
return
|
||||
tcu_stop_counter (pwm)
|
||||
event.invoke ()
|
||||
is_active = false
|
||||
Kernel::free_cap (event)
|
||||
is_beeping = false
|
||||
void beep (unsigned freq, unsigned ms, Kernel::Cap cb):
|
||||
stop ()
|
||||
event = cb
|
||||
@ -115,12 +114,11 @@ Kernel::Num start ():
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Buzzer::BEEP:
|
||||
// Volume is not used for this buzzer.
|
||||
// Volume is not used by this buzzer.
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
buzzer.beep (Kernel::recv.data[1].l, Kernel::recv.data[1].h, arg)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (arg)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Buzzer::STOP:
|
||||
|
@ -17,6 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "iris.hh"
|
||||
#include "devices.hh"
|
||||
|
||||
// For some unknown reason, gcc needs this to be defined.
|
||||
unsigned __gxx_personality_v0
|
||||
@ -33,7 +34,7 @@ namespace Kernel:
|
||||
Thread my_thread
|
||||
Memory my_memory
|
||||
Cap my_call
|
||||
Cap my_parent
|
||||
Parent my_parent
|
||||
__recv_data_t recv
|
||||
|
||||
void print_caps ():
|
||||
|
@ -19,28 +19,50 @@
|
||||
#include "devices.hh"
|
||||
#include "iris.hh"
|
||||
|
||||
static Keyboard kbd, sysreq
|
||||
static Buzzer buzzer
|
||||
static Keyboard sysreq
|
||||
static Device kbd_dev, buz_dev
|
||||
static List <String> kbd_names
|
||||
static unsigned slot
|
||||
|
||||
// Event types.
|
||||
enum type:
|
||||
MEMORY
|
||||
KBDDEV
|
||||
KBD
|
||||
KEYNAMES
|
||||
SYSREQ
|
||||
KBDDEV
|
||||
BUZDEV
|
||||
BUZZER
|
||||
|
||||
static void user_reply (Kernel::Cap target, unsigned dev):
|
||||
switch dev:
|
||||
case Keyboard::ID:
|
||||
// keyboard user
|
||||
kdebug ("keyboard requested\n")
|
||||
Kernel::Cap kbd = kbd_dev.create_user (Kernel::Cap ())
|
||||
kbd_dev.use (kbd)
|
||||
target.invoke (0, 0, kbd.copy ())
|
||||
Kernel::free_cap (kbd)
|
||||
break
|
||||
case Buzzer::ID:
|
||||
// buzzer user
|
||||
kdebug ("buzzer requested\n")
|
||||
Kernel::Cap buzzer = buz_dev.create_user (Kernel::Cap ())
|
||||
buz_dev.use (buzzer)
|
||||
kdebug ("invoking reply: ")
|
||||
kdebug_num (target.code)
|
||||
kdebug ("\n")
|
||||
target.invoke (0, 0, buzzer.copy ())
|
||||
Kernel::free_cap (buzzer)
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid id requested:")
|
||||
kdebug_num (dev)
|
||||
kdebug_char ('\n')
|
||||
break
|
||||
|
||||
static void setup ():
|
||||
unsigned state = 0
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (32)
|
||||
slot = caps.use ()
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, MEMORY))
|
||||
Kernel::Cap driver_memory = Kernel::my_memory.create_memory ()
|
||||
Kernel::Caps slot0 = Kernel::my_thread.get_caps (0)
|
||||
Kernel::Cap user
|
||||
unsigned device
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
@ -59,44 +81,38 @@ static void setup ():
|
||||
default:
|
||||
kdebug ("unexpected keyboard\n")
|
||||
break
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Buzzer::ID:
|
||||
caps.set (BUZDEV, arg.copy ())
|
||||
buz_dev = Kernel::Cap (slot, BUZDEV)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Parent::GET_DEVICE:
|
||||
user = reply
|
||||
device = Kernel::recv.data[1].l
|
||||
slot0.print (reply.idx ())
|
||||
break
|
||||
default:
|
||||
kdebug ("unknown setup request for init\n")
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
kdebug ("unknown setup request for init\n")
|
||||
continue
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
if ++state == 3:
|
||||
if ++state == 4:
|
||||
break
|
||||
// sysreq
|
||||
kdebug ("using sysreq\n")
|
||||
Kernel::Cap cb = Kernel::my_receiver.create_capability (SYSREQ)
|
||||
sysreq.set_cb (cb.copy ())
|
||||
// keyboard user
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, KBD))
|
||||
kbd = kbd_dev.create_user (driver_memory)
|
||||
kbd_dev.use (kbd)
|
||||
// keyboard callback
|
||||
Kernel::set_recv_arg (cb)
|
||||
Kernel::my_receiver.create_capability (KBD)
|
||||
kbd.set_cb (cb.copy ())
|
||||
// keyboard name list
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, KEYNAMES))
|
||||
kbd_names = kbd.get_keys ()
|
||||
// buzzer user
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, BUZZER))
|
||||
buzzer = buz_dev.create_user (driver_memory)
|
||||
buz_dev.use (buzzer)
|
||||
// clean up.
|
||||
Kernel::free_cap (cb)
|
||||
|
||||
//char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
|
||||
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$*T\nE& B=UDLR+-F^CA"
|
||||
// First user reply.
|
||||
kdebug ("sending first user reply\n")
|
||||
user_reply (user, device)
|
||||
Kernel::free_cap (user)
|
||||
|
||||
Kernel::Num start ():
|
||||
setup ()
|
||||
@ -112,20 +128,11 @@ Kernel::Num start ():
|
||||
else:
|
||||
kdebug ("pressed.\n\n")
|
||||
break
|
||||
case KBD:
|
||||
unsigned code = Kernel::recv.data[0].l
|
||||
if code & Keyboard::RELEASE:
|
||||
kdebug_char ('-')
|
||||
else:
|
||||
kdebug_char ('+')
|
||||
buzzer.beep (2000, 100, 0)
|
||||
String name = kbd_names.get (code & ~Keyboard::RELEASE)
|
||||
unsigned size = name.get_size ().l
|
||||
char buffer[16]
|
||||
for unsigned i = 0; i < size; i += 16:
|
||||
name.get_chars (i, buffer)
|
||||
for unsigned k = 0; k < size - i && k < 16; ++k:
|
||||
kdebug_char (buffer[k])
|
||||
kdebug_char ('\n')
|
||||
Kernel::free_cap (name)
|
||||
default:
|
||||
if Kernel::recv.data[0].l != Parent::GET_DEVICE:
|
||||
kdebug ("invalid call from user\n")
|
||||
break
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
user_reply (reply, Kernel::recv.data[1].l)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
|
@ -27,9 +27,15 @@ extern unsigned char const charset[127-32][6]
|
||||
|
||||
#define assert(x) do { while (!(x)) kdebug ("assertion failed " #x); } while (0)
|
||||
|
||||
#if defined (TRENDTAC)
|
||||
// For now, support only 16 bpp.
|
||||
// Screen is 800x480 tft.
|
||||
static unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2
|
||||
#else if defined (NANONOTE)
|
||||
static unsigned h = 320, v = 240, fps = 70, Bpp = 3
|
||||
#else
|
||||
#error unknown board
|
||||
#endif
|
||||
#define frame_size (v * h * Bpp)
|
||||
|
||||
static unsigned physical_descriptor
|
||||
@ -40,21 +46,49 @@ struct Descriptor:
|
||||
unsigned id
|
||||
unsigned cmd
|
||||
|
||||
#if defined (TRENDTAC)
|
||||
static void reset ():
|
||||
LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16
|
||||
LCD_VSYNC = vs
|
||||
LCD_HSYNC = hs
|
||||
LCD_DAV = (vs << 16) | (vs + v)
|
||||
LCD_DAH = (hs << 16) | (hs + h)
|
||||
LCD_VAT = ((hs + h) << 16) | (vs + v)
|
||||
#if defined (TRENDTAC)
|
||||
unsigned fps = 60
|
||||
// Vertical timings.
|
||||
unsigned vps = 0, vpe = vps + 20, vds = vpe, vde = vds + v, vt = vde
|
||||
// Horizontal timings.
|
||||
unsigned hps = 0, hpe = hps + 80, hds = hpe, hde = hds + h, ht = hde
|
||||
unsigned extra = 0
|
||||
// Bits per pixel.
|
||||
unsigned bpp = LCD_CTRL_BPP_16
|
||||
// Configuration.
|
||||
#define MODE_TFT_GEN 0
|
||||
#define VSYNC_N (1 << 8)
|
||||
LCD_CFG = MODE_TFT_GEN | VSYNC_N
|
||||
unsigned cfg = MODE_TFT_GEN | VSYNC_N
|
||||
#elif defined (NANONOTE)
|
||||
unsigned fps = 70
|
||||
// Vertical timings.
|
||||
unsigned vps = 0, vpe = vps + 1, vds = vpe + 20, vde = vds + v, vt = vde + 1
|
||||
// Horizontal timings.
|
||||
unsigned hps = 0, hpe = hps + 1, hds = hpe + 140, hde = hds + h, ht = hde + 273
|
||||
// 3 bytes per pixel, so for the display area 2 extra clocks are sent.
|
||||
unsigned extra = 2
|
||||
// Bits per pixel.
|
||||
unsigned bpp = LCD_CTRL_BPP_18_24
|
||||
// Configuration.
|
||||
unsigned cfg = LCD_CFG_MODE_TFT_SERIAL_TFT | LCD_CFG_PCP | LCD_CFG_HSP | LCD_CFG_VSP
|
||||
#else
|
||||
#error unknown board
|
||||
#endif
|
||||
|
||||
LCD_CTRL = bpp | LCD_CTRL_BST_16
|
||||
LCD_VSYNC = (vps << 16) | vpe
|
||||
LCD_HSYNC = (hps << 16) | hpe
|
||||
LCD_DAV = (vds << 16) | vde
|
||||
LCD_DAH = (hds << 16) | hde
|
||||
LCD_VAT = (ht << 16) | vt
|
||||
LCD_CFG = cfg
|
||||
|
||||
cpm_stop_lcd ()
|
||||
|
||||
unsigned pixclock = fps * (hs + h) * (vs + v)
|
||||
unsigned pixclock = fps * (ht + extra * (hde - hds)) * vt
|
||||
|
||||
#if defined (TRENDTAC)
|
||||
unsigned pllout = cpm_get_pllout ()
|
||||
CPM_CFCR2 = pllout / pixclock - 1
|
||||
|
||||
@ -63,18 +97,29 @@ static void reset ():
|
||||
assert (val <= 0xf)
|
||||
cpm_set_lcdclk_div (val)
|
||||
CPM_CFCR |= CPM_CFCR_UPE
|
||||
#elif defined (NANONOTE)
|
||||
unsigned val = cpm_get_pllout2 () / pclk - 1
|
||||
if val > 0x3ff:
|
||||
kdebug ("pixel clock too large\n")
|
||||
Kernel::panic ()
|
||||
return
|
||||
cpm_set_pixdiv (val);
|
||||
|
||||
val = cpm_get_pllout () / (pixclock * 3)
|
||||
if val > 0x1f:
|
||||
kdebug ("pixel divider too large\n")
|
||||
Kernel::panic ()
|
||||
return
|
||||
cpm_set_ldiv (val)
|
||||
// Update dividers.
|
||||
CPM_CPCCR |= CPM_CPCCR_CE
|
||||
#endif
|
||||
|
||||
cpm_start_lcd ()
|
||||
|
||||
LCD_DA0 = physical_descriptor
|
||||
lcd_set_ena ()
|
||||
lcd_enable_eof_intr ()
|
||||
#elif defined (NANONOTE)
|
||||
static void reset ():
|
||||
// TODO
|
||||
#else
|
||||
#error unknown board
|
||||
#endif
|
||||
|
||||
static void putchar (unsigned x, unsigned y, unsigned ch, unsigned fg = 0xffff, unsigned bg = 0x0000):
|
||||
if ch < 32 || ch > 126:
|
||||
@ -83,19 +128,19 @@ static void putchar (unsigned x, unsigned y, unsigned ch, unsigned fg = 0xffff,
|
||||
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[charset[ch][k] & (1 << r) ? 1 : 0]
|
||||
LCD_FRAMEBUFFER_BASE[(y * 8 + r) * h + x * 6 + k] = lookup[charset[ch][k] & (1 << r) ? 1 : 0]
|
||||
|
||||
static unsigned log_x = 1, log_y = 1
|
||||
static void inc_logx ():
|
||||
if ++log_x >= 800 / 6:
|
||||
if ++log_x >= h / 6:
|
||||
log_x = 1
|
||||
if ++log_y >= 480 / 8:
|
||||
if ++log_y >= v / 8:
|
||||
log_y = 1
|
||||
|
||||
static void log_char (unsigned ch):
|
||||
switch ch:
|
||||
case '\n':
|
||||
while log_x < 800 / 6:
|
||||
while log_x < h / 6:
|
||||
putchar (log_x++, log_y, ' ')
|
||||
inc_logx ()
|
||||
break
|
||||
@ -138,22 +183,22 @@ Kernel::Num start ():
|
||||
p.alloc_physical (physical + i * PAGE_SIZE, false, true)
|
||||
Kernel::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE)
|
||||
Kernel::free_cap (p)
|
||||
for unsigned y = 0; y < 480; ++y:
|
||||
unsigned g = (y << 6) / 480
|
||||
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
|
||||
for unsigned x = 0; x < 800; ++x:
|
||||
unsigned r = (x << 5) / 800
|
||||
unsigned b = ((9 * x * x + 25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
|
||||
for unsigned y = 0; y < v; ++y:
|
||||
unsigned g = (y << 6) / v
|
||||
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * h * h + 25 * v * v)
|
||||
for unsigned x = 0; x < h; ++x:
|
||||
unsigned r = (x << 5) / h
|
||||
unsigned b = ((9 * x * x + 25 * y * y) << 5) / (9 * h * h + 25 * v * v)
|
||||
if r != olr:
|
||||
olr = r
|
||||
r = 0x1f
|
||||
unsigned oyb = b
|
||||
if y > 0:
|
||||
oyb = ((9 * x * x + 25 * (y - 1) * (y - 1)) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
|
||||
oyb = ((9 * x * x + 25 * (y - 1) * (y - 1)) << 5) / (9 * h * h + 25 * v * v)
|
||||
if b != ob || b != oyb:
|
||||
ob = b
|
||||
b = 0x1f
|
||||
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
|
||||
LCD_FRAMEBUFFER_BASE[y * h + x] = (r << 11) | (g << 5) | (b)
|
||||
Kernel::Page p = Kernel::my_memory.mapping (&descriptor)
|
||||
physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK)
|
||||
Kernel::free_cap (p)
|
||||
@ -166,11 +211,12 @@ Kernel::Num start ():
|
||||
reset ()
|
||||
|
||||
Kernel::Cap logcap = Kernel::my_receiver.create_capability (Init::LCD_LOG)
|
||||
#if defined (TRENDTAC)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
||||
#endif
|
||||
|
||||
((Init)Kernel::my_parent).register_lcd ()
|
||||
|
||||
Kernel::Cap eof_cb = Kernel::alloc_cap ()
|
||||
Kernel::Cap eof_cb
|
||||
bool have_eof = false
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
//log_msg ()
|
||||
@ -180,11 +226,15 @@ Kernel::Num start ():
|
||||
eof_cb.invoke ()
|
||||
break
|
||||
case Init::LCD_SET_EOF_CB:
|
||||
Kernel::free_cap (eof_cb)
|
||||
eof_cb = Kernel::recv.arg
|
||||
Kernel::recv.arg = Kernel::alloc_cap ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
if have_eof:
|
||||
Kernel::free_cap (eof_cb)
|
||||
else:
|
||||
have_eof = true
|
||||
eof_cb = Kernel::get_arg ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::register_interrupt (IRQ_LCD)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Init::LCD_LOG:
|
||||
log_char (Kernel::recv.data[0].l)
|
||||
|
70
boot-programs/metronome.ccp
Normal file
70
boot-programs/metronome.ccp
Normal file
@ -0,0 +1,70 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/metronome.ccp: Userspace program.
|
||||
// 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/>.
|
||||
|
||||
#include "devices.hh"
|
||||
#include "keys.hh"
|
||||
|
||||
Kernel::Num start ():
|
||||
kdebug ("metronome started\n")
|
||||
Buzzer buzzer = Kernel::my_parent.get_device <Buzzer> ()
|
||||
Keyboard kbd = Kernel::my_parent.get_device <Keyboard> ()
|
||||
Kernel::Cap key = Kernel::my_receiver.create_capability (0)
|
||||
kbd.set_cb (key)
|
||||
unsigned mHz = 1000
|
||||
unsigned freq = 1000
|
||||
Kernel::my_receiver.set_alarm (1)
|
||||
bool running (true)
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.l:
|
||||
case ~0:
|
||||
if running:
|
||||
buzzer.beep (freq, 10, ~0)
|
||||
Kernel::my_receiver.set_alarm (HZ * 1000 / mHz)
|
||||
break
|
||||
case 0:
|
||||
if Kernel::recv.data[0].l & Keyboard::RELEASE:
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Key::VOLUME_UP:
|
||||
freq = freq * 11 / 10
|
||||
break
|
||||
case Key::VOLUME_DOWN:
|
||||
freq = freq * 9 / 10
|
||||
break
|
||||
case Key::LEFT:
|
||||
mHz = mHz * 101 / 100
|
||||
break
|
||||
case Key::RIGHT:
|
||||
mHz = mHz * 99 / 100
|
||||
break
|
||||
case Key::UP:
|
||||
mHz = mHz * 11 / 10
|
||||
break
|
||||
case Key::DOWN:
|
||||
mHz = mHz * 9 / 10
|
||||
break
|
||||
case Key::P:
|
||||
running = !running
|
||||
if running:
|
||||
Kernel::my_receiver.set_alarm (1)
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("huh?\n")
|
||||
break
|
@ -19,6 +19,7 @@
|
||||
#include "devices.hh"
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
#include "keys.hh"
|
||||
|
||||
//#define QI
|
||||
#define SCAN_INTERVAL HZ / 50
|
||||
@ -33,27 +34,8 @@ class DevKbd:
|
||||
static unsigned const COLS[NUM_COLS]
|
||||
static unsigned const ROWS[NUM_ROWS]
|
||||
static unsigned const encode[NUM_ROWS][NUM_COLS]
|
||||
enum Keys:
|
||||
#ifdef QI
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M
|
||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z
|
||||
F1, F2, F3, F4, F5, F6, F7, F8
|
||||
TAB, BACKSLASH, QUOTE, COMMA, PERIOD, SLASH, EQUAL, SPACE
|
||||
ESCAPE, ENTER, BACKSPACE
|
||||
UP, DOWN, LEFT, RIGHT
|
||||
CAPS, ARROW, QI, CTRL, VOLUP, VOLDOWN, SHIFT, ALT, FN
|
||||
#else
|
||||
N0, N1, N2, N3, N4, N5, N6, N7, N8, N9
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M
|
||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z
|
||||
F1, F2, F3, F4
|
||||
CAPS, TAB, ENTER, ESCAPE, MP3, SPACE, BACKSPACE, EQUALS
|
||||
UP, DOWN, LEFT, RIGHT
|
||||
VOLUP, VOLDOWN
|
||||
FN, SHIFT, CTRL, ALT
|
||||
#endif
|
||||
NUM_KEYS
|
||||
static char const *const names[NUM_KEYS]
|
||||
static unsigned const NUM_KEYS = 58
|
||||
static unsigned const keys[NUM_KEYS]
|
||||
unsigned state[NUM_COLS]
|
||||
Kernel::Cap event
|
||||
bool is_active
|
||||
@ -61,27 +43,14 @@ class DevKbd:
|
||||
public:
|
||||
unsigned size ():
|
||||
return NUM_KEYS
|
||||
unsigned get_name_size (unsigned n):
|
||||
if n >= NUM_KEYS:
|
||||
return 0
|
||||
unsigned ret = 0
|
||||
for char const *p = names[n]; *p; ++p:
|
||||
++ret
|
||||
return ret
|
||||
void send_name (unsigned n, Kernel::Cap c, Kernel::Num offset):
|
||||
if n >= NUM_KEYS:
|
||||
c.invoke (0, 0)
|
||||
return
|
||||
unsigned data[4]
|
||||
char *d = (char *)data
|
||||
if offset.value () < get_name_size (n):
|
||||
unsigned o = offset.l & ~3;
|
||||
unsigned p
|
||||
for p = 0; p < 16 && names[n][p + o]; ++p:
|
||||
*d++ = names[n][p + o]
|
||||
for ; p < 16; ++p:
|
||||
*d++ = 0
|
||||
c.invoke (Kernel::Num (data[0], data[1]), Kernel::Num (data[2], data[3]))
|
||||
void send_keys (unsigned first, Kernel::Cap target):
|
||||
unsigned d[4]
|
||||
unsigned i
|
||||
for i = 0; first + i < NUM_KEYS && i < 4; ++i:
|
||||
d[i] = keys[first + i]
|
||||
for ; i < 4; ++i:
|
||||
d[i] = ~0
|
||||
target.invoke (Kernel::Num (d[0], d[1]), Kernel::Num (d[2], d[3]))
|
||||
bool scanning ():
|
||||
return is_scanning
|
||||
void inactive ():
|
||||
@ -155,43 +124,44 @@ unsigned const DevKbd::COLS[NUM_COLS] = { 10, 11, 12, 13, 14, 15, 16, 17 }
|
||||
unsigned const DevKbd::ROWS[NUM_ROWS] = { 18, 19, 20, 21, 22, 23, 24, 26 }
|
||||
unsigned const DevKbd::encode[NUM_ROWS][NUM_COLS] = {
|
||||
#ifdef QI
|
||||
{ F1, F2, F3, F4, F5, F6, F7, ~0 },
|
||||
{ Q, W, E, R, T, Y, U, I },
|
||||
{ A, S, D, F, G, H, J, K },
|
||||
{ ESCAPE, Z, X, C, V, B, N, M },
|
||||
{ TAB, CAPS, BACKSLASH, QUOTE, COMMA, PERIOD, SLASH, UP },
|
||||
{ O, L, EQUAL, ARROW, SPACE, QI, CTRL, LEFT },
|
||||
{ F8, P, BACKSPACE, ENTER, VOLUP, VOLDOWN, DOWN, RIGHT },
|
||||
{ SHIFT, ALT, FN, ~0, ~0, ~0, ~0, ~0 }
|
||||
{ Key::F1, Key::F2, Key::F3, Key::F4, Key::F5, Key::F6, Key::F7, ~0 },
|
||||
{ Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I },
|
||||
{ Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K },
|
||||
{ Key::ESCAPE, Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M },
|
||||
{ Key::TAB, Key::CAPS, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP },
|
||||
{ Key::O, Key::L, Key::EQUAL, Key::ARROW, Key::SPACE, Key::QI, Key::CTRL, Key::LEFT },
|
||||
{ Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT },
|
||||
{ Key::SHIFT, Key::ALT, Key::FN, ~0, ~0, ~0, ~0, ~0 }
|
||||
#else
|
||||
{ ESCAPE, TAB, F1, F2, F3, F4, MP3, ~0 },
|
||||
{ N1, N2, N3, N4, N5, N6, N7, N8 },
|
||||
{ Q, W, E, R, T, Y, U, I },
|
||||
{ A, S, D, F, G, H, J, K },
|
||||
{ Z, X, C, V, B, N, M, UP },
|
||||
{ N9, O, L, ALT, CAPS, SPACE, EQUALS, LEFT },
|
||||
{ BACKSPACE, N0, P, ENTER, VOLUP, VOLDOWN, DOWN, RIGHT },
|
||||
{ FN, SHIFT, CTRL, ~0, ~0, ~0, ~0, ~0 }
|
||||
{ Key::ESCAPE, Key::TAB, Key::F1, Key::F2, Key::F3, Key::F4, Key::SPECIAL + 0, ~0 },
|
||||
{ Key::N1, Key::N2, Key::N3, Key::N4, Key::N5, Key::N6, Key::N7, Key::N8 },
|
||||
{ Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I },
|
||||
{ Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K },
|
||||
{ Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M, Key::UP },
|
||||
{ Key::N9, Key::O, Key::L, Key::LEFT_ALT, Key::CAPS_LOCK, Key::SPACE, Key::EQUALS, Key::LEFT },
|
||||
{ Key::BACKSPACE, Key::N0, Key::P, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT },
|
||||
{ Key::FN, Key::LEFT_SHIFT, Key::LEFT_CONTROL, ~0, ~0, ~0, ~0, ~0 }
|
||||
#endif
|
||||
}
|
||||
char const *const DevKbd::names[NUM_KEYS] = {
|
||||
unsigned const DevKbd::keys[NUM_KEYS] = {
|
||||
#ifdef QI
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
|
||||
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8",
|
||||
"tab", "\\", "'", ",", ".", "/", "=", "space",
|
||||
"escape", "enter", "backspace",
|
||||
"up", "down", "left", "right",
|
||||
"caps lock", "arrow", "qi", "left control", "volume up", "volume down", "left shift", "left alt", "fn"
|
||||
Key::F1, Key::F2, Key::F3, Key::F4, Key::F5, Key::F6, Key::F7,
|
||||
Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I,
|
||||
Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K,
|
||||
Key::ESCAPE, Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M,
|
||||
Key::TAB, Key::CAPS, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP,
|
||||
Key::O, Key::L, Key::EQUAL, Key::ARROW, Key::SPACE, Key::QI, Key::CTRL, Key::LEFT,
|
||||
Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT,
|
||||
Key::SHIFT, Key::ALT, Key::FN
|
||||
#else
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
|
||||
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"f1", "f2", "f3", "f4",
|
||||
"caps lock", "tab", "enter", "escape", "mp3", "space", "backspace", "=",
|
||||
"up", "down", "left", "right",
|
||||
"volume up", "volume down",
|
||||
"fn", "left shift", "left control", "left alt"
|
||||
Key::ESCAPE, Key::TAB, Key::F1, Key::F2, Key::F3, Key::F4, Key::SPECIAL + 0,
|
||||
Key::N1, Key::N2, Key::N3, Key::N4, Key::N5, Key::N6, Key::N7, Key::N8,
|
||||
Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I,
|
||||
Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K,
|
||||
Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M, Key::UP,
|
||||
Key::N9, Key::O, Key::L, Key::LEFT_ALT, Key::CAPS_LOCK, Key::SPACE, Key::EQUALS, Key::LEFT,
|
||||
Key::BACKSPACE, Key::N0, Key::P, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT,
|
||||
Key::FN, Key::LEFT_SHIFT, Key::LEFT_CONTROL
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -222,12 +192,10 @@ class PowerButton:
|
||||
|
||||
enum codes:
|
||||
KBD_DEV = 32
|
||||
KBD_LIST
|
||||
PWR
|
||||
|
||||
Kernel::Num start ():
|
||||
map_gpio ()
|
||||
map_tcu ()
|
||||
|
||||
DevKbd kbd
|
||||
PowerButton pwr
|
||||
@ -242,7 +210,6 @@ Kernel::Num start ():
|
||||
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
unsigned user (~0)
|
||||
unsigned next_user (0)
|
||||
List <String> list = List <String> (Kernel::my_receiver.create_capability (KBD_LIST))
|
||||
Kernel::register_interrupt (IRQ_GPIO3)
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
@ -307,24 +274,6 @@ Kernel::Num start ():
|
||||
kdebug ("\n")
|
||||
break
|
||||
break
|
||||
case KBD_LIST:
|
||||
// Keyboard name lookup.
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Kernel::Caps::GET:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
unsigned num = Kernel::recv.data[1].l
|
||||
Kernel::Cap name = Kernel::my_receiver.create_capability (Kernel::Num (num, KBD_LIST))
|
||||
reply.invoke (kbd.get_name_size (num), 0, name.copy ())
|
||||
Kernel::free_cap (name)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Kernel::Caps::GET_SIZE:
|
||||
Kernel::recv.reply.invoke (kbd.size ())
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid list operation\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
break
|
||||
break
|
||||
@ -337,29 +286,23 @@ Kernel::Num start ():
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Keyboard::SET_CB:
|
||||
kdebug ("set cb\n")
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
kbd.active (Kernel::get_arg ())
|
||||
Kernel::recv.reply.invoke ()
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Keyboard::GET_NUM_KEYS:
|
||||
kdebug ("get #keys\n")
|
||||
Kernel::recv.reply.invoke (kbd.size ())
|
||||
break
|
||||
case Keyboard::GET_KEYS:
|
||||
kdebug ("get keys\n")
|
||||
Kernel::recv.reply.invoke (0, 0, list)
|
||||
kbd.send_keys (Kernel::recv.data[0].l, Kernel::recv.reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("other\n")
|
||||
break
|
||||
break
|
||||
case KBD_LIST:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case String::GET_SIZE:
|
||||
Kernel::recv.reply.invoke (kbd.get_name_size (Kernel::recv.protected_data.l))
|
||||
break
|
||||
case String::GET_CHARS:
|
||||
kbd.send_name (Kernel::recv.protected_data.l, Kernel::recv.reply, Kernel::recv.data[1])
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid string operation\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("unknown num: ")
|
||||
kdebug_num (Kernel::recv.protected_data.h)
|
||||
|
@ -75,11 +75,26 @@ struct WString : public String:
|
||||
void set_page (Kernel::Num idx, Kernel::Page page):
|
||||
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
|
||||
|
||||
// Interface for talking to the parent process.
|
||||
struct Parent : public Kernel::Cap:
|
||||
Parent (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
GET_DEVICE = WString::ID
|
||||
EXIT
|
||||
ID
|
||||
// Get a device handle.
|
||||
template <typename _T> _T get_device (unsigned num = 0):
|
||||
icall (CAP_MASTER_DIRECT | GET_DEVICE, Kernel::Num (_T::ID, num))
|
||||
return Kernel::get_arg ()
|
||||
// Exit the program. The parent does not reply, but kills the process.
|
||||
void exit (Kernel::Num code):
|
||||
call (CAP_MASTER_DIRECT | EXIT, code)
|
||||
|
||||
// Every process which wants to be switchable through a terminal must implement this interface.
|
||||
struct Device : public Kernel::Cap:
|
||||
Device (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
CREATE_USER = WString::ID
|
||||
CREATE_USER = Parent::ID
|
||||
DESTROY_USER
|
||||
UNUSE
|
||||
USE
|
||||
@ -104,6 +119,7 @@ struct Keyboard : public Kernel::Cap:
|
||||
Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
SET_CB = Device::ID
|
||||
GET_NUM_KEYS
|
||||
GET_KEYS
|
||||
ID
|
||||
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
|
||||
@ -112,10 +128,10 @@ struct Keyboard : public Kernel::Cap:
|
||||
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately.
|
||||
void set_cb (Kernel::Cap cb):
|
||||
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
||||
// Get a list of keys on this keyboard. The key codes start at zero with no gaps.
|
||||
List <String> get_keys ():
|
||||
icall (CAP_MASTER_DIRECT | GET_KEYS)
|
||||
return List <String> (Kernel::get_arg ())
|
||||
unsigned get_num_keys ():
|
||||
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
|
||||
void get_keys (unsigned first):
|
||||
call (CAP_MASTER_DIRECT | GET_KEYS, first)
|
||||
|
||||
// Buzzer interface.
|
||||
struct Buzzer : public Kernel::Cap:
|
84
invoke.ccp
84
invoke.ccp
@ -19,33 +19,32 @@
|
||||
#include "kernel.hh"
|
||||
|
||||
static void log_message (char const *prefix, unsigned target, unsigned pdata, kCapability::Context *c):
|
||||
if !dbg_code.l:
|
||||
dbg_log (prefix)
|
||||
dbg_log (": caller=")
|
||||
dbg_log_num ((unsigned)old_current)
|
||||
dbg_log ("; target=")
|
||||
dbg_log_num (target)
|
||||
dbg_log (prefix)
|
||||
dbg_log (": caller=")
|
||||
dbg_log_num ((unsigned)old_current)
|
||||
dbg_log ("; target=")
|
||||
dbg_log_num (target)
|
||||
dbg_log ("; pdata=")
|
||||
dbg_log_num (pdata)
|
||||
dbg_log ("; data=")
|
||||
dbg_log_num (c->data[0].h)
|
||||
dbg_log (":")
|
||||
dbg_log_num (c->data[0].l)
|
||||
dbg_log (",")
|
||||
dbg_log_num (c->data[1].h)
|
||||
dbg_log (":")
|
||||
dbg_log_num (c->data[1].l)
|
||||
if c->reply.valid ():
|
||||
dbg_log ("; reply target=")
|
||||
dbg_log_num ((unsigned)c->reply->target)
|
||||
dbg_log ("; pdata=")
|
||||
dbg_log_num (pdata)
|
||||
dbg_log ("; data=")
|
||||
dbg_log_num (c->data[0].h)
|
||||
dbg_log (":")
|
||||
dbg_log_num (c->data[0].l)
|
||||
dbg_log (",")
|
||||
dbg_log_num (c->data[1].h)
|
||||
dbg_log (":")
|
||||
dbg_log_num (c->data[1].l)
|
||||
if c->reply.valid ():
|
||||
dbg_log ("; reply target=")
|
||||
dbg_log_num ((unsigned)c->reply->target)
|
||||
dbg_log ("; pdata=")
|
||||
dbg_log_num (c->reply->protected_data.l)
|
||||
if c->arg.valid ():
|
||||
dbg_log ("; arg target=")
|
||||
dbg_log_num ((unsigned)c->arg->target)
|
||||
dbg_log ("; pdata=")
|
||||
dbg_log_num (c->arg->protected_data.l)
|
||||
dbg_log ("\n")
|
||||
dbg_log_num (c->reply->protected_data.l)
|
||||
if c->arg.valid ():
|
||||
dbg_log ("; arg target=")
|
||||
dbg_log_num ((unsigned)c->arg->target)
|
||||
dbg_log ("; pdata=")
|
||||
dbg_log_num (c->arg->protected_data.l)
|
||||
dbg_log ("\n")
|
||||
|
||||
void kThread::raise (unsigned code, unsigned data):
|
||||
dpanic (code, "raise")
|
||||
@ -104,8 +103,8 @@ bool kReceiver::try_deliver ():
|
||||
if m->protected_data.value () == reply_protected_data.value ():
|
||||
protected_only = false
|
||||
break
|
||||
if !m:
|
||||
return false
|
||||
if !m:
|
||||
return false
|
||||
bool dummy
|
||||
kCapRef c = owner->find_capability (owner->recv_reply, &dummy)
|
||||
if c.valid ():
|
||||
@ -121,7 +120,7 @@ bool kReceiver::try_deliver ():
|
||||
// Send a message to a receiver; try to deliver it immediately.
|
||||
bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *c):
|
||||
//log_message ("send_message", (unsigned)this, protected_data.l, c)
|
||||
if owner && owner->is_waiting () && (protected_data.value () == reply_protected_data.value () || !protected_only):
|
||||
if owner && owner->is_waiting () && (!protected_only || protected_data.value () == reply_protected_data.value ()):
|
||||
if protected_only:
|
||||
protected_only = false
|
||||
bool dummy
|
||||
@ -145,16 +144,6 @@ bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *
|
||||
if !msg:
|
||||
return false
|
||||
msg->protected_data = protected_data
|
||||
if protected_only && protected_data.value () == reply_protected_data.value ():
|
||||
// Put this message in the end (where it will be first seen). Clear the protected_only flag.
|
||||
protected_only = false
|
||||
if msg->next:
|
||||
((kMessage *)msg->next)->prev = NULL
|
||||
messages = (kMessage *)msg->next
|
||||
msg->next = NULL
|
||||
msg->prev = last_message
|
||||
((kMessage *)msg->prev)->next = msg
|
||||
last_message = msg
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
msg->data[i] = c->data[i]
|
||||
msg->caps.clone (0, c->reply, c->copy[0])
|
||||
@ -194,9 +183,9 @@ static void reply_cap (unsigned target, Kernel::Num protected_data, kCapRef *ref
|
||||
c.data[0] = Kernel::Num (num, 0)
|
||||
if reply_target:
|
||||
reply_target->send_message (reply_protected, &c)
|
||||
c.arg->invalidate ()
|
||||
else:
|
||||
dpanic (0, "nothing to reply to")
|
||||
c.arg->invalidate ()
|
||||
|
||||
static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
kReceiver *receiver = (kReceiver *)protected_data.l
|
||||
@ -713,6 +702,8 @@ static void print_cap (kCapRef cap, kCapRef self):
|
||||
dbg_log_char ('!')
|
||||
else:
|
||||
dbg_log_char ('=')
|
||||
dbg_log_num ((unsigned)cap->target)
|
||||
dbg_log_char (':')
|
||||
dbg_log_num (cap->protected_data.l)
|
||||
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
|
||||
print_cap (c, self)
|
||||
@ -746,12 +737,9 @@ static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
|
||||
return
|
||||
case Kernel::Caps::PRINT & REQUEST_MASK:
|
||||
if c->data[1].l >= caps->size:
|
||||
if c->data[1].l == ~0:
|
||||
// debug: power down.
|
||||
*((volatile unsigned *)0xa0003020) = 1
|
||||
return
|
||||
dpanic (0, "invalid caps for print")
|
||||
return
|
||||
dbg_code.h = (unsigned)caps->cap (c->data[1].l)
|
||||
kCapRef cap (caps, c->data[1].l)
|
||||
kCapRef orig (caps, c->data[1].l)
|
||||
while cap->parent.valid ():
|
||||
@ -796,11 +784,12 @@ static void kill_reply (kReceiver *r):
|
||||
static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapability::Context *c):
|
||||
// Kernel calling convention:
|
||||
// data[0].l is the request.
|
||||
// caps[0] is the reply capability
|
||||
// reply is the reply capability, or (for call capabilities) the target to call.
|
||||
// other parameters' meanings depend on the operation.
|
||||
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL_ASYNC):
|
||||
// This is a call capability. reply is the capability to call. It should be replaced by the reply capability.
|
||||
((kReceiver *)protected_data.l)->protected_only = target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL)
|
||||
// This is a call capability. reply is the capability to call.
|
||||
kReceiver *owner = (kReceiver *)protected_data.l
|
||||
owner->protected_only = target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL)
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
if !reply_target:
|
||||
@ -825,6 +814,7 @@ static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapabil
|
||||
c->reply.reset ()
|
||||
reply_target = (kReceiver *)protected_data.l
|
||||
reply_protected = reply_target->reply_protected_data
|
||||
kReceiver *r = reply_target
|
||||
kernel_invoke ((unsigned)call_target->target, call_target->protected_data, c)
|
||||
return
|
||||
if must_wait:
|
||||
|
4
iris.hhp
4
iris.hhp
@ -65,6 +65,8 @@
|
||||
// This constant signifies that no capability is passed.
|
||||
#define CAP_NONE (~CAP_COPY)
|
||||
|
||||
struct Parent
|
||||
|
||||
namespace Kernel:
|
||||
enum Exception_code:
|
||||
NO_ERROR
|
||||
@ -161,7 +163,7 @@ namespace Kernel:
|
||||
extern Thread my_thread
|
||||
extern Memory my_memory
|
||||
extern Cap my_call
|
||||
extern Cap my_parent
|
||||
extern Parent my_parent
|
||||
extern __recv_data_t recv
|
||||
|
||||
inline Cap get_reply ():
|
||||
|
10
kernel.hhp
10
kernel.hhp
@ -137,11 +137,12 @@ struct kReceiver : public kObject:
|
||||
Kernel::Num reply_protected_data
|
||||
bool protected_only
|
||||
// This limit is for messages stored in its address space. There is unlimited space if senders provide it.
|
||||
unsigned queue_limit
|
||||
unsigned queue_limit, queue_use
|
||||
void own (kThreadP o)
|
||||
void orphan ()
|
||||
bool try_deliver ()
|
||||
bool send_message (Kernel::Num protected_data, kCapability::Context *c)
|
||||
void check (unsigned line)
|
||||
|
||||
struct kPage : public kObject:
|
||||
unsigned frame
|
||||
@ -205,6 +206,8 @@ struct kMemory : public kObject:
|
||||
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":
|
||||
@ -219,7 +222,12 @@ extern "C":
|
||||
void dbg_log_num (unsigned num, unsigned digits = 8)
|
||||
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_log_char(x) do {} while (0)
|
||||
#define dbg_log(x) do {} while (0)
|
||||
|
147
keys.hhp
Normal file
147
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
|
23
memory.ccp
23
memory.ccp
@ -34,6 +34,7 @@ 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)
|
||||
void print_free ():
|
||||
#endif
|
||||
#else
|
||||
|
||||
@ -129,11 +130,20 @@ void phys_free (unsigned page, unsigned num):
|
||||
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)
|
||||
bool check_free (kObject *o, unsigned size):
|
||||
for kFreePages *p = first_free; p; p = p->next:
|
||||
if (unsigned)o + size > (unsigned)p && (unsigned)o < (unsigned)p + p->num * PAGE_SIZE:
|
||||
return false
|
||||
return true
|
||||
|
||||
void print_free ():
|
||||
dbg_log ("Free pages: ")
|
||||
for kFreePages *p = first_free; p; p = p->next:
|
||||
dbg_log_num ((unsigned)p)
|
||||
dbg_log (":")
|
||||
dbg_log_num (p->num, 4)
|
||||
dbg_log ("->")
|
||||
dbg_log ("NULL\n")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -142,6 +152,8 @@ 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)
|
||||
for kReceiver *r = mem->receivers; r; r = (kReceiver *)r->next:
|
||||
check_impl (r->messages, num, msg)
|
||||
check_impl (mem->capses, num, msg)
|
||||
check_impl (mem->memories, num, msg)
|
||||
for kMemory *m = mem->memories; m; m = (kMemory *)m->next:
|
||||
@ -149,6 +161,7 @@ void check_memory (kMemory *mem, unsigned num, char const *msg):
|
||||
|
||||
void check (unsigned num, char const *msg):
|
||||
check_memory (&top_memory, num, msg)
|
||||
top_memory.check (num)
|
||||
#endif
|
||||
|
||||
unsigned raw_zalloc ():
|
||||
|
@ -131,20 +131,18 @@ void flush_tlb (unsigned asid):
|
||||
__asm__ volatile ("tlbwi")
|
||||
|
||||
static void arch_invoke ():
|
||||
kCapRef target
|
||||
target = old_current->find_capability (old_current->arch.v[0], &must_wait)
|
||||
kCapRef target = old_current->find_capability (old_current->arch.v[0], &must_wait)
|
||||
do_schedule = false
|
||||
kCapability::Context msg
|
||||
msg.reply = old_current->find_capability (old_current->arch.t[0], &msg.copy[0])
|
||||
msg.arg = old_current->find_capability (old_current->arch.t[1], &msg.copy[1])
|
||||
if must_wait:
|
||||
bool dummy
|
||||
old_current->recv_reply = old_current->arch.t[2]
|
||||
old_current->recv_arg = old_current->arch.t[3]
|
||||
if !target.valid ():
|
||||
if must_wait:
|
||||
old_current->wait ()
|
||||
return
|
||||
msg.reply = old_current->find_capability (old_current->arch.t[0], &msg.copy[0])
|
||||
msg.arg = old_current->find_capability (old_current->arch.t[1], &msg.copy[1])
|
||||
msg.data[0] = Kernel::Num (old_current->arch.a[0], old_current->arch.a[1])
|
||||
msg.data[1] = Kernel::Num (old_current->arch.a[2], old_current->arch.a[3])
|
||||
target->invoke (&msg)
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
load = 0x80000000
|
||||
|
||||
ARCH_CXXFLAGS = -DNUM_THREADS=4
|
||||
ARCH_CXXFLAGS = -DNUM_THREADS=5
|
||||
ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
|
||||
CROSS = mipsel-linux-gnu-
|
||||
OBJDUMP = $(CROSS)objdump
|
||||
@ -28,7 +28,7 @@ LDFLAGS = --omagic -Ttext $(load)
|
||||
arch_iris_sources = mips/interrupts.cc mips/arch.cc
|
||||
boot_sources = mips/init.cc mips/nanonote/board.cc
|
||||
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh
|
||||
boot_threads = init udc nanonote-gpio buzzer
|
||||
boot_threads = init udc nanonote-gpio buzzer metronome
|
||||
|
||||
test: iris.raw nanonote-boot
|
||||
./nanonote-boot iris.raw 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8')
|
||||
@ -50,7 +50,7 @@ mips/entry.o: $(boot_threads)
|
||||
mips/init.o: TARGET_FLAGS = -I/usr/include
|
||||
$(boot_threads): TARGET_FLAGS = -I.
|
||||
$(boot_threads): LDFLAGS = -EL
|
||||
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): boot-programs/devices.hh
|
||||
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh
|
||||
lcd: boot-programs/charset.data
|
||||
|
||||
boot-programs/charset.data: boot-programs/charset
|
||||
@ -63,4 +63,4 @@ boot-programs/charset.data: boot-programs/charset
|
||||
iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) mips/nanonote/threadlist.o mips/boot.o $(subst .cc,.o,$(boot_sources))
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
ARCH_CLEAN_FILES = $(boot_sources) $(boot_threads) $(arch_headers) boot_programs/devices.hh mips/*.o mips/nanonote/*.o boot-programs/charset.data iris.elf iris.raw mips/nanonote/sdram-setup.elf mips/nanonote/sdram-setup.raw
|
||||
ARCH_CLEAN_FILES = $(boot_sources) $(boot_threads) $(arch_headers) devices.hh keys.hh mips/*.o mips/nanonote/*.o boot-programs/charset.data iris.elf iris.raw mips/nanonote/sdram-setup.elf mips/nanonote/sdram-setup.raw
|
||||
|
@ -54,4 +54,5 @@ void board_init ():
|
||||
UART0_DLLR = uart_div
|
||||
UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1
|
||||
UART0_FCR = UARTFCR_UUE | UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS
|
||||
dbg_code.l = 1
|
||||
dbg_log ("Serial port initialized\n")
|
||||
|
@ -35,7 +35,11 @@ thread2:
|
||||
thread3:
|
||||
.incbin "buzzer"
|
||||
|
||||
.balign 0x1000
|
||||
thread4:
|
||||
.incbin "metronome"
|
||||
|
||||
thread5:
|
||||
|
||||
// Everything from here may be freed after kernel initialization.
|
||||
init_start:
|
||||
@ -46,3 +50,4 @@ thread_start:
|
||||
.word thread2
|
||||
.word thread3
|
||||
.word thread4
|
||||
.word thread5
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#ifdef USE_SERIAL
|
||||
void dbg_log_char (unsigned ch):
|
||||
if dbg_code.l == 0:
|
||||
return
|
||||
while !(UART0_LSR & UARTLSR_TDRQ):
|
||||
UART0_TDR = ch
|
||||
#else
|
||||
|
@ -90,6 +90,6 @@ void schedule ():
|
||||
void timer_interrupt ():
|
||||
kReceiver *recv, *next
|
||||
for recv = first_alarm; recv; recv = next:
|
||||
next = (kReceiver *)recv->next
|
||||
next = (kReceiver *)recv->next_alarm
|
||||
alarm_tick (recv)
|
||||
//schedule ()
|
||||
|
Loading…
Reference in New Issue
Block a user