diff --git a/AK/Bitmap.h b/AK/Bitmap.h index 553d1b12b1..c2f6993f76 100644 --- a/AK/Bitmap.h +++ b/AK/Bitmap.h @@ -3,6 +3,7 @@ #include "StdLib.h" #include "Types.h" #include "kmalloc.h" +#include "Assertions.h" namespace AK { @@ -14,9 +15,9 @@ public: return Bitmap(data, size); } - static Bitmap create(unsigned size) + static Bitmap create(unsigned size, bool default_value = 0) { - return Bitmap(size); + return Bitmap(size, default_value); } ~Bitmap() @@ -45,12 +46,14 @@ public: const byte* data() const { return m_data; } private: - explicit Bitmap(unsigned size) + explicit Bitmap(unsigned size, bool default_value) : m_size(size) , m_owned(true) { ASSERT(m_size != 0); - m_data = reinterpret_cast(kmalloc(ceilDiv(size, 8u))); + size_t size_to_allocate = ceilDiv(size, 8u); + m_data = reinterpret_cast(kmalloc(size_to_allocate)); + memset(m_data, default_value ? 0xff : 0x00, size_to_allocate); } Bitmap(byte* data, unsigned size) diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index 8dbce26612..93989f8d0d 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -7,6 +7,7 @@ #include "Process.h" //#define MM_DEBUG +//#define PAGE_FAULT_DEBUG #define SCRUB_DEALLOCATED_PAGE_TABLES static MemoryManager* s_the; @@ -67,7 +68,7 @@ void MemoryManager::initializePaging() memset(m_kernel_page_directory, 0, sizeof(PageDirectory)); #ifdef MM_DEBUG - kprintf("MM: Kernel page directory @ %p\n", m_kernel_page_directory); + dbgprintf("MM: Kernel page directory @ %p\n", m_kernel_page_directory); #endif // Make null dereferences crash. @@ -208,15 +209,66 @@ void MemoryManager::initialize() s_the = new MemoryManager; } +Region* MemoryManager::region_from_laddr(Process& process, LinearAddress laddr) +{ + ASSERT_INTERRUPTS_DISABLED(); + + // FIXME: Use a binary search tree (maybe red/black?) or some other more appropriate data structure! + for (auto& region : process.m_regions) { + if (region->contains(laddr)) + return region.ptr(); + } + ASSERT_NOT_REACHED(); +} + +bool MemoryManager::copy_on_write(Process& process, Region& region, unsigned page_index_in_region) +{ +#ifdef PAGE_FAULT_DEBUG + dbgprintf(" >> It's a COW page and it's time to COW!\n"); +#endif + auto physical_page_to_copy = move(region.physical_pages[page_index_in_region]); + auto ppages = allocate_physical_pages(1); + ASSERT(ppages.size() == 1); + byte* dest_ptr = quickmap_page(*ppages[0]); + const byte* src_ptr = region.linearAddress.offset(page_index_in_region * PAGE_SIZE).asPtr(); +#ifdef PAGE_FAULT_DEBUG + dbgprintf(" >> COW P%x <- P%x\n", ppages[0]->paddr().get(), physical_page_to_copy->paddr().get()); +#endif + memcpy(dest_ptr, src_ptr, PAGE_SIZE); + region.physical_pages[page_index_in_region] = move(ppages[0]); + unquickmap_page(); + region.cow_map.set(page_index_in_region, false); + remap_region_page(process.m_page_directory, region, page_index_in_region, true); + return true; +} + PageFaultResponse MemoryManager::handle_page_fault(const PageFault& fault) { ASSERT_INTERRUPTS_DISABLED(); - kprintf("MM: handle_page_fault(%w) at L%x\n", fault.code(), fault.laddr().get()); +#ifdef PAGE_FAULT_DEBUG + dbgprintf("MM: handle_page_fault(%w) at L%x\n", fault.code(), fault.laddr().get()); +#endif + auto* region = region_from_laddr(*current, fault.laddr()); + ASSERT(region); + auto page_index_in_region = region->page_index_from_address(fault.laddr()); if (fault.is_not_present()) { - kprintf(" >> NP fault!\n"); + kprintf(" >> NP fault in Region{%p}[%u]\n", region, page_index_in_region); } else if (fault.is_protection_violation()) { - kprintf(" >> PV fault!\n"); + if (region->cow_map.get(page_index_in_region)) { +#ifdef PAGE_FAULT_DEBUG + dbgprintf(" >> PV (COW) fault in Region{%p}[%u]\n", region, page_index_in_region); +#endif + bool success = copy_on_write(*current, *region, page_index_in_region); + ASSERT(success); + return PageFaultResponse::Continue; + } + kprintf(" >> PV fault in Region{%p}[%u]\n", region, page_index_in_region); + } else { + ASSERT_NOT_REACHED(); } + + + return PageFaultResponse::ShouldCrash; } @@ -264,6 +316,66 @@ void MemoryManager::flushTLB(LinearAddress laddr) asm volatile("invlpg %0": :"m" (*(char*)laddr.get()) : "memory"); } +byte* MemoryManager::quickmap_page(PhysicalPage& physical_page) +{ + ASSERT_INTERRUPTS_DISABLED(); + auto page_laddr = LinearAddress(4 * MB); + auto pte = ensurePTE(m_kernel_page_directory, page_laddr); + pte.setPhysicalPageBase(physical_page.paddr().get()); + pte.setPresent(true); // FIXME: Maybe we should use the is_readable flag here? + pte.setWritable(true); + pte.setUserAllowed(false); + flushTLB(page_laddr); +#ifdef MM_DEBUG + dbgprintf("MM: >> quickmap_page L%x => P%x\n", page_laddr, physical_page.paddr().get()); +#endif + return page_laddr.asPtr(); +} + +void MemoryManager::unquickmap_page() +{ + ASSERT_INTERRUPTS_DISABLED(); + auto page_laddr = LinearAddress(4 * MB); + auto pte = ensurePTE(m_kernel_page_directory, page_laddr); +#ifdef MM_DEBUG + auto old_physical_address = pte.physicalPageBase(); +#endif + pte.setPhysicalPageBase(0); + pte.setPresent(false); + pte.setWritable(false); + pte.setUserAllowed(false); + flushTLB(page_laddr); +#ifdef MM_DEBUG + dbgprintf("MM: >> unquickmap_page L%x =/> P%x\n", page_laddr, old_physical_address); +#endif +} + +void MemoryManager::remap_region_page(PageDirectory* page_directory, Region& region, unsigned page_index_in_region, bool user_allowed) +{ + InterruptDisabler disabler; + auto page_laddr = region.linearAddress.offset(page_index_in_region * PAGE_SIZE); + auto pte = ensurePTE(page_directory, page_laddr); + auto& physical_page = region.physical_pages[page_index_in_region]; + ASSERT(physical_page); + pte.setPhysicalPageBase(physical_page->paddr().get()); + pte.setPresent(true); // FIXME: Maybe we should use the is_readable flag here? + if (region.cow_map.get(page_index_in_region)) + pte.setWritable(false); + else + pte.setWritable(region.is_writable); + pte.setUserAllowed(user_allowed); + flushTLB(page_laddr); +#ifdef MM_DEBUG + dbgprintf("MM: >> remap_region_page (PD=%x) '%s' L%x => P%x (@%p)\n", page_directory, region.name.characters(), page_laddr.get(), physical_page->paddr().get(), physical_page.ptr()); +#endif +} + +void MemoryManager::remap_region(Process& process, Region& region) +{ + InterruptDisabler disabler; + map_region_at_address(process.m_page_directory, region, region.linearAddress, true); +} + void MemoryManager::map_region_at_address(PageDirectory* page_directory, Region& region, LinearAddress laddr, bool user_allowed) { InterruptDisabler disabler; @@ -274,11 +386,15 @@ void MemoryManager::map_region_at_address(PageDirectory* page_directory, Region& if (physical_page) { pte.setPhysicalPageBase(physical_page->paddr().get()); pte.setPresent(true); // FIXME: Maybe we should use the is_readable flag here? + if (region.cow_map.get(i)) + pte.setWritable(false); + else + pte.setWritable(region.is_writable); } else { pte.setPhysicalPageBase(0); pte.setPresent(false); + pte.setWritable(region.is_writable); } - pte.setWritable(region.is_writable); pte.setUserAllowed(user_allowed); flushTLB(page_laddr); #ifdef MM_DEBUG @@ -399,34 +515,27 @@ bool MemoryManager::validate_user_write(const Process& process, LinearAddress la RetainPtr Region::clone() { InterruptDisabler disabler; - KernelPagingScope pagingScope; if (is_readable && !is_writable) { // Create a new region backed by the same physical pages. return adopt(*new Region(linearAddress, size, physical_pages, String(name), is_readable, is_writable)); } - // FIXME: Implement COW regions. - auto clone_physical_pages = MM.allocate_physical_pages(physical_pages.size()); - auto clone_region = adopt(*new Region(linearAddress, size, move(clone_physical_pages), String(name), is_readable, is_writable)); - // FIXME: It would be cool to make the src_alias a read-only mapping. - byte* src_alias = MM.create_kernel_alias_for_region(*this); - byte* dest_alias = MM.create_kernel_alias_for_region(*clone_region); - - memcpy(dest_alias, src_alias, size); - - MM.remove_kernel_alias_for_region(*clone_region, dest_alias); - MM.remove_kernel_alias_for_region(*this, src_alias); - return clone_region; + // Set up a COW region. The parent (this) region becomes COW as well! + for (size_t i = 0; i < physical_pages.size(); ++i) + cow_map.set(i, true); + MM.remap_region(*current, *this); + return adopt(*new Region(linearAddress, size, physical_pages, String(name), is_readable, is_writable, true)); } -Region::Region(LinearAddress a, size_t s, Vector> pp, String&& n, bool r, bool w) +Region::Region(LinearAddress a, size_t s, Vector> pp, String&& n, bool r, bool w, bool cow) : linearAddress(a) , size(s) , physical_pages(move(pp)) , name(move(n)) , is_readable(r) , is_writable(w) + , cow_map(Bitmap::create(physical_pages.size(), cow)) { } diff --git a/Kernel/MemoryManager.h b/Kernel/MemoryManager.h index e02a930fbb..415fa83a28 100644 --- a/Kernel/MemoryManager.h +++ b/Kernel/MemoryManager.h @@ -2,6 +2,7 @@ #include "types.h" #include "i386.h" +#include #include #include #include @@ -54,16 +55,27 @@ struct PageDirectory { }; struct Region : public Retainable { - Region(LinearAddress, size_t, Vector>, String&&, bool r, bool w); + Region(LinearAddress, size_t, Vector>, String&&, bool r, bool w, bool cow = false); ~Region(); RetainPtr clone(); + bool contains(LinearAddress laddr) const + { + return laddr >= linearAddress && laddr < linearAddress.offset(size); + } + + unsigned page_index_from_address(LinearAddress laddr) const + { + return (laddr - linearAddress).get() / PAGE_SIZE; + } + LinearAddress linearAddress; size_t size { 0 }; Vector> physical_pages; String name; bool is_readable { true }; bool is_writable { true }; + Bitmap cow_map; }; #define MM MemoryManager::the() @@ -98,6 +110,8 @@ public: Vector> allocate_physical_pages(size_t count); + void remap_region(Process&, Region&); + private: MemoryManager(); ~MemoryManager(); @@ -105,6 +119,7 @@ private: LinearAddress allocate_linear_address_range(size_t); void map_region_at_address(PageDirectory*, Region&, LinearAddress, bool user_accessible); void unmap_range(PageDirectory*, LinearAddress, size_t); + void remap_region_page(PageDirectory*, Region&, unsigned page_index_in_region, bool user_allowed); void initializePaging(); void flushEntireTLB(); @@ -118,6 +133,13 @@ private: void create_identity_mapping(LinearAddress, size_t length); void remove_identity_mapping(LinearAddress, size_t); + static Region* region_from_laddr(Process&, LinearAddress); + + bool copy_on_write(Process&, Region&, unsigned page_index_in_region); + + byte* quickmap_page(PhysicalPage&); + void unquickmap_page(); + struct PageDirectoryEntry { explicit PageDirectoryEntry(dword* pde) : m_pde(pde) { } diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp index d68813eb6f..0516089dbd 100644 --- a/Kernel/ProcFileSystem.cpp +++ b/Kernel/ProcFileSystem.cpp @@ -59,8 +59,12 @@ ByteBuffer procfs$pid_vm(Process& process) region->linearAddress.offset(region->size - 1).get(), region->size, region->name.characters()); - for (auto& physical_page : region->physical_pages) { - ptr += ksprintf(ptr, "P%x ", physical_page ? physical_page->paddr().get() : 0); + for (size_t i = 0; i < region->physical_pages.size(); ++i) { + auto& physical_page = region->physical_pages[i]; + ptr += ksprintf(ptr, "P%x%s ", + physical_page ? physical_page->paddr().get() : 0, + region->cow_map.get(i) ? "!" : "" + ); } ptr += ksprintf(ptr, "\n"); } @@ -249,24 +253,6 @@ ByteBuffer procfs$kmalloc() return buffer; } -static const char* toString(Process::State state) -{ - switch (state) { - case Process::Invalid: return "Invalid"; - case Process::Runnable: return "Runnable"; - case Process::Running: return "Running"; - case Process::Terminated: return "Term"; - case Process::Crashing: return "Crash"; - case Process::Exiting: return "Exit"; - case Process::BlockedSleep: return "Sleep"; - case Process::BlockedWait: return "Wait"; - case Process::BlockedRead: return "Read"; - case Process::BeingInspected: return "Inspect"; - } - ASSERT_NOT_REACHED(); - return nullptr; -} - ByteBuffer procfs$summary() { InterruptDisabler disabler; diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 701065d7e7..3c88ff83d2 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -19,6 +19,14 @@ //#define TASK_DEBUG //#define FORK_DEBUG //#define SCHEDULER_DEBUG +#define COOL_GLOBALS + +#ifdef COOL_GLOBALS +struct CoolGlobals { + dword current_pid; +}; +CoolGlobals* g_cool_globals; +#endif // FIXME: Only do a single validation for accesses that don't span multiple pages. // FIXME: Some places pass strlen(arg1) as arg2. This doesn't seem entirely perfect.. @@ -96,6 +104,9 @@ static void hlt_loop() void Process::initialize() { +#ifdef COOL_GLOBALS + g_cool_globals = (CoolGlobals*)0x1000; +#endif current = nullptr; next_pid = 0; s_processes = new InlineLinkedList; @@ -353,6 +364,7 @@ int Process::exec(const String& path, Vector&& arguments, Vector m_tss.ds = 0x23; m_tss.es = 0x23; m_tss.fs = 0x23; + m_tss.gs = 0x23; m_tss.ss = 0x23; m_tss.cr3 = (dword)m_page_directory; auto* stack_region = allocate_region(LinearAddress(), defaultStackSize, "stack"); @@ -845,7 +857,7 @@ bool scheduleNewProcess() for (auto* process = s_processes->head(); process; process = process->next()) { //if (process->state() == Process::BlockedWait || process->state() == Process::BlockedSleep) // continue; - dbgprintf("%w %s(%u) @ %w:%x\n", process->state(), process->name().characters(), process->pid(), process->tss().cs, process->tss().eip); + dbgprintf("% 12s %s(%u) @ %w:%x\n", toString(process->state()), process->name().characters(), process->pid(), process->tss().cs, process->tss().eip); } #endif @@ -915,6 +927,10 @@ static bool contextSwitch(Process* t) current = t; t->set_state(Process::Running); +#ifdef COOL_GLOBALS + g_cool_globals->current_pid = t->pid(); +#endif + if (!t->selector()) { t->setSelector(gdt_alloc_entry()); auto& descriptor = getGDTEntry(t->selector()); diff --git a/Kernel/Process.h b/Kernel/Process.h index 2d8acee68c..c6cb4d49cb 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -236,6 +236,24 @@ private: Process::State m_original_state { Process::Invalid }; }; +static inline const char* toString(Process::State state) +{ + switch (state) { + case Process::Invalid: return "Invalid"; + case Process::Runnable: return "Runnable"; + case Process::Running: return "Running"; + case Process::Terminated: return "Term"; + case Process::Crashing: return "Crash"; + case Process::Exiting: return "Exit"; + case Process::BlockedSleep: return "Sleep"; + case Process::BlockedWait: return "Wait"; + case Process::BlockedRead: return "Read"; + case Process::BeingInspected: return "Inspect"; + } + ASSERT_NOT_REACHED(); + return nullptr; +} + extern void yield(); extern bool scheduleNewProcess(); extern void switchNow(); diff --git a/Kernel/StdLib.h b/Kernel/StdLib.h index 112aa8dad6..8b58218418 100644 --- a/Kernel/StdLib.h +++ b/Kernel/StdLib.h @@ -2,17 +2,7 @@ #include "types.h" -#if 0 -inline void memcpy(void *dest, const void *src, DWORD n) -{ - BYTE* bdest = (BYTE*)dest; - const BYTE* bsrc = (const BYTE*)src; - for (; n; --n) - *(bdest++) = *(bsrc++); -} -#else void memcpy(void*, const void*, DWORD); -#endif void strcpy(char*, const char*); int strcmp(char const*, const char*); DWORD strlen(const char*); diff --git a/Kernel/i386.cpp b/Kernel/i386.cpp index 0eefee4676..dfc903a48c 100644 --- a/Kernel/i386.cpp +++ b/Kernel/i386.cpp @@ -56,24 +56,12 @@ asm( " iret\n" ); -extern volatile dword exception_state_dump; -extern volatile word exception_code; -asm( - ".globl exception_state_dump\n" - "exception_state_dump:\n" - ".long 0\n" - ".globl exception_code\n" - "exception_code:\n" - ".short 0\n" -); - #define EH_ENTRY(ec) \ -extern "C" void exception_ ## ec ## _handler(); \ +extern "C" void exception_ ## ec ## _handler(RegisterDumpWithExceptionCode&); \ extern "C" void exception_ ## ec ## _entry(); \ asm( \ ".globl exception_" # ec "_entry\n" \ "exception_" # ec "_entry: \n" \ - " pop exception_code\n" \ " pusha\n" \ " pushw %ds\n" \ " pushw %es\n" \ @@ -88,7 +76,7 @@ asm( \ " popw %es\n" \ " popw %fs\n" \ " popw %gs\n" \ - " mov %esp, exception_state_dump\n" \ + " mov %esp, %eax\n" \ " call exception_" # ec "_handler\n" \ " popw %gs\n" \ " popw %gs\n" \ @@ -96,11 +84,12 @@ asm( \ " popw %es\n" \ " popw %ds\n" \ " popa\n" \ + " add $0x4, %esp\n" \ " iret\n" \ ); #define EH_ENTRY_NO_CODE(ec) \ -extern "C" void exception_ ## ec ## _handler(); \ +extern "C" void exception_ ## ec ## _handler(RegisterDump&); \ extern "C" void exception_ ## ec ## _entry(); \ asm( \ ".globl exception_" # ec "_entry\n" \ @@ -119,7 +108,7 @@ asm( \ " popw %es\n" \ " popw %fs\n" \ " popw %gs\n" \ - " mov %esp, exception_state_dump\n" \ + " mov %esp, %eax\n" \ " call exception_" # ec "_handler\n" \ " popw %gs\n" \ " popw %gs\n" \ @@ -132,9 +121,8 @@ asm( \ // 6: Invalid Opcode EH_ENTRY_NO_CODE(6); -void exception_6_handler() +void exception_6_handler(RegisterDump& regs) { - auto& regs = *reinterpret_cast(exception_state_dump); kprintf("%s invalid opcode: %u(%s)\n", current->isRing0() ? "Kernel" : "Process", current->pid(), current->name().characters()); word ss; @@ -147,7 +135,6 @@ void exception_6_handler() esp = regs.esp_if_crossRing; } - kprintf("exception code: %w\n", exception_code); kprintf("pc=%w:%x ds=%w es=%w fs=%w gs=%w\n", regs.cs, regs.eip, regs.ds, regs.es, regs.fs, regs.gs); kprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx); kprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, esp, regs.esi, regs.edi); @@ -163,10 +150,9 @@ void exception_6_handler() // 13: General Protection Fault EH_ENTRY(13); -void exception_13_handler() +void exception_13_handler(RegisterDumpWithExceptionCode& regs) { - auto& regs = *reinterpret_cast(exception_state_dump); - kprintf("%s crash: %u(%s)\n", current->isRing0() ? "Kernel" : "Process", current->pid(), current->name().characters()); + kprintf("%s GPF: %u(%s)\n", current->isRing0() ? "Kernel" : "User", current->pid(), current->name().characters()); word ss; dword esp; @@ -178,7 +164,7 @@ void exception_13_handler() esp = regs.esp_if_crossRing; } - kprintf("exception code: %w\n", exception_code); + kprintf("exception code: %w\n", regs.exception_code); kprintf("pc=%w:%x ds=%w es=%w fs=%w gs=%w\n", regs.cs, regs.eip, regs.ds, regs.es, regs.fs, regs.gs); kprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx); kprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, esp, regs.esi, regs.edi); @@ -193,19 +179,18 @@ void exception_13_handler() // 14: Page Fault EH_ENTRY(14); -void exception_14_handler() +void exception_14_handler(RegisterDumpWithExceptionCode& regs) { ASSERT(current); dword faultAddress; asm ("movl %%cr2, %%eax":"=a"(faultAddress)); - auto& regs = *reinterpret_cast(exception_state_dump); - kprintf("Ring%u page fault in %s(%u), %s laddr=%p\n", + dbgprintf("Ring%u page fault in %s(%u), %s laddr=%p\n", regs.cs & 3, current->name().characters(), current->pid(), - exception_code & 2 ? "write" : "read", + regs.exception_code & 2 ? "write" : "read", faultAddress); word ss; @@ -218,13 +203,15 @@ void exception_14_handler() esp = regs.esp_if_crossRing; } - kprintf("exception code: %w\n", exception_code); - kprintf("pc=%w:%x ds=%w es=%w fs=%w gs=%w\n", regs.cs, regs.eip, regs.ds, regs.es, regs.fs, regs.gs); - kprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx); - kprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, esp, regs.esi, regs.edi); +#ifdef PAGE_FAULT_DEBUG + dbgprintf("exception code: %w\n", regs.exception_code); + dbgprintf("pc=%w:%x ds=%w es=%w fs=%w gs=%w\n", regs.cs, regs.eip, regs.ds, regs.es, regs.fs, regs.gs); + dbgprintf("stk=%w:%x\n", ss, esp); + dbgprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx); + dbgprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, esp, regs.esi, regs.edi); byte* codeptr = (byte*)regs.eip; - kprintf("code: %b %b %b %b %b %b %b %b\n", + dbgprintf("code: %b %b %b %b %b %b %b %b\n", codeptr[0], codeptr[1], codeptr[2], @@ -234,17 +221,20 @@ void exception_14_handler() codeptr[6], codeptr[7] ); +#endif if (current->isRing0()) HANG; - auto response = MM.handle_page_fault(PageFault(exception_code, LinearAddress(faultAddress))); + auto response = MM.handle_page_fault(PageFault(regs.exception_code, LinearAddress(faultAddress))); if (response == PageFaultResponse::ShouldCrash) { kprintf("Crashing after unresolved page fault\n"); Process::processDidCrash(current); } else if (response == PageFaultResponse::Continue) { - kprintf("Continuing after resolved page fault\n"); +#ifdef PAGE_FAULT_DEBUG + dbgprintf("Continuing after resolved page fault\n"); +#endif } else { ASSERT_NOT_REACHED(); } diff --git a/Kernel/i386.h b/Kernel/i386.h index c17c61bfa2..7842c1ce08 100644 --- a/Kernel/i386.h +++ b/Kernel/i386.h @@ -170,6 +170,30 @@ struct RegisterDump { WORD ss_if_crossRing; } PACKED; +struct RegisterDumpWithExceptionCode { + WORD ss; + WORD gs; + WORD fs; + WORD es; + WORD ds; + DWORD edi; + DWORD esi; + DWORD ebp; + DWORD esp; + DWORD ebx; + DWORD edx; + DWORD ecx; + DWORD eax; + WORD exception_code; + WORD __exception_code_padding; + DWORD eip; + WORD cs; + WORD __csPadding; + DWORD eflags; + DWORD esp_if_crossRing; + WORD ss_if_crossRing; +} PACKED; + inline constexpr dword pageBaseOf(dword address) { return address & 0xfffff000; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index ce41514fcc..aa4a339116 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -100,23 +100,34 @@ static void loadKsyms(const ByteBuffer& buffer) s_ksyms_ready = true; } -void dump_backtrace() +void dump_backtrace(bool use_ksyms) { - if (!current) + if (!current) { + HANG; return; + } extern volatile bool ksyms_ready(); - if (!ksyms_ready()) + if (use_ksyms && !ksyms_ready()) { + HANG; return; - dword stack_variable; + } struct RecognizedSymbol { dword address; const KSym* ksym; }; Vector recognizedSymbols; - for (dword* stackPtr = &stack_variable; current->isValidAddressForKernel(LinearAddress((dword)stackPtr)); stackPtr = (dword*)*stackPtr) { - dword retaddr = stackPtr[1]; - if (auto* ksym = ksymbolicate(retaddr)) - recognizedSymbols.append({ retaddr, ksym }); + if (use_ksyms) { + for (dword* stackPtr = (dword*)&use_ksyms; current->isValidAddressForKernel(LinearAddress((dword)stackPtr)); stackPtr = (dword*)*stackPtr) { + dword retaddr = stackPtr[1]; + if (auto* ksym = ksymbolicate(retaddr)) + recognizedSymbols.append({ retaddr, ksym }); + } + } else{ + for (dword* stackPtr = (dword*)&use_ksyms; current->isValidAddressForKernel(LinearAddress((dword)stackPtr)); stackPtr = (dword*)*stackPtr) { + dword retaddr = stackPtr[1]; + kprintf("%x (next: %x)\n", retaddr, stackPtr ? (dword*)*stackPtr : 0); + } + return; } size_t bytesNeeded = 0; for (auto& symbol : recognizedSymbols) { diff --git a/Kernel/types.h b/Kernel/types.h index 8a61b405a5..4fd1375ef0 100644 --- a/Kernel/types.h +++ b/Kernel/types.h @@ -105,3 +105,8 @@ public: private: dword m_address { 0 }; }; + +inline LinearAddress operator-(const LinearAddress& a, const LinearAddress& b) +{ + return LinearAddress(a.get() - b.get()); +}