diff --git a/bootstrap/init.ccp b/bootstrap/init.ccp new file mode 100644 index 0000000..3f050c2 --- /dev/null +++ b/bootstrap/init.ccp @@ -0,0 +1,136 @@ +#pypp 0 +// Iris: micro-kernel for a capability-based operating system. +// bootstrap/init.ccp: Bootstrapping code. +// Copyright 2009 Bas Wijnen +// +// 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 . + +#include "devices.hh" +#include "iris.hh" + +struct file: + unsigned size + // Only the first 16 characters of the name are used, because that's much easier. + // This means that file names must be different in the first 16 characters if sort order matters. + char name[16] + String string + +static unsigned num_files +static file *files +static unsigned index +static Kernel::Memory top_memory +static unsigned max_pages +static char *mapping + +// Get the initial block device and filesystem. +static Directory receive_devices (): + String dev + Filesystem fs + for unsigned i = 0; i < 2; ++i: + Kernel::wait () + if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE: + kdebug ("Invalid bootstrap request.\n") + Kernel::panic (0) + switch Kernel::recv.data[1].l: + case String::ID: + if dev: + kdebug ("duplicate device.\n") + Kernel::panic (0) + dev = Kernel::get_arg () + Kernel::recv.reply.invoke () + break + case Filesystem::ID: + if fs: + kdebug ("duplicate filesystem.\n") + Kernel::panic (0) + fs = Kernel::get_arg () + Kernel::recv.reply.invoke () + break + default: + kdebug ("unexpected device: ") + kdebug_num (Kernel::recv.data[1].l) + kdebug_char ('\n') + Kernel::panic (0) + // Initialize the root file system. + Directory root = fs.use_device (dev.copy ()) + Kernel::free_cap (dev) + Kernel::free_cap (fs) + return root + +// Make a list of all files. +static void list_files (Directory root): + Kernel::Num fullsize = root.get_size () + if fullsize.h != 0: + kdebug ("Too many files in bootstrap directory.\n") + Kernel::panic (0) + num_files = fullsize.l + files = new file[num_files] + Kernel::Caps caps = Kernel::my_memory.create_caps (num_files * 2) + unsigned slot = Kernel::alloc_slot () + caps.use (slot) + for unsigned i = 0; i < num_files; ++i: + Kernel::set_recv_arg (Kernel::Cap (slot, i * 2)) + String n = root.get_name (i) + n.get_chars (0, files[i].name) + Kernel::set_recv_arg (Kernel::Cap (slot, i * 2 + 1)) + files[i].string = root.get_file_ro (i) + Kernel::Num fullsize = files[i].string.get_size () + if fullsize.h != 0: + kdebug ("initial file size too large.\n") + Kernel::panic (0) + files[i].size = fullsize.l + if max_pages < (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK: + max_pages = (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK + +// Sort the list of files. +static bool is_less (file *f1, file *f2): + return + +// Bubble sort. +static void sort (): + index = new unsigned[num_files] + index[0] = 0 + // Invariant: index[0...f-1] is sorted. + for unsigned f = 1; f < num_files; ++f: + // Bubble up until top. Test for less-than, because it wraps to maxunsigned. + unsigned i + // Invariant: index[0...f] \ index[i+1] is sorted and index[i+1...f] is sorted. + for i = f - 1; i < f; --i: + if is_less (&files[index[i]], &files[f]): + break + index[i + 1] = index[i] + index[i + 1] = f + +static void run (file *f): + Kernel::Memory mem = top_memory.create_memory () + unsigned num_pages = (f->size + PAGE_SIZE - 1) & PAGE_MASK + for unsigned p = 0; p < num_pages; ++p: + pages[p] = f->string.get_page (p << PAGE_BITS, mem.create_page ()) + Kernel::my_memory.map (pages[p], (unsigned)&mapping[p << PAGE_BITS]) + // TODO: parse elf file. + +Kernel::Num start (): + top_memory = Kernel::get_top_memory () + // Wait for the debugging device to be active, in case there is one. + Kernel::schedule () + Directory root = receive_devices () + root.lock_ro () + list_files (root) + sort () + pages = new Kernel::Page[max_pages] + mapping = alloc_space (max_pages) + for unsigned i = 0; i < num_files; ++i: + run (files[i]) + root.unlock_ro () + return 0 diff --git a/devices.hhp b/devices.hhp index dc6e53c..73950e3 100644 --- a/devices.hhp +++ b/devices.hhp @@ -226,7 +226,7 @@ struct Directory : public Kernel::Cap: // Get the number of entries in this directory. Kernel::Num get_size (): return call (CAP_MASTER_DIRECT | GET_SIZE) - // Get the filename. The return value is the size of the string, the page is filled with the string itself. + // Get the filename. String get_name (Kernel::Num idx): icall (CAP_MASTER_DIRECT | GET_NAME, idx) return Kernel::get_arg () diff --git a/iris.hhp b/iris.hhp index d13dd83..2e578c3 100644 --- a/iris.hhp +++ b/iris.hhp @@ -42,8 +42,8 @@ #define CAPTYPE_THREAD 0x600 #define CAPTYPE_PAGE 0x800 #define CAPTYPE_CAPS 0xa00 -//#define CAPTYPE_??? 0xc00 -//#define CAPTYPE_??? 0xe00 +#define CAPTYPE_LIST 0xc00 +#define CAPTYPE_LISTITEM 0xe00 // All kernel capabilities have a master capability, which can create others. #define CAP_MASTER 0 @@ -130,6 +130,7 @@ namespace Kernel: struct Thread struct Page struct Memory + struct List void print_caps () unsigned alloc_slot () @@ -428,6 +429,46 @@ namespace Kernel: void alloc_physical (unsigned 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: + REMOVE = CAPTYPE_LISTITEM + 1 + CLEAR + SET_CAP + ADD + void remove (): + call (CAP_MASTER_DIRECT | REMOVE) + void clear (): + call (CAP_MASTER_DIRECT | CLEAR) + void set_cap (Cap c): + call (CAP_MASTER_DIRECT | SET_CAP, c.code) + // ADD is called by the kernel on non-listitem objects which are added to a list, to allow virtualization. + // Also, to add a listitem to a list, the listitem capability must be of type ADD or MASTER. + + struct List : public Cap: + List (Cap c = Cap ()) : Cap (c): + enum request: + GET_NEXT = CAPTYPE_LIST + 1 + SET_EMPTY_CB + ADD_ITEM + GET_INFO + SET_INFO + GET_CAP + Listitem get_next (Listitem current = Listitem ()): + icall (current, CAP_MASTER_DIRECT | GET_NEXT) + return get_arg () + void set_empty_cb (Cap cb): + ocall (cb, CAP_MASTER_DIRECT | SET_EMPTY_CB) + void add_item (Listitem item): + ocall (item, CAP_MASTER_DIRECT | ADD_ITEM) + Num get_info (Listitem item): + return ocall (item, CAP_MASTER_DIRECT | GET_INFO) + void set_info (Listitem item, Num info): + ocall (item, CAP_MASTER_DIRECT | SET_INFO, info) + 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): @@ -454,6 +495,12 @@ namespace Kernel: 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 @@ -464,7 +511,7 @@ namespace Kernel: Page mapping (void *address): icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address)) return get_arg () - unsigned get_limit (unsigned limit): + unsigned get_limit (): return call (CAP_MASTER_DIRECT | GET_LIMIT).l void set_limit (unsigned limit): call (CAP_MASTER_DIRECT | SET_LIMIT, limit) diff --git a/kernel.hhp b/kernel.hhp index e375628..da51729 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -36,6 +36,8 @@ struct kReceiver struct kCapability struct kCaps struct kMemory +struct kList +struct kListitem // Some functions which must be defined early. extern "C": @@ -58,6 +60,8 @@ typedef kReceiver *kReceiverP typedef kCapability *kCapabilityP typedef kCaps *kCapsP typedef kMemory *kMemoryP +typedef kList *kListP +typedef kListitem *kListitemP typedef void *kPointer struct kCapRef: @@ -183,12 +187,25 @@ struct kMessage : public kObject: // This is a real Caps of two elements, not a link. kCaps caps +struct kListitem : public kObject: + kListitemP prev_item, next_item + kThreadP owner + unsigned cap + Kernel::Num info + +struct kList : public kObject: + kListitemP first_item + kThreadP owner + unsigned cb + 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