diff --git a/alloc.ccp b/alloc.ccp index b171349..0694486 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -176,6 +176,7 @@ kPage *kMemory::alloc_page (): return NULL ret->frame = 0 ret->flags = 0 + ret->mapping = ~0 return ret kThread *kMemory::alloc_thread (unsigned size): @@ -303,6 +304,8 @@ void kCaps::clone (unsigned index, kCapRef source, bool copy): set (index, source->target, source->protected_data, source) void kMemory::free_page (kPage *page): + if page->mapping != ~0: + page->address_space->unmap (page) if page->flags & Kernel::Page::PAYING: unuse () if page->frame: @@ -458,7 +461,6 @@ void kMemory::free_memory (kMemory *mem): free_list (mem->lists) while mem->listitems: free_listitem (mem->listitems) - kMemory_arch_free (mem) if mem->frees: panic (0, "kernel memory leak: memory still in use") free_obj (mem, (void **)&memories) diff --git a/boot-programs/init.ccp b/boot-programs/init.ccp index 35b5bf9..5ec237c 100644 --- a/boot-programs/init.ccp +++ b/boot-programs/init.ccp @@ -27,24 +27,24 @@ static unsigned _free extern unsigned _end void init_alloc (): - _free = (unsigned)&_end + _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK char *alloc_space (unsigned pages): unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK - _free = ret + pages * PAGE_SIZE + _free = ret + (pages << PAGE_BITS) return (char *)ret void *operator new[] (unsigned size): + //kdebug ("new ") void *ret = (void *)_free size = (size + 3) & ~3 unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1) if rest < size: unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS - char *space = alloc_space (pages) for unsigned p = 0; p < pages; ++p: Kernel::Page page = Kernel::my_memory.create_page () page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME) - Kernel::my_memory.map (page, (unsigned)&space[p << PAGE_BITS]) + Kernel::my_memory.map (page, _free + rest + (p << PAGE_BITS)) Kernel::free_cap (page) _free += size //kdebug_num ((unsigned)ret) @@ -125,9 +125,6 @@ static void list_files (Directory root): kdebug ("\n") Kernel::panic (0) num_files = fullsize.l - kdebug ("files in directory: ") - kdebug_num (num_files) - kdebug ("\n") files = new file[num_files] Kernel::Caps caps = Kernel::my_memory.create_caps (num_files) unsigned slot = Kernel::alloc_slot () @@ -184,15 +181,14 @@ static void run (file *f, bool priv): Kernel::Memory mem = top_memory.create_memory () unsigned num_pages = (f->size + PAGE_SIZE - 1) >> PAGE_BITS for unsigned p = 0; p < num_pages; ++p: - kdebug_num (p) - kdebug ("/") - kdebug_num (num_pages) - kdebug ("\n") + //kdebug_num (p) + //kdebug ("/") + //kdebug_num (num_pages) + //kdebug ("\n") Kernel::set_recv_arg (Kernel::Cap (slot, p)) Kernel::my_memory.create_page () Kernel::Page (slot, p).set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING) f->string.get_page (p << PAGE_BITS, Kernel::Cap (slot, p)) - kdebug_line () Kernel::my_memory.map (Kernel::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS]) Kernel::Thread thread = mem.create_thread (NUM_SLOTS) if priv: @@ -229,24 +225,18 @@ static void run (file *f, bool priv): return thread.set_pc (header->e_entry) thread.set_sp (0x80000000) - kdebug_line () for unsigned section = 0; section < header->e_shnum; ++section: - kdebug_line () Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize) if ~shdr->sh_flags & SHF_ALLOC: continue - kdebug_line () bool readonly = !(shdr->sh_flags & SHF_WRITE) //bool executable = shdr->sh_flags & SHF_EXEC_INSTR - kdebug_line () if shdr->sh_type != SHT_NOBITS: - kdebug_line () unsigned file_offset = shdr->sh_offset >> PAGE_BITS if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2): kdebug ("thread too large\n") Kernel::panic (0) return - kdebug_line () for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE: unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS unsigned idx = file_offset + section_offset @@ -257,24 +247,28 @@ static void run (file *f, bool priv): continue Kernel::free_cap (page) page = mem.create_page () - page.set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING) + unsigned f + if readonly: + f = Kernel::Page::PAYING | Kernel::Page::MAPPED_READONLY + else: + f = Kernel::Page::PAYING + page.set_flags (f, f) Kernel::Page (slot, idx).share (page, 0) - kdebug ("mapping at ") - kdebug_num (p) - kdebug ("\n") - if !mem.map (page, p, readonly): + //kdebug ("mapping at ") + //kdebug_num (p) + //if readonly: + // kdebug (" (readonly)") + //kdebug ("\n") + if !mem.map (page, p): kdebug ("unable to map page\n") Kernel::panic (0) return Kernel::free_cap (page) - kdebug_line () else: - kdebug_line () if readonly: kdebug ("unwritable bss section\n") Kernel::panic (0) return - kdebug_line () for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE: Kernel::Page page = mem.mapping ((void *)p) if Kernel::recv.data[0].l == Kernel::NO_ERROR: @@ -302,103 +296,53 @@ static void run (file *f, bool priv): Kernel::panic (0) return Kernel::free_cap (page) - kdebug_line () - kdebug_line () - for unsigned p = 0; p <= num_pages; ++p: + for unsigned p = 0; p < num_pages; ++p: Kernel::my_memory.destroy (Kernel::Page (slot, p)) - kdebug_line () Kernel::Page stackpage = mem.create_page () - kdebug_line () stackpage.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME) - kdebug_line () if Kernel::recv.data[0].l != Kernel::NO_ERROR || !mem.map (stackpage, 0x7ffff000): kdebug ("unable to map initial stack page\n") Kernel::panic (0) return - kdebug_line () Kernel::free_cap (stackpage) Kernel::Caps caps = mem.create_caps (NUM_CAPS) - kdebug_line () thread.use (caps, 0) thread.set_info (Kernel::Thread::A0, NUM_SLOTS) thread.set_info (Kernel::Thread::A1, NUM_CAPS) - kdebug_line () Kernel::Receiver receiver = mem.create_receiver () receiver.set_owner (thread.copy ()) Kernel::Cap call = receiver.create_call_capability () Kernel::Cap parent = Kernel::my_receiver.create_capability (++current_thread) - kdebug_line () caps.set (__receiver_num, receiver.copy ()) caps.set (__thread_num, thread.copy ()) caps.set (__memory_num, mem.copy ()) caps.set (__call_num, call.copy ()) caps.set (__parent_num, parent.copy ()) - kdebug_line () thread.run () - kdebug_line () Kernel::free_cap (receiver) Kernel::free_cap (thread) Kernel::free_cap (mem) Kernel::free_cap (call) Kernel::free_cap (parent) - kdebug_line () - Kernel::print_caps () - -static void dump_devices (): - kdebug ("String: ") - kdebug_num (String::ID, 3) - kdebug ("\nWString: ") - kdebug_num (WString::ID, 3) - kdebug ("\nDevice: ") - kdebug_num (Device::ID, 3) - kdebug ("\nParent: ") - kdebug_num (Parent::ID, 3) - kdebug ("\nKeyboard: ") - kdebug_num (Keyboard::ID, 3) - kdebug ("\nBuzzer: ") - kdebug_num (Buzzer::ID, 3) - kdebug ("\nDisplay: ") - kdebug_num (Display::ID, 3) - kdebug ("\nSetting: ") - kdebug_num (Setting::ID, 3) - kdebug ("\nDirectory: ") - kdebug_num (Directory::ID, 3) - kdebug ("\nWDirectory: ") - kdebug_num (WDirectory::ID, 3) - kdebug ("\nFilesystem: ") - kdebug_num (Filesystem::ID, 3) - kdebug ("\nStream: ") - kdebug_num (Stream::ID, 3) - kdebug ("\n") + Kernel::free_cap (caps) Kernel::Num start (): // Wait for the debugging device to be active, in case there is one. Kernel::schedule () init_alloc () - dump_devices () top_memory = Kernel::get_top_memory () Directory root = receive_devices () root.lock_ro () - kdebug_line () list_files (root) - kdebug_line () sort () - kdebug_line () Kernel::Caps caps = Kernel::my_memory.create_caps (max_pages) - kdebug ("max pages: ") - kdebug_num (max_pages) - kdebug ("\n") slot = caps.use () mapping = alloc_space (max_pages) for unsigned i = 0; i < num_files; ++i: - kdebug_line () run (&files[index[i]], files[index[i]].name[0] == '#') - kdebug_line () - kdebug_line () root.unlock_ro () - kdebug_line () Kernel::free_slot (slot) - kdebug_line () Kernel::my_memory.destroy (caps) - kdebug_line () - return 0 + while true: + Kernel::wait () + kdebug ("request!\n") diff --git a/invoke.ccp b/invoke.ccp index f612118..a135784 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -299,7 +299,6 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_ kPage *ret = mem->alloc_page () if ret: reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs) - dbg_log ("page created\n") else: dpanic (0x33311992, "out of memory creating page") reply_num (Kernel::ERR_OUT_OF_MEMORY) @@ -355,17 +354,18 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_ dpanic (0x52993341, "Trying to map foreign page") reply_num (Kernel::ERR_INVALID_ARGUMENT) return - bool readonly = c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY - mem->map (page, c->data[1].l & PAGE_MASK, readonly) + if c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY: + dbg_log ("Mapping readonly because capability is readonly\n") + page->flags |= Kernel::Page::MAPPED_READONLY + mem->map (page, c->data[1].l & PAGE_MASK) break case Kernel::Memory::MAPPING & REQUEST_MASK: - bool readonly - kPage *page = mem->get_mapping (c->data[1].l, &readonly) + kPage *page = mem->get_mapping (c->data[1].l) if !page: reply_num (Kernel::ERR_UNMAPPED_READ) return unsigned t = CAPTYPE_PAGE | CAP_MASTER - if readonly: + if page->flags & Kernel::Page::MAPPED_READONLY: t |= Kernel::Page::READONLY reply_cap (t, (unsigned)page, &page->refs) return @@ -554,14 +554,14 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_ reply_num (0) return -static bool page_check_payment (kPage *page): +static void page_check_payment (kPage *page): kPage *p for p = page->share_prev; p; p = p->share_prev: if p->flags & Kernel::Page::PAYING: - return true + return for p = page->share_next; p; p = p->share_next: if p->flags & Kernel::Page::PAYING: - return true + return // No kPage is paying for this frame anymore. raw_pfree (page->frame) kPage *next @@ -577,7 +577,6 @@ static bool page_check_payment (kPage *page): p->share_next = NULL p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME) kPage_arch_update_mapping (p) - return false static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c): kPage *page = (kPage *)protected_data.l @@ -599,9 +598,11 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da t->flags |= Kernel::Page::READONLY if !(page->flags & Kernel::Page::FRAME): dpanic (0, "sharing nothing results in lost page") + kPage_arch_update_mapping (t) break if c->data[0].h & Kernel::Page::COPY: if ~t->flags & Kernel::Page::PAYING: + kPage_arch_update_mapping (t) break if !(c->data[0].h & Kernel::Page::FORGET) || page->flags & Kernel::Page::SHARED: unsigned *d = (unsigned *)page->frame @@ -629,10 +630,10 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da page->frame = NULL page->flags &= ~Kernel::Page::FRAME kPage_arch_update_mapping (page) - kPage_arch_update_mapping (t) else: if t == page: dpanic (0, "sharing page with itself") + kPage_arch_update_mapping (t) break if c->data[0].h & Kernel::Page::FORGET: if ~page->flags & Kernel::Page::SHARED: @@ -661,7 +662,7 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da t->share_prev->share_next = t t->frame = page->frame t->flags |= Kernel::Page::FRAME - kPage_arch_update_mapping (t) + kPage_arch_update_mapping (t) break case Kernel::Page::SET_FLAGS & REQUEST_MASK: if cmd & Kernel::Page::READONLY: @@ -679,8 +680,7 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da if ~page->flags & old & Kernel::Page::PAYING: // Decrease the use counter in any case. page->address_space->unuse () - if !page_check_payment (page): - page->flags &= ~Kernel::Page::FRAME + page_check_payment (page) // If we start paying, increase the use counter. if page->flags & ~old & Kernel::Page::PAYING: @@ -694,19 +694,10 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da // If we want a frame, see if we can get it. if ~old & page->flags & Kernel::Page::FRAME: - kPage *p - for p = page; p; p = p->share_prev: - if p->flags & Kernel::Page::PAYING: - break - if !p: - for p = page->share_next; p; p = p->share_next: - if p->flags & Kernel::Page::PAYING: - break - if !p: - dpanic (0, "cannot have frame without payer") - page->flags &= ~Kernel::Page::FRAME - // If we can get the new frame, get it. - if ~old & page->flags & Kernel::Page::FRAME: + if ~page->flags & Kernel::Page::PAYING: + dpanic (0, "cannot have frame without paying") + page->flags &= ~Kernel::Page::FRAME + else: page->frame = page->address_space->zalloc () kPage_arch_update_mapping (page) break diff --git a/iris.hhp b/iris.hhp index 4a7f12e..af6836a 100644 --- a/iris.hhp +++ b/iris.hhp @@ -447,10 +447,12 @@ namespace Kernel: 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 = 0x10 + PHYSICAL = 0x20 // This is a read-only flag, saying if this is uncachable memory. - UNCACHED = 0x20 + UNCACHED = 0x40 void share (Cap target, unsigned flags): ocall (target, Kernel::Num (CAP_MASTER_DIRECT | SHARE, flags)) unsigned get_flags (): @@ -538,9 +540,7 @@ namespace Kernel: void destroy (Cap target): ocall (target, CAP_MASTER_DIRECT | DESTROY) // TODO: LIST - bool map (Cap page, unsigned address, bool readonly = false): - if readonly: - address |= Page::READONLY + bool map (Cap page, unsigned address): return ocall (page, CAP_MASTER_DIRECT | MAP, address).l != ~0 Page mapping (void *address): icall (CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address)) diff --git a/kernel.hhp b/kernel.hhp index 034f0d0..d57364f 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -115,6 +115,8 @@ 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 @@ -167,6 +169,7 @@ struct kReceiver : public kObject: struct kPage : public kObject: unsigned frame unsigned flags + unsigned mapping kPageP share_first kPageP share_prev, share_next kPage_arch arch @@ -213,9 +216,9 @@ struct kMemory : public kObject: unsigned limit, used kMemory_arch arch - inline bool map (kPage *page, unsigned address, bool readonly) - inline void unmap (kPage *page, unsigned address) - inline kPage *get_mapping (unsigned address, bool *readonly) + 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) @@ -300,20 +303,20 @@ void kThread_arch_receive (kThread *thread, Kernel::Num protected_data, Kernel:: 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, bool write) -void kMemory_arch_unmap (kMemory *mem, kPage *page, unsigned address) -kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly) +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_update_mapping (kPage *page) void arch_register_interrupt (unsigned num, kReceiverP r) void arch_reboot () void arch_uncache_page (unsigned page) -bool kMemory::map (kPage *page, unsigned address, bool readonly = false): - return kMemory_arch_map (this, page, address, readonly) -void kMemory::unmap (kPage *page, unsigned address): - kMemory_arch_unmap (this, page, address) -kPage *kMemory::get_mapping (unsigned address, bool *readonly): - return kMemory_arch_get_mapping (this, address, readonly) +bool kMemory::map (kPage *page, unsigned address): + return kMemory_arch_map (this, page, address) +void kMemory::unmap (kPage *page): + 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): diff --git a/mips/arch.ccp b/mips/arch.ccp index 5554172..afbf642 100644 --- a/mips/arch.ccp +++ b/mips/arch.ccp @@ -114,83 +114,31 @@ void kMemory_arch_init (kMemory *mem): mem->arch.directory = NULL mem->arch.shadow = NULL -void kMemory_arch_free (kMemory *mem): - //dbg_log_line () - while mem->arch.first_page_table: - mem->unmap (mem->arch.first_page_table->first_page->page, mem->arch.first_page_table->first_page->mapping) - if (kMemory *)asids[mem->arch.asid] == mem: - flush_tlb (mem->arch.asid) - asids[mem->arch.asid] = asids[0] - asids[0] = mem->arch.asid - mem->unuse () - mem->zfree ((unsigned)mem->arch.directory) - -static arch_page_table *alloc_page_table (kMemory *mem): - //dbg_log_line () - arch_page_table *ret = (arch_page_table *)mem->search_free (sizeof (arch_page_table), (void **)&mem->arch.first_page_table) - if !ret: - return NULL - ret->first_page = NULL - return ret - -static arch_page *alloc_page (kMemory *mem, arch_page_table *t): - //dbg_log_line () - arch_page *ret = (arch_page *)mem->search_free (sizeof (arch_page), (void **)&t->first_page) - if !ret: - return NULL - ret->page = NULL - ret->mapping = ~0 - ret->prev_mapped = NULL - ret->next_mapped = NULL - return ret - -static void free_page_table (arch_page_table *t, unsigned idx): - //dbg_log_line () - kMemory *mem = t->address_space - mem->zfree ((unsigned)mem->arch.directory[idx]) - mem->arch.directory[idx] = NULL - mem->arch.shadow[idx] = NULL - mem->free_obj (t, (void **)&mem->arch.first_page_table) - if !mem->arch.first_page_table: - mem->zfree ((unsigned)mem->arch.directory) - mem->zfree ((unsigned)mem->arch.shadow) - mem->arch.directory = NULL - mem->arch.shadow = NULL - -static void tlb_reset (unsigned address, unsigned asid, unsigned value): +static void tlb_reset (kMemory *mem, unsigned address, unsigned value): //dbg_log_line () + unsigned asid = mem->arch.asid + if asids[asid] != (unsigned)mem: + //dbg_log ("not resetting tlb, because the asid is not in use.\n") + return + //dbg_log ("resetting tlb for ") + //dbg_log_num (address) + //dbg_log ("\n") cp0_set (CP0_ENTRY_HI, address | asid) __asm__ volatile ("tlbp") unsigned idx cp0_get (CP0_INDEX, idx) if ~idx & 0x80000000: + __asm__ volatile ("tlbr") if address & (1 << PAGE_BITS): cp0_set (CP0_ENTRY_LO1, value) else: cp0_set (CP0_ENTRY_LO0, value) __asm__ volatile ("tlbwi") -static void free_page (arch_page_table *t, arch_page *p): - //dbg_log_line () - if !p: - dpanic (0, "freeing page 0") - return - if p->prev_mapped: - p->prev_mapped->next_mapped = p->next_mapped - else: - p->page->arch.first_mapped = p->next_mapped - if p->next_mapped: - p->next_mapped->prev_mapped = p->prev_mapped - tlb_reset (p->mapping, p->address_space->arch.asid, 0) - unsigned idx = p->mapping >> 21 - p->address_space->free_obj (p, (void **)&t->first_page) - if !t->first_page: - free_page_table (t, idx) - -static unsigned make_entry_lo (kPage *page, bool readonly): +static unsigned make_entry_lo (kPage *page): //dbg_log_line () if !page->frame: - dbg_log ("not mapping because there is no frame\n") + //dbg_log ("not mapping because there is no frame\n") return 0 unsigned flags if page->flags & Kernel::Page::UNCACHED: @@ -198,121 +146,108 @@ static unsigned make_entry_lo (kPage *page, bool readonly): else: // 18 is write-back cache; 00 is write-through cache. flags = 0x18 | 0x2 - if !readonly: + if ~page->flags & Kernel::Page::MAPPED_READONLY: flags |= 0x4 return ((page->frame & ~0x80000000) >> 6) | flags -bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address, bool readonly): +bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address): //dbg_log_line () if address >= 0x80000000: dpanic (address, "trying to map to kernel address") return false - address &= PAGE_MASK + if page->mapping != ~0: + mem->unmap (page) + if address == ~0: + return true + if address & ~PAGE_MASK: + dpanic (address, "mapping not page-aligned") + address &= PAGE_MASK if !mem->arch.directory: - mem->arch.directory = (unsigned **)mem->zalloc () + //dbg_log ("creating directory\n") + mem->arch.directory = (Table **)mem->zalloc () if !mem->arch.directory: + dpanic (0, "unable to allocate directory") return false - mem->arch.shadow = (arch_page_table **)mem->zalloc () + mem->arch.shadow = (kPageP *)mem->zalloc () if !mem->arch.shadow: + dpanic (0, "unable to allocate shadow directory") mem->zfree ((unsigned)mem->arch.directory) mem->arch.directory = NULL return false - unsigned *table = mem->arch.directory[address >> 21] - arch_page_table *t = mem->arch.shadow[address >> 21] + Table *table = mem->arch.directory[address >> 21] if !table: - table = (unsigned *)mem->zalloc () + //dbg_log ("creating table\n") + table = (Table *)mem->zalloc () if !table: - if !mem->arch.first_page_table: - mem->zfree ((unsigned)mem->arch.directory) - mem->zfree ((unsigned)mem->arch.shadow) - mem->arch.directory = NULL - mem->arch.shadow = NULL - return false - t = alloc_page_table (mem) - if !t: - mem->zfree ((unsigned)table) - if !mem->arch.first_page_table: - mem->zfree ((unsigned)mem->arch.directory) - mem->zfree ((unsigned)mem->arch.shadow) - mem->arch.directory = NULL - mem->arch.shadow = NULL + dpanic (0, "unable to allocate table") + //if mem->arch.first_table == ~0: + // mem->zfree ((unsigned)mem->arch.directory) + // mem->zfree ((unsigned)mem->arch.shadow) + // mem->arch.directory = NULL + // mem->arch.shadow = NULL return false mem->arch.directory[address >> 21] = table - mem->arch.shadow[address >> 21] = t - arch_page *p = alloc_page (mem, t) - if !p: - if !t->first_page: - // This automatically cleans up the rest. - free_page_table (t, address >> 21) - return false unsigned idx = (address >> 12) & ((1 << 9) - 1) - if table[idx]: + if table->entrylo[idx]: dbg_log ("page already mapped: ") dbg_log_num (idx, 3) dbg_log (";") - dbg_log_num (table[idx]) + dbg_log_num (table->entrylo[idx]) dbg_log ("/") - dbg_log_num (table[idx + 0x200]) + dbg_log_num ((unsigned)table->page[idx]) dbg_log (" table: ") dbg_log_num ((unsigned)table) dbg_log ("\n") - mem->unmap ((kPage *)table[idx + 0x200], address) - table[idx] = make_entry_lo (page, readonly) - table[idx + 0x200] = (unsigned)p - dbg_log ("mapped at address ") - dbg_log_num (address) - dbg_log_char ('\n') - p->mapping = address + readonly - p->page = page - p->next_mapped = page->arch.first_mapped - if p->next_mapped: - p->next_mapped->prev_mapped = p - page->arch.first_mapped = p + mem->unmap (table->page[idx]) + table->entrylo[idx] = make_entry_lo (page) + table->page[idx] = page + //dbg_log ("mapped at address ") + //dbg_log_num (address) + //dbg_log_char ('\n') + page->mapping = address + page->arch.next_mapped = mem->arch.shadow[address >> 21] + if page->arch.next_mapped: + page->arch.next_mapped->arch.prev_mapped = page + mem->arch.shadow[address >> 21] = page + tlb_reset (mem, address, table->entrylo[idx]) return true -void kMemory_arch_unmap (kMemory *mem, kPage *page, unsigned address): +void kMemory_arch_unmap (kMemory *mem, kPage *page): //dbg_log_line () - unsigned didx = address >> 21 - unsigned tidx = (address >> 12) & ((1 << 9) - 1) - unsigned *table = mem->arch.directory[didx] - arch_page_table *t = mem->arch.shadow[didx] - table[tidx] = 0 - arch_page *p = (arch_page *)table[tidx + 0x200] - table[tidx + 0x200] = 0 - free_page (t, p) + unsigned didx = page->mapping >> 21 + unsigned tidx = (page->mapping >> 12) & ((1 << 9) - 1) + Table *table = mem->arch.directory[didx] + table->entrylo[tidx] = 0 + table->page[tidx] = NULL + if page->arch.next_mapped: + page->arch.next_mapped->arch.prev_mapped = page->arch.prev_mapped + if page->arch.prev_mapped: + page->arch.prev_mapped->arch.next_mapped = page->arch.next_mapped + else: + mem->arch.shadow[didx] = page->arch.next_mapped + page->arch.prev_mapped = NULL + page->arch.next_mapped = NULL + tlb_reset (mem, page->mapping, 0) + page->mapping = ~0 -kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly): +kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address): //dbg_log_line () if address >= 0x80000000 || !mem->arch.directory: return NULL - unsigned *table = mem->arch.directory[address >> 21] + Table *table = mem->arch.directory[address >> 21] if !table: return NULL - unsigned idx = (address >> 12) & ((1 << 9) - 1) - arch_page *page = (arch_page *)table[idx + 0x200] - if !page: - return NULL - if readonly: - *readonly = !(table[idx] & 4) - return page->page + return table->page[(address >> 12) & ((1 << 9) - 1)] void kPage_arch_update_mapping (kPage *page): //dbg_log_line () - if !page->arch.first_mapped: + if page->mapping == ~0: return - kMemory *as = page->address_space - unsigned target = make_entry_lo (page, page->flags & Kernel::Page::READONLY) - for arch_page *p = page->arch.first_mapped; p; p = p->next_mapped: - unsigned de = p->mapping >> 21 - unsigned te = (p->mapping >> 12) & ((1 << 9) - 1) - bool readonly = p->mapping & 1 - unsigned t - if readonly: - t = target & ~0x4 - else: - t = target - as->arch.directory[de][te] = t - tlb_reset (p->mapping & ~1, as->arch.asid, t) + unsigned target = make_entry_lo (page) + unsigned de = page->mapping >> 21 + unsigned te = (page->mapping >> 12) & ((1 << 9) - 1) + page->address_space->arch.directory[de]->entrylo[te] = target + tlb_reset (page->address_space, page->mapping, target) typedef unsigned cacheline[8] void arch_uncache_page (unsigned page): diff --git a/mips/arch.hhp b/mips/arch.hhp index 36e49bb..abd86be 100644 --- a/mips/arch.hhp +++ b/mips/arch.hhp @@ -93,32 +93,29 @@ struct kThread_arch: unsigned at, v[2], a[4], t[10], s[8], gp, fp, ra, hi, lo, k[2] // The following is used for page mapping. -// Each Memory has a two directories with 0x400 entries, -// page tables and mapping page tables. Mapping page tables are -// pages which contain 0x200 EntryLo. values and 0x200 Page pointers. -// For a virtual address, bits 0-11 are in the physical address, -// bits 12-20 are an index in the page table, bits 21-30 -// are an index in the page directory and bit 31 is always 0. - -struct arch_page : public kObject : - kPage *page - unsigned mapping - arch_page *prev_mapped, *next_mapped - -struct arch_page_table : public kObject : - arch_page *first_page +// Each Memory has a directory with 0x400 page tables. +// Page tables are pages which contain 0x200 EntryLo. values and 0x200 +// kPage pointers. +// For a virtual address, bits 0-11 are in the physical address, bits 12-20 are +// an index in the page table, bits 21-30 are an index in the page directory +// and bit 31 is always 0. struct kPage_arch: - arch_page *first_mapped + kPageP prev_mapped, next_mapped + +struct Table: + unsigned entrylo[0x200] + kPage *page[0x200] struct kMemory_arch: unsigned asid - unsigned **directory - arch_page_table **shadow - arch_page_table *first_page_table + Table **directory + kPageP *shadow + unsigned first_table // Pointers to kMemory when asid is taken, index of next free, or 0, if free. // asid[0] is used as index to first free asid. +// asid value 0 is only used by the idle task. EXTERN unsigned asids[64] EXTERN kReceiverP arch_interrupt_receiver[32] @@ -143,7 +140,7 @@ extern "C": extern unsigned thread_start[NUM_THREADS + 1] #endif // Fast pointer to page directory, for tlb miss events -extern unsigned **directory +extern Table **directory #endif // not defined ASM diff --git a/mips/init.ccp b/mips/init.ccp index 2ad6593..17f32eb 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -44,7 +44,7 @@ static void init_idle (): idle_memory.memories = NULL idle_memory.limit = 0 idle_memory.used = 0 - idle_memory.arch.directory = (unsigned **)0x80000000 + idle_memory.arch.directory = (Table **)0x80000000 // Shadow is never used for the idle task. idle_memory.arch.shadow = NULL idle_memory.arch.asid = 0 @@ -125,7 +125,6 @@ static void init_threads (): #ifndef NDEBUG thread->id = i #endif - kPage **pages = (kPage **)mem->zalloc () Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i] for unsigned j = 0; j < SELFMAG; ++j: if header->e_ident[j] != ELFMAG[j]: @@ -148,6 +147,7 @@ static void init_threads (): return thread->pc = header->e_entry thread->sp = 0x80000000 + unsigned *used = (unsigned *)mem->zalloc () for unsigned section = 0; section < header->e_shnum; ++section: Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize) if ~shdr->sh_flags & SHF_ALLOC: @@ -162,30 +162,35 @@ static void init_threads (): for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE: unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS unsigned idx = file_offset + section_offset - kPage *page = mem->get_mapping (p, &readonly) + kPage *page = mem->get_mapping (p) if page: - if !pages[idx]: - panic (0, "multiple pages mapped to one address in initial file") - return - if pages[idx]->frame != page->frame: + if page->frame != thread_start[i] + (idx << PAGE_BITS): panic (0, "different pages mapped to one address in intitial file") return continue - if !pages[idx]: - pages[idx] = mem->alloc_page () - pages[idx]->frame = thread_start[i] + (idx << PAGE_BITS) - pages[idx]->flags = Kernel::Page::PAYING | Kernel::Page::FRAME - ++top_memory.limit - mem->use () - if !mem->map (pages[idx], p, readonly): + used[idx] = 1 + page = mem->alloc_page () + page->frame = thread_start[i] + (idx << PAGE_BITS) + page->flags = Kernel::Page::PAYING | Kernel::Page::FRAME + if readonly: + page->flags |= Kernel::Page::MAPPED_READONLY + if !mem->map (page, p): panic (0x22446688, "unable to map initial page") return + //dbg_log ("mapped page ") + //if readonly: + // dbg_log ("as readonly ") + //dbg_log ("at address ") + //dbg_log_num (p) + //dbg_log (" for ") + //dbg_log_num (i, 1) + //dbg_log_char ('\n') else: if readonly: panic (0x33399993, "unwritable bss section") return for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE: - kPage *page = mem->get_mapping (p, &readonly) + kPage *page = mem->get_mapping (p) if !page: page = mem->alloc_page () if !page: @@ -199,8 +204,13 @@ static void init_threads (): if !mem->map (page, p): panic (0x33557799, "unable to map initial bss page") return + dbg_log ("mapped bss page at address ") + dbg_log_num (p) + dbg_log (" for ") + dbg_log_num (i, 1) + dbg_log_char ('\n') else: - if readonly: + if page->flags & Kernel::Page::MAPPED_READONLY: panic (0x20203030, "bss section starts on read-only page") return for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4: @@ -210,10 +220,12 @@ static void init_threads (): continue ((unsigned *)page->frame)[(a & ~PAGE_MASK) >> 2] = 0 for unsigned p = 0; p <= ((thread_start[i + 1] - thread_start[i] - 1) >> PAGE_BITS); ++p: - if pages[p]: - continue ++top_memory.limit + if used[p]: + mem->use () + continue top_memory.pfree (thread_start[i] + (p << PAGE_BITS)) + mem->pfree ((unsigned)used) kPage *stackpage = mem->alloc_page () stackpage->frame = mem->zalloc () stackpage->flags = Kernel::Page::PAYING | Kernel::Page::FRAME @@ -242,7 +254,6 @@ static void init_threads (): thread->schedule_prev = previous thread->schedule_next = NULL previous = thread - mem->pfree ((unsigned)pages) // Initialize the kernel, finish by falling into the idle task. void init (unsigned mem): diff --git a/mips/interrupts.ccp b/mips/interrupts.ccp index d596b22..99da592 100644 --- a/mips/interrupts.ccp +++ b/mips/interrupts.ccp @@ -73,7 +73,7 @@ kThread *tlb_refill (): return current unsigned EntryHi cp0_get (CP0_ENTRY_HI, EntryHi) - unsigned *t = directory[EntryHi >> 21] + Table *t = directory[EntryHi >> 21] if !t: unsigned addr cp0_get (CP0_BAD_V_ADDR, addr) @@ -81,9 +81,16 @@ kThread *tlb_refill (): else: // - 2 instead of - 1 means reset bit 0 unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2) - cp0_set (CP0_ENTRY_LO0, t[idx]) - cp0_set (CP0_ENTRY_LO1, t[idx + 1]) + cp0_set (CP0_ENTRY_LO0, t->entrylo[idx]) + cp0_set (CP0_ENTRY_LO1, t->entrylo[idx + 1]) __asm__ volatile ("tlbwr") + //dbg_log ("tlb refill ") + //dbg_log_num (t->entrylo[idx]) + //dbg_log (":") + //dbg_log_num (t->entrylo[idx + 1]) + //dbg_log (" for ") + //dbg_log_num (EntryHi) + //dbg_log ("\n") handle_exit () return current diff --git a/panic.ccp b/panic.ccp index f385aff..b397572 100644 --- a/panic.ccp +++ b/panic.ccp @@ -46,6 +46,29 @@ void dbg_log_num (unsigned num, unsigned digits): #if 1 || defined (NDEBUG) static void panic_message (unsigned n, const char *line, char const *name, char const *message): + //unsigned addr + //cp0_get (CP0_BAD_V_ADDR, addr) + //unsigned de = addr >> 21 + //unsigned te = (addr >> 12) & ((1 << 9) - 1) + //dbg_log_num ((unsigned)old_current->address_space->arch.directory[de]->page[te]) + //dbg_log (":") + //dbg_log_num (old_current->address_space->arch.directory[de]->entrylo[te]) + //dbg_log ("\n") + //__asm__ volatile ("tlbp") + //unsigned idx, hi + //cp0_get (CP0_INDEX, idx) + //dbg_log_num (idx) + //dbg_log (":") + //cp0_get (CP0_ENTRY_HI, hi) + //dbg_log_num (hi) + //dbg_log (":") + //unsigned lo + //cp0_get (CP0_ENTRY_LO0, lo) + //dbg_log_num (lo) + //dbg_log (":") + //cp0_get (CP0_ENTRY_LO1, lo) + //dbg_log_num (lo) + //dbg_log ("\n") dbg_log ("Panic: caller = ") if old_current: dbg_log_num (old_current->id, 2)