From ea2abd110bd6a4518a954477562e2dd94a5fef9d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 3 Aug 2009 12:39:56 +0000 Subject: [PATCH] * Renamed the ROUNDOWN macro to ROUNDDOWN. Also changed the implementation of ROUNDUP to use '*' and '/' -- the compiler will optimize that for powers of two anyway and this implementation works for other numbers as well. * The thread::fault_handler use in C[++] code was broken with gcc 4. At least when other functions were invoked. Trying to trick the compiler wasn't a particularly good idea anyway, since the next compiler version could break the trick again. So the general policy is to use the fault handlers only in assembly code where we have full control. Changed that for x86 (save for the vm86 mode, which has a similar mechanism), but not for the other architectures. * Introduced fault_handler, fault_handler_stack_pointer, and fault_jump_buffer fields in the cpu_ent structure, which must be used instead of thread::fault_handler in the kernel debugger. Consequently user_memcpy() must not be used in the kernel debugger either. Introduced a debug_memcpy() instead. * Introduced debug_call_with_fault_handler() function which calls a function in a setjmp() and fault handler context. The architecture specific backend arch_debug_call_with_fault_handler() has only been implemented for x86 yet. * Introduced debug_is_kernel_memory_accessible() for use in the kernel debugger. It determines whether a range of memory can be accessed in the way specified. The architecture specific back end arch_vm_translation_map_is_kernel_page_accessible() has only been implemented for x86 yet. * Added arch_debug_unset_current_thread() (only implemented for x86) to unset the current thread pointer in the kernel debugger. When entering the kernel debugger we do some basic sanity checks of the currently set thread structure and unset it, if they fail. This allows certain commands (most importantly the stack trace command) to avoid accessing the thread structure. * x86: When handling a double fault, we do now install a special handler for page faults. This allows us to gracefully catch faulting commands, even if e.g. the thread structure is toast. We are now in much better shape to deal with double faults. Hopefully avoiding the triple faults that some people have been experiencing on their hardware and ideally even allowing to use the kernel debugger normally. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32073 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/arch/debug.h | 6 + .../private/kernel/arch/vm_translation_map.h | 7 +- headers/private/kernel/arch/x86/arch_cpu.h | 1 + headers/private/kernel/cpu.h | 23 ++- headers/private/kernel/debug.h | 10 +- headers/private/kernel/kernel.h | 4 +- src/system/boot/loader/elf.cpp | 6 +- src/system/boot/loader/kernel_args.cpp | 4 +- src/system/boot/platform/bios_ia32/mmu.cpp | 2 +- .../platform/openfirmware/arch/ppc/mmu.cpp | 4 +- src/system/boot/platform/u-boot/mmu.cpp | 2 +- src/system/kernel/arch/m68k/arch_cpu.cpp | 24 ++- src/system/kernel/arch/m68k/arch_debug.cpp | 37 ++-- .../m68k/arch_vm_translation_map_impl.cpp | 12 +- src/system/kernel/arch/ppc/arch_cpu.cpp | 22 +- src/system/kernel/arch/ppc/arch_debug.cpp | 37 ++-- .../arch/ppc/arch_vm_translation_map.cpp | 18 +- src/system/kernel/arch/x86/arch_debug.cpp | 61 ++++-- src/system/kernel/arch/x86/arch_int.cpp | 194 ++++++++++++------ src/system/kernel/arch/x86/arch_interrupts.S | 18 ++ .../arch/x86/arch_vm_translation_map.cpp | 76 ++++++- src/system/kernel/arch/x86/arch_x86.S | 49 +++++ src/system/kernel/arch/x86/asm_offsets.cpp | 6 + src/system/kernel/arch/x86/interrupts.h | 1 + .../arch/x86/x86_physical_page_mapper.h | 6 + .../x86_physical_page_mapper_large_memory.cpp | 4 +- src/system/kernel/debug/debug.cpp | 141 ++++++++++++- src/system/kernel/debug/debug_commands.cpp | 48 +++-- src/system/kernel/debug/debug_parser.cpp | 5 +- src/system/kernel/debug/gdb.cpp | 4 +- src/system/kernel/elf.cpp | 10 +- src/system/kernel/slab/Slab.cpp | 2 +- src/system/kernel/vm/vm.cpp | 32 ++- 33 files changed, 649 insertions(+), 227 deletions(-) diff --git a/headers/private/kernel/arch/debug.h b/headers/private/kernel/arch/debug.h index 17e9802023..a910fa9626 100644 --- a/headers/private/kernel/arch/debug.h +++ b/headers/private/kernel/arch/debug.h @@ -11,6 +11,9 @@ #include +#include + + struct kernel_args; struct thread; @@ -27,6 +30,9 @@ void* arch_debug_get_interrupt_pc(bool* _isSyscall); bool arch_debug_contains_call(struct thread *thread, const char *symbol, addr_t start, addr_t end); void arch_debug_save_registers(int *); +void arch_debug_unset_current_thread(void); +void arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer, + void (*function)(void*), void* parameter); bool arch_is_debug_variable_defined(const char* variableName); status_t arch_set_debug_variable(const char* variableName, uint64 value); diff --git a/headers/private/kernel/arch/vm_translation_map.h b/headers/private/kernel/arch/vm_translation_map.h index 13c530c4e1..855c1464ee 100644 --- a/headers/private/kernel/arch/vm_translation_map.h +++ b/headers/private/kernel/arch/vm_translation_map.h @@ -23,11 +23,14 @@ status_t arch_vm_translation_map_init(struct kernel_args *args); status_t arch_vm_translation_map_init_post_area(struct kernel_args *args); status_t arch_vm_translation_map_init_post_sem(struct kernel_args *args); -// quick function to map a page in regardless of map context. Used in VM initialization, -// before most vm data structures exist +// Quick function to map a page in regardless of map context. Used in VM +// initialization before most vm data structures exist. status_t arch_vm_translation_map_early_map(struct kernel_args *args, addr_t va, addr_t pa, uint8 attributes, addr_t (*get_free_page)(struct kernel_args *)); +bool arch_vm_translation_map_is_kernel_page_accessible(addr_t virtualAddress, + uint32 protection); + #ifdef __cplusplus } #endif diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 6c94982f37..c93ddef224 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -284,6 +284,7 @@ bool x86_check_feature(uint32 feature, enum x86_feature_type type); void* x86_get_double_fault_stack(int32 cpu, size_t* _size); int32 x86_double_fault_get_cpu(void); void x86_double_fault_exception(struct iframe* frame); +void x86_page_fault_exception_double_fault(struct iframe* frame); #define read_cr3(value) \ diff --git a/headers/private/kernel/cpu.h b/headers/private/kernel/cpu.h index 2f681204aa..b3e38b925c 100644 --- a/headers/private/kernel/cpu.h +++ b/headers/private/kernel/cpu.h @@ -9,6 +9,8 @@ #define _KERNEL_CPU_H +#include + #include #include #include @@ -24,19 +26,24 @@ /* CPU local data structure */ typedef struct cpu_ent { - int cpu_num; + int cpu_num; // thread.c: used to force a reschedule at quantum expiration time - int preempted; - timer quantum_timer; + int preempted; + timer quantum_timer; // keeping track of CPU activity - bigtime_t active_time; - bigtime_t last_kernel_time; - bigtime_t last_user_time; + bigtime_t active_time; + bigtime_t last_kernel_time; + bigtime_t last_user_time; - bool invoke_scheduler; - bool disabled; + // used in the kernel debugger + addr_t fault_handler; + addr_t fault_handler_stack_pointer; + jmp_buf fault_jump_buffer; + + bool invoke_scheduler; + bool disabled; // arch-specific stuff arch_cpu_info arch; diff --git a/headers/private/kernel/debug.h b/headers/private/kernel/debug.h index 83b807e6aa..50bc105ac4 100644 --- a/headers/private/kernel/debug.h +++ b/headers/private/kernel/debug.h @@ -8,11 +8,14 @@ #ifndef _KERNEL_DEBUG_H #define _KERNEL_DEBUG_H -#include "kernel_debug_config.h" + +#include #include #include +#include "kernel_debug_config.h" + /* KDEBUG The kernel debug level. @@ -123,6 +126,11 @@ extern debug_page_fault_info* debug_get_page_fault_info(); extern void debug_trap_cpu_in_kdl(int32 cpu, bool returnIfHandedOver); extern void debug_double_fault(int32 cpu); extern bool debug_emergency_key_pressed(char key); +extern bool debug_is_kernel_memory_accessible(addr_t address, size_t size, + uint32 protection); +extern int debug_call_with_fault_handler(jmp_buf jumpBuffer, + void (*function)(void*), void* parameter); +extern status_t debug_memcpy(void* to, const void* from, size_t size); extern char kgetc(void); extern void kputs(const char *string); diff --git a/headers/private/kernel/kernel.h b/headers/private/kernel/kernel.h index 5dee855b8a..56117b9f26 100644 --- a/headers/private/kernel/kernel.h +++ b/headers/private/kernel/kernel.h @@ -39,8 +39,8 @@ #define ENV_SIZE (B_PAGE_SIZE * 8) -#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) -#define ROUNDOWN(a, b) (((a) / (b)) * (b)) +#define ROUNDDOWN(a, b) (((a) / (b)) * (b)) +#define ROUNDUP(a, b) ROUNDDOWN((a) + (b) - 1, b) #define CHECK_BIT(a, b) ((a) & (1 << (b))) diff --git a/src/system/boot/loader/elf.cpp b/src/system/boot/loader/elf.cpp index fbb5e3611a..4940f0e822 100644 --- a/src/system/boot/loader/elf.cpp +++ b/src/system/boot/loader/elf.cpp @@ -126,9 +126,9 @@ load_elf_symbol_table(int fd, preloaded_image *image) status = B_ERROR; goto error1; } - + // find symbol table in section headers - + for (int32 i = 0; i < elfHeader.e_shnum; i++) { if (sectionHeaders[i].sh_type == SHT_SYMTAB) { stringHeader = §ionHeaders[sectionHeaders[i].sh_link]; @@ -275,7 +275,7 @@ elf_load_image(int fd, preloaded_image *image) } else continue; - region->start = ROUNDOWN(header.p_vaddr, B_PAGE_SIZE); + region->start = ROUNDDOWN(header.p_vaddr, B_PAGE_SIZE); region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); region->delta = -region->start; diff --git a/src/system/boot/loader/kernel_args.cpp b/src/system/boot/loader/kernel_args.cpp index f04003d8ce..96ec8125a8 100644 --- a/src/system/boot/loader/kernel_args.cpp +++ b/src/system/boot/loader/kernel_args.cpp @@ -62,7 +62,7 @@ insert_address_range(addr_range* ranges, uint32* _numRanges, uint32 maxRanges, { uint32 numRanges = *_numRanges; - start = ROUNDOWN(start, B_PAGE_SIZE); + start = ROUNDDOWN(start, B_PAGE_SIZE); size = ROUNDUP(size, B_PAGE_SIZE); addr_t end = start + size; @@ -141,7 +141,7 @@ remove_address_range(addr_range* ranges, uint32* _numRanges, uint32 maxRanges, uint32 numRanges = *_numRanges; addr_t end = ROUNDUP(start + size, B_PAGE_SIZE); - start = ROUNDOWN(start, B_PAGE_SIZE); + start = ROUNDDOWN(start, B_PAGE_SIZE); for (uint32 i = 0; i < numRanges; i++) { addr_t rangeStart = ranges[i].start; diff --git a/src/system/boot/platform/bios_ia32/mmu.cpp b/src/system/boot/platform/bios_ia32/mmu.cpp index b3b9fd9207..677e9759f0 100644 --- a/src/system/boot/platform/bios_ia32/mmu.cpp +++ b/src/system/boot/platform/bios_ia32/mmu.cpp @@ -632,7 +632,7 @@ mmu_init(void) extMemoryBlock[i].base_addr = ROUNDUP(extMemoryBlock[i].base_addr, B_PAGE_SIZE); extMemoryBlock[i].length - = ROUNDOWN(extMemoryBlock[i].length, B_PAGE_SIZE); + = ROUNDDOWN(extMemoryBlock[i].length, B_PAGE_SIZE); // we ignore all memory beyond 4 GB if (extMemoryBlock[i].base_addr > 0xffffffffULL) diff --git a/src/system/boot/platform/openfirmware/arch/ppc/mmu.cpp b/src/system/boot/platform/openfirmware/arch/ppc/mmu.cpp index 82e5eaf6cd..262e2c18b2 100644 --- a/src/system/boot/platform/openfirmware/arch/ppc/mmu.cpp +++ b/src/system/boot/platform/openfirmware/arch/ppc/mmu.cpp @@ -57,7 +57,7 @@ static status_t insert_memory_range(addr_range *ranges, uint32 &numRanges, uint32 maxRanges, const void *_start, uint32 _size) { - addr_t start = ROUNDOWN(addr_t(_start), B_PAGE_SIZE); + addr_t start = ROUNDDOWN(addr_t(_start), B_PAGE_SIZE); addr_t end = ROUNDUP(addr_t(_start) + _size, B_PAGE_SIZE); addr_t size = end - start; if (size == 0) @@ -133,7 +133,7 @@ static status_t remove_memory_range(addr_range *ranges, uint32 &numRanges, uint32 maxRanges, const void *_start, uint32 _size) { - addr_t start = ROUNDOWN(addr_t(_start), B_PAGE_SIZE); + addr_t start = ROUNDDOWN(addr_t(_start), B_PAGE_SIZE); addr_t end = ROUNDUP(addr_t(_start) + _size, B_PAGE_SIZE); for (uint32 i = 0; i < numRanges; i++) { diff --git a/src/system/boot/platform/u-boot/mmu.cpp b/src/system/boot/platform/u-boot/mmu.cpp index 1550f72a79..91bbb46ff6 100644 --- a/src/system/boot/platform/u-boot/mmu.cpp +++ b/src/system/boot/platform/u-boot/mmu.cpp @@ -618,7 +618,7 @@ mmu_init(void) extMemoryBlock[i].base_addr = ROUNDUP(extMemoryBlock[i].base_addr, B_PAGE_SIZE); extMemoryBlock[i].length - = ROUNDOWN(extMemoryBlock[i].length, B_PAGE_SIZE); + = ROUNDDOWN(extMemoryBlock[i].length, B_PAGE_SIZE); // we ignore all memory beyond 4 GB if (extMemoryBlock[i].base_addr > 0xffffffffULL) diff --git a/src/system/kernel/arch/m68k/arch_cpu.cpp b/src/system/kernel/arch/m68k/arch_cpu.cpp index 3a90acced2..235c5aabaf 100644 --- a/src/system/kernel/arch/m68k/arch_cpu.cpp +++ b/src/system/kernel/arch/m68k/arch_cpu.cpp @@ -30,7 +30,7 @@ int arch_fpu_type; int arch_mmu_type; int arch_platform; -status_t +status_t arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) { // enable FPU @@ -44,7 +44,7 @@ arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) } -status_t +status_t arch_cpu_init_percpu(kernel_args *args, int curr_cpu) { //detect_cpu(curr_cpu); @@ -102,7 +102,7 @@ arch_cpu_init_post_modules(kernel_args *args) } -void +void arch_cpu_sync_icache(void *address, size_t len) { cpu_ops.flush_icache((addr_t)address, len); @@ -125,7 +125,7 @@ arch_cpu_memory_write_barrier(void) } -void +void arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) { int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE; @@ -139,11 +139,11 @@ arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) } -void +void arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) { int i; - + cpu_ops.flush_insn_pipeline(); for (i = 0; i < num_pages; i++) { cpu_ops.flush_atc_addr(pages[i]); @@ -153,7 +153,7 @@ arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) } -void +void arch_cpu_global_TLB_invalidate(void) { cpu_ops.flush_insn_pipeline(); @@ -162,7 +162,7 @@ arch_cpu_global_TLB_invalidate(void) } -void +void arch_cpu_user_TLB_invalidate(void) { cpu_ops.flush_insn_pipeline(); @@ -179,6 +179,7 @@ arch_cpu_user_memcpy(void *to, const void *from, size_t size, char *s = (char *)from; addr_t oldFaultHandler = *faultHandler; +// TODO: This doesn't work correctly with gcc 4 anymore! if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) goto error; @@ -200,7 +201,7 @@ error: * \param to Pointer to the destination C-string. * \param from Pointer to the source C-string. * \param size Size in bytes of the string buffer pointed to by \a to. - * + * * \return strlen(\a from). */ @@ -210,12 +211,13 @@ arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHand int from_length = 0; addr_t oldFaultHandler = *faultHandler; +// TODO: This doesn't work correctly with gcc 4 anymore! if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) goto error; if (size > 0) { to[--size] = '\0'; - // copy + // copy for ( ; size; size--, from_length++, to++, from++) { if ((*to = *from) == '\0') break; @@ -240,6 +242,7 @@ arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) char *xs = (char *)s; addr_t oldFaultHandler = *faultHandler; +// TODO: This doesn't work correctly with gcc 4 anymore! if (m68k_set_fault_handler(faultHandler, (addr_t)&&error)) goto error; @@ -289,6 +292,7 @@ arch_cpu_idle(void) bool m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler) { +// TODO: This doesn't work correctly with gcc 4 anymore! *handlerLocation = handler; return false; } diff --git a/src/system/kernel/arch/m68k/arch_debug.cpp b/src/system/kernel/arch/m68k/arch_debug.cpp index c0d3b77e47..7b50744226 100644 --- a/src/system/kernel/arch/m68k/arch_debug.cpp +++ b/src/system/kernel/arch/m68k/arch_debug.cpp @@ -65,25 +65,14 @@ get_current_stack_frame() static status_t get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) { - struct thread *thread = thread_get_current_thread(); - addr_t oldFaultHandler = thread->fault_handler; + stack_frame frame; + if (debug_memcpy(&frame, (void*)framePointer, sizeof(frame)) != B_OK) + return B_BAD_ADDRESS; - // set fault handler, so that we can safely access user stacks - if (thread) { - if (m68k_set_fault_handler(&thread->fault_handler, (addr_t)&&error)) - goto error; - } + *ip = frame.return_address; + *next = (addr_t)frame.previous; - *ip = ((struct stack_frame *)framePointer)->return_address; - *next = (addr_t)((struct stack_frame *)framePointer)->previous; - - if (thread) - thread->fault_handler = oldFaultHandler; return B_OK; - -error: - thread->fault_handler = oldFaultHandler; - return B_BAD_ADDRESS; } @@ -367,6 +356,22 @@ arch_debug_get_interrupt_pc(bool* _isSyscall) } +void +arch_debug_unset_current_thread(void) +{ + // TODO: Implement! +} + + +void +arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer, + void (*function)(void*), void* parameter) +{ + // TODO: Implement! Most likely in assembly. + longjmp(jumpBuffer, 1); +} + + bool arch_is_debug_variable_defined(const char* variableName) { diff --git a/src/system/kernel/arch/m68k/arch_vm_translation_map_impl.cpp b/src/system/kernel/arch/m68k/arch_vm_translation_map_impl.cpp index 8c15140d71..1d1a16e4eb 100644 --- a/src/system/kernel/arch/m68k/arch_vm_translation_map_impl.cpp +++ b/src/system/kernel/arch/m68k/arch_vm_translation_map_impl.cpp @@ -651,7 +651,7 @@ unmap_tmap(vm_translation_map *map, addr_t start, addr_t end) status_t status; int index; - start = ROUNDOWN(start, B_PAGE_SIZE); + start = ROUNDDOWN(start, B_PAGE_SIZE); end = ROUNDUP(end, B_PAGE_SIZE); TRACE(("unmap_tmap: asked to free pages 0x%lx to 0x%lx\n", start, end)); @@ -873,7 +873,7 @@ protect_tmap(vm_translation_map *map, addr_t start, addr_t end, uint32 attribute status_t status; int index; - start = ROUNDOWN(start, B_PAGE_SIZE); + start = ROUNDDOWN(start, B_PAGE_SIZE); end = ROUNDUP(end, B_PAGE_SIZE); TRACE(("protect_tmap: pages 0x%lx to 0x%lx, attributes %lx\n", start, end, attributes)); @@ -1511,3 +1511,11 @@ m68k_vm_translation_map_early_map(kernel_args *args, addr_t va, addr_t pa, return B_OK; } + +bool +arch_vm_translation_map_is_kernel_page_accessible(addr_t virtualAddress, + uint32 protection) +{ + // TODO: Implement! + return false; +} diff --git a/src/system/kernel/arch/ppc/arch_cpu.cpp b/src/system/kernel/arch/ppc/arch_cpu.cpp index bcb6d2cf93..6dbb82ab56 100644 --- a/src/system/kernel/arch/ppc/arch_cpu.cpp +++ b/src/system/kernel/arch/ppc/arch_cpu.cpp @@ -16,7 +16,7 @@ static bool sHasTlbia; -status_t +status_t arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) { // enable FPU @@ -65,7 +65,7 @@ arch_cpu_init_post_modules(kernel_args *args) #define CACHELINE 32 -void +void arch_cpu_sync_icache(void *address, size_t len) { int l, off; @@ -109,7 +109,7 @@ arch_cpu_memory_write_barrier(void) } -void +void arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) { asm volatile("sync"); @@ -124,7 +124,7 @@ arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) } -void +void arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) { int i; @@ -140,7 +140,7 @@ arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) } -void +void arch_cpu_global_TLB_invalidate(void) { if (sHasTlbia) { @@ -156,7 +156,7 @@ arch_cpu_global_TLB_invalidate(void) tlbie(address); eieio(); ppc_sync(); - + address += B_PAGE_SIZE; } tlbsync(); @@ -165,7 +165,7 @@ arch_cpu_global_TLB_invalidate(void) } -void +void arch_cpu_user_TLB_invalidate(void) { arch_cpu_global_TLB_invalidate(); @@ -180,6 +180,7 @@ arch_cpu_user_memcpy(void *to, const void *from, size_t size, char *s = (char *)from; addr_t oldFaultHandler = *faultHandler; +// TODO: This doesn't work correctly with gcc 4 anymore! if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) goto error; @@ -201,7 +202,7 @@ error: * \param to Pointer to the destination C-string. * \param from Pointer to the source C-string. * \param size Size in bytes of the string buffer pointed to by \a to. - * + * * \return strlen(\a from). */ @@ -211,12 +212,13 @@ arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHand int from_length = 0; addr_t oldFaultHandler = *faultHandler; +// TODO: This doesn't work correctly with gcc 4 anymore! if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) goto error; if (size > 0) { to[--size] = '\0'; - // copy + // copy for ( ; size; size--, from_length++, to++, from++) { if ((*to = *from) == '\0') break; @@ -241,6 +243,7 @@ arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) char *xs = (char *)s; addr_t oldFaultHandler = *faultHandler; +// TODO: This doesn't work correctly with gcc 4 anymore! if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) goto error; @@ -286,6 +289,7 @@ arch_cpu_idle(void) bool ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler) { +// TODO: This doesn't work correctly with gcc 4 anymore! *handlerLocation = handler; return false; } diff --git a/src/system/kernel/arch/ppc/arch_debug.cpp b/src/system/kernel/arch/ppc/arch_debug.cpp index 1d382bd863..94a2f21b1e 100644 --- a/src/system/kernel/arch/ppc/arch_debug.cpp +++ b/src/system/kernel/arch/ppc/arch_debug.cpp @@ -64,25 +64,14 @@ get_current_stack_frame() static status_t get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) { - struct thread *thread = thread_get_current_thread(); - addr_t oldFaultHandler = thread->fault_handler; + stack_frame frame; + if (debug_memcpy(&frame, (void*)framePointer, sizeof(frame)) != B_OK) + return B_BAD_ADDRESS; - // set fault handler, so that we can safely access user stacks - if (thread) { - if (ppc_set_fault_handler(&thread->fault_handler, (addr_t)&&error)) - goto error; - } + *ip = frame.return_address; + *next = (addr_t)frame.previous; - *ip = ((struct stack_frame *)framePointer)->return_address; - *next = (addr_t)((struct stack_frame *)framePointer)->previous; - - if (thread) - thread->fault_handler = oldFaultHandler; return B_OK; - -error: - thread->fault_handler = oldFaultHandler; - return B_BAD_ADDRESS; } @@ -303,6 +292,22 @@ arch_debug_get_interrupt_pc(bool* _isSyscall) } +void +arch_debug_unset_current_thread(void) +{ + // TODO: Implement! +} + + +void +arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer, + void (*function)(void*), void* parameter) +{ + // TODO: Implement! Most likely in assembly. + longjmp(jumpBuffer, 1); +} + + bool arch_is_debug_variable_defined(const char* variableName) { diff --git a/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp b/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp index a5c49aedaa..72b6d9b5db 100644 --- a/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp +++ b/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp @@ -330,7 +330,7 @@ unmap_tmap(vm_translation_map *map, addr_t start, addr_t end) { page_table_entry *entry; - start = ROUNDOWN(start, B_PAGE_SIZE); + start = ROUNDDOWN(start, B_PAGE_SIZE); end = ROUNDUP(end, B_PAGE_SIZE); // dprintf("vm_translation_map.unmap_tmap: start 0x%lx, end 0x%lx\n", start, end); @@ -678,8 +678,8 @@ ppc_map_address_range(addr_t virtualAddress, addr_t physicalAddress, size_t size) { addr_t virtualEnd = ROUNDUP(virtualAddress + size, B_PAGE_SIZE); - virtualAddress = ROUNDOWN(virtualAddress, B_PAGE_SIZE); - physicalAddress = ROUNDOWN(physicalAddress, B_PAGE_SIZE); + virtualAddress = ROUNDDOWN(virtualAddress, B_PAGE_SIZE); + physicalAddress = ROUNDDOWN(physicalAddress, B_PAGE_SIZE); vm_address_space *addressSpace = vm_kernel_address_space(); @@ -701,7 +701,7 @@ void ppc_unmap_address_range(addr_t virtualAddress, size_t size) { addr_t virtualEnd = ROUNDUP(virtualAddress + size, B_PAGE_SIZE); - virtualAddress = ROUNDOWN(virtualAddress, B_PAGE_SIZE); + virtualAddress = ROUNDDOWN(virtualAddress, B_PAGE_SIZE); vm_address_space *addressSpace = vm_kernel_address_space(); @@ -713,7 +713,7 @@ ppc_unmap_address_range(addr_t virtualAddress, size_t size) status_t ppc_remap_address_range(addr_t *_virtualAddress, size_t size, bool unmap) { - addr_t virtualAddress = ROUNDOWN(*_virtualAddress, B_PAGE_SIZE); + addr_t virtualAddress = ROUNDDOWN(*_virtualAddress, B_PAGE_SIZE); size = ROUNDUP(*_virtualAddress + size - virtualAddress, B_PAGE_SIZE); vm_address_space *addressSpace = vm_kernel_address_space(); @@ -746,3 +746,11 @@ ppc_remap_address_range(addr_t *_virtualAddress, size_t size, bool unmap) return B_OK; } + +bool +arch_vm_translation_map_is_kernel_page_accessible(addr_t virtualAddress, + uint32 protection) +{ + // TODO: Implement! + return false; +} diff --git a/src/system/kernel/arch/x86/arch_debug.cpp b/src/system/kernel/arch/x86/arch_debug.cpp index facc378050..5b479c2a56 100644 --- a/src/system/kernel/arch/x86/arch_debug.cpp +++ b/src/system/kernel/arch/x86/arch_debug.cpp @@ -56,26 +56,36 @@ already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 ebp) } +/*! Safe to be called only from outside the debugger. +*/ static status_t -get_next_frame(addr_t ebp, addr_t *_next, addr_t *_eip) +get_next_frame_no_debugger(addr_t ebp, addr_t *_next, addr_t *_eip) { - // set fault handler, so that we can safely access user stacks - addr_t oldFaultHandler = thread_get_current_thread()->fault_handler; - thread_get_current_thread()->fault_handler = (addr_t)&&error; - // Fake goto to trick the compiler not to optimize the code at the label - // away. - if (ebp == 0) - goto error; + // TODO: Do this more efficiently in assembly. + stack_frame frame; + if (user_memcpy(&frame, (void*)ebp, sizeof(frame)) != B_OK) + return B_BAD_ADDRESS; - *_eip = ((struct stack_frame *)ebp)->return_address; - *_next = (addr_t)((struct stack_frame *)ebp)->previous; + *_eip = frame.return_address; + *_next = (addr_t)frame.previous; - thread_get_current_thread()->fault_handler = oldFaultHandler; return B_OK; +} -error: - thread_get_current_thread()->fault_handler = oldFaultHandler; - return B_BAD_ADDRESS; + +/*! Safe to be called only from inside the debugger. +*/ +static status_t +get_next_frame_debugger(addr_t ebp, addr_t *_next, addr_t *_eip) +{ + stack_frame frame; + if (debug_memcpy(&frame, (void*)ebp, sizeof(frame)) != B_OK) + return B_BAD_ADDRESS; + + *_eip = frame.return_address; + *_next = (addr_t)frame.previous; + + return B_OK; } @@ -285,8 +295,10 @@ print_stack_frame(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp, kprintf(" + 0x%04lx\n", eip - baseAddress); } else { vm_area *area = NULL; - if (thread->team->address_space != NULL) + if (thread != NULL && thread->team != NULL + && thread->team->address_space != NULL) { area = vm_area_lookup(thread->team->address_space, eip); + } if (area != NULL) { kprintf("%ld:%s@%p + %#lx\n", area->id, area->name, (void*)area->base, eip - area->base); @@ -358,6 +370,7 @@ setup_for_thread(char *arg, struct thread **_thread, uint32 *_ebp, *_thread = thread; } + static bool is_double_fault_stack_address(int32 cpu, addr_t address) { @@ -564,7 +577,7 @@ stack_trace(int argc, char **argv) } else { addr_t eip, nextEbp; - if (get_next_frame(ebp, &nextEbp, &eip) != B_OK) { + if (get_next_frame_debugger(ebp, &nextEbp, &eip) != B_OK) { kprintf("%08lx -- read fault\n", ebp); break; } @@ -723,7 +736,7 @@ show_call(int argc, char **argv) } else { addr_t eip, nextEbp; - if (get_next_frame(ebp, &nextEbp, &eip) != B_OK) { + if (get_next_frame_debugger(ebp, &nextEbp, &eip) != B_OK) { kprintf("%08lx -- read fault\n", ebp); break; } @@ -894,7 +907,7 @@ arch_debug_contains_call(struct thread *thread, const char *symbol, } else { addr_t eip, nextEbp; - if (get_next_frame(ebp, &nextEbp, &eip) != B_OK + if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK || eip == 0 || ebp == 0) break; @@ -964,7 +977,7 @@ arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, skipFrames = 0; } } else { - if (get_next_frame(ebp, &nextEbp, &eip) != B_OK) + if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK) break; } @@ -1000,6 +1013,16 @@ arch_debug_get_interrupt_pc(bool* _isSyscall) } +/*! Sets the current thread to \c NULL. + Invoked in the kernel debugger only. +*/ +void +arch_debug_unset_current_thread(void) +{ + write_dr3(NULL); +} + + bool arch_is_debug_variable_defined(const char* variableName) { diff --git a/src/system/kernel/arch/x86/arch_int.cpp b/src/system/kernel/arch/x86/arch_int.cpp index 607f1a8a0d..955df6cb0b 100644 --- a/src/system/kernel/arch/x86/arch_int.cpp +++ b/src/system/kernel/arch/x86/arch_int.cpp @@ -204,22 +204,27 @@ set_gate(desc_table *gate_addr, addr_t addr, int type, int dpl) /*! Initializes the descriptor for interrupt vector \a n in the IDT of the - boot CPU to an interrupt-gate descriptor with the given procedure address. + specified CPU to an interrupt-gate descriptor with the given procedure + address. + For CPUs other than the boot CPU it must not be called before + arch_int_init_post_vm(). */ static void -set_interrupt_gate(int n, void (*addr)()) +set_interrupt_gate(int32 cpu, int n, void (*addr)()) { - set_gate(&sIDTs[0][n], (addr_t)addr, 14, DPL_KERNEL); + set_gate(&sIDTs[cpu][n], (addr_t)addr, 14, DPL_KERNEL); } /*! Initializes the descriptor for interrupt vector \a n in the IDT of the - boot CPU to an trap-gate descriptor with the given procedure address. + specified CPU to an trap-gate descriptor with the given procedure address. + For CPUs other than the boot CPU it must not be called before + arch_int_init_post_vm(). */ static void -set_trap_gate(int n, void (*addr)()) +set_trap_gate(int32 cpu, int n, void (*addr)()) { - set_gate(&sIDTs[0][n], (unsigned int)addr, 15, DPL_USER); + set_gate(&sIDTs[cpu][n], (unsigned int)addr, 15, DPL_USER); } @@ -851,27 +856,74 @@ x86_double_fault_exception(struct iframe* frame) frame->edi = tss->edi; frame->flags = tss->eflags; + // Use a special handler for page faults which avoids the triple fault + // pitfalls. + set_interrupt_gate(cpu, 14, &trap14_double_fault); + debug_double_fault(cpu); } +void +x86_page_fault_exception_double_fault(struct iframe* frame) +{ + uint32 cr2; + asm("movl %%cr2, %0" : "=r" (cr2)); + + // Only if this CPU has a fault handler, we're allowed to be here. + cpu_ent& cpu = gCPU[x86_double_fault_get_cpu()]; + addr_t faultHandler = cpu.fault_handler; + if (faultHandler != 0) { + debug_set_page_fault_info(cr2, frame->eip, + (frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0); + frame->eip = faultHandler; + frame->ebp = cpu.fault_handler_stack_pointer; + return; + } + + // No fault handler. This is bad. Since we originally came from a double + // fault, we don't try to reenter the kernel debugger. Instead we just + // print the info we've got and enter an infinite loop. + kprintf("Page fault in double fault debugger without fault handler! " + "Touching address %p from eip %p. Entering infinite loop...\n", + (void*)cr2, (void*)frame->eip); + + while (true); +} + + static void page_fault_exception(struct iframe* frame) { struct thread *thread = thread_get_current_thread(); - bool kernelDebugger = debug_debugger_running(); - unsigned int cr2; + uint32 cr2; addr_t newip; asm("movl %%cr2, %0" : "=r" (cr2)); - if (kernelDebugger) { - // if this thread has a fault handler, we're allowed to be here - if (thread && thread->fault_handler != 0) { - debug_set_page_fault_info(cr2, frame->eip, - (frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0); - frame->eip = thread->fault_handler; - return; + if (debug_debugger_running()) { + // If this CPU or this thread has a fault handler, we're allowed to be + // here. + if (thread != NULL) { + cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; + if (cpu->fault_handler != 0) { + debug_set_page_fault_info(cr2, frame->eip, + (frame->error_code & 0x2) != 0 + ? DEBUG_PAGE_FAULT_WRITE : 0); + frame->eip = cpu->fault_handler; + frame->ebp = cpu->fault_handler_stack_pointer; + return; + } + + if (thread->fault_handler != 0) { + kprintf("ERROR: thread::fault_handler used in kernel " + "debugger!\n"); + debug_set_page_fault_info(cr2, frame->eip, + (frame->error_code & 0x2) != 0 + ? DEBUG_PAGE_FAULT_WRITE : 0); + frame->eip = thread->fault_handler; + return; + } } // otherwise, not really @@ -886,8 +938,16 @@ page_fault_exception(struct iframe* frame) // disabled, which in most cases is a bug. We should add some thread // flag allowing to explicitly indicate that this handling is desired. if (thread && thread->fault_handler != 0) { - frame->eip = thread->fault_handler; - return; + if (frame->eip != thread->fault_handler) { + frame->eip = thread->fault_handler; + return; + } + + // The fault happened at the fault handler address. This is a + // certain infinite loop. + panic("page fault, interrupts disabled, fault handler loop. " + "Touching address %p from eip %p\n", (void*)cr2, + (void*)frame->eip); } // If we are not running the kernel startup the page fault was not @@ -971,60 +1031,60 @@ arch_int_init(struct kernel_args *args) // setup the standard programmable interrupt controller pic_init(); - set_interrupt_gate(0, &trap0); - set_interrupt_gate(1, &trap1); - set_interrupt_gate(2, &trap2); - set_trap_gate(3, &trap3); - set_interrupt_gate(4, &trap4); - set_interrupt_gate(5, &trap5); - set_interrupt_gate(6, &trap6); - set_interrupt_gate(7, &trap7); + set_interrupt_gate(0, 0, &trap0); + set_interrupt_gate(0, 1, &trap1); + set_interrupt_gate(0, 2, &trap2); + set_trap_gate(0, 3, &trap3); + set_interrupt_gate(0, 4, &trap4); + set_interrupt_gate(0, 5, &trap5); + set_interrupt_gate(0, 6, &trap6); + set_interrupt_gate(0, 7, &trap7); // trap8 (double fault) is set in arch_cpu.c - set_interrupt_gate(9, &trap9); - set_interrupt_gate(10, &trap10); - set_interrupt_gate(11, &trap11); - set_interrupt_gate(12, &trap12); - set_interrupt_gate(13, &trap13); - set_interrupt_gate(14, &trap14); -// set_interrupt_gate(15, &trap15); - set_interrupt_gate(16, &trap16); - set_interrupt_gate(17, &trap17); - set_interrupt_gate(18, &trap18); - set_interrupt_gate(19, &trap19); + set_interrupt_gate(0, 9, &trap9); + set_interrupt_gate(0, 10, &trap10); + set_interrupt_gate(0, 11, &trap11); + set_interrupt_gate(0, 12, &trap12); + set_interrupt_gate(0, 13, &trap13); + set_interrupt_gate(0, 14, &trap14); +// set_interrupt_gate(0, 15, &trap15); + set_interrupt_gate(0, 16, &trap16); + set_interrupt_gate(0, 17, &trap17); + set_interrupt_gate(0, 18, &trap18); + set_interrupt_gate(0, 19, &trap19); - set_interrupt_gate(32, &trap32); - set_interrupt_gate(33, &trap33); - set_interrupt_gate(34, &trap34); - set_interrupt_gate(35, &trap35); - set_interrupt_gate(36, &trap36); - set_interrupt_gate(37, &trap37); - set_interrupt_gate(38, &trap38); - set_interrupt_gate(39, &trap39); - set_interrupt_gate(40, &trap40); - set_interrupt_gate(41, &trap41); - set_interrupt_gate(42, &trap42); - set_interrupt_gate(43, &trap43); - set_interrupt_gate(44, &trap44); - set_interrupt_gate(45, &trap45); - set_interrupt_gate(46, &trap46); - set_interrupt_gate(47, &trap47); - set_interrupt_gate(48, &trap48); - set_interrupt_gate(49, &trap49); - set_interrupt_gate(50, &trap50); - set_interrupt_gate(51, &trap51); - set_interrupt_gate(52, &trap52); - set_interrupt_gate(53, &trap53); - set_interrupt_gate(54, &trap54); - set_interrupt_gate(55, &trap55); + set_interrupt_gate(0, 32, &trap32); + set_interrupt_gate(0, 33, &trap33); + set_interrupt_gate(0, 34, &trap34); + set_interrupt_gate(0, 35, &trap35); + set_interrupt_gate(0, 36, &trap36); + set_interrupt_gate(0, 37, &trap37); + set_interrupt_gate(0, 38, &trap38); + set_interrupt_gate(0, 39, &trap39); + set_interrupt_gate(0, 40, &trap40); + set_interrupt_gate(0, 41, &trap41); + set_interrupt_gate(0, 42, &trap42); + set_interrupt_gate(0, 43, &trap43); + set_interrupt_gate(0, 44, &trap44); + set_interrupt_gate(0, 45, &trap45); + set_interrupt_gate(0, 46, &trap46); + set_interrupt_gate(0, 47, &trap47); + set_interrupt_gate(0, 48, &trap48); + set_interrupt_gate(0, 49, &trap49); + set_interrupt_gate(0, 50, &trap50); + set_interrupt_gate(0, 51, &trap51); + set_interrupt_gate(0, 52, &trap52); + set_interrupt_gate(0, 53, &trap53); + set_interrupt_gate(0, 54, &trap54); + set_interrupt_gate(0, 55, &trap55); - set_trap_gate(98, &trap98); // for performance testing only - set_trap_gate(99, &trap99); + set_trap_gate(0, 98, &trap98); // for performance testing only + set_trap_gate(0, 99, &trap99); - set_interrupt_gate(251, &trap251); - set_interrupt_gate(252, &trap252); - set_interrupt_gate(253, &trap253); - set_interrupt_gate(254, &trap254); - set_interrupt_gate(255, &trap255); + set_interrupt_gate(0, 251, &trap251); + set_interrupt_gate(0, 252, &trap252); + set_interrupt_gate(0, 253, &trap253); + set_interrupt_gate(0, 254, &trap254); + set_interrupt_gate(0, 255, &trap255); // init interrupt handler table table = gInterruptHandlerTable; diff --git a/src/system/kernel/arch/x86/arch_interrupts.S b/src/system/kernel/arch/x86/arch_interrupts.S index 59f6869928..99547ce7f1 100644 --- a/src/system/kernel/arch/x86/arch_interrupts.S +++ b/src/system/kernel/arch/x86/arch_interrupts.S @@ -213,6 +213,7 @@ FUNCTION(double_fault): POP_IFRAME_AND_RETURN() FUNCTION_END(double_fault) + TRAP(trap9, 9) TRAP_ERRC(trap10, 10) TRAP_ERRC(trap11, 11) @@ -257,6 +258,23 @@ TRAP(trap254, 254) TRAP(trap255, 255) +.align 8; +FUNCTION(trap14_double_fault): + pushl $14 + pushl $-1 + pushl $-1 + + PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER) + + movl %esp, %ebp // frame pointer is the iframe + + pushl %ebp + call x86_page_fault_exception_double_fault + + POP_IFRAME_AND_RETURN() +FUNCTION_END(trap14_double_fault) + + .align 16 STATIC_FUNCTION(int_bottom): PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER) diff --git a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp index 3c4a8fae22..cabe6a66d9 100644 --- a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp +++ b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp @@ -375,7 +375,7 @@ unmap_tmap(vm_translation_map *map, addr_t start, addr_t end) page_directory_entry *pd = map->arch_data->pgdir_virt; int index; - start = ROUNDOWN(start, B_PAGE_SIZE); + start = ROUNDDOWN(start, B_PAGE_SIZE); end = ROUNDUP(end, B_PAGE_SIZE); TRACE(("unmap_tmap: asked to free pages 0x%lx to 0x%lx\n", start, end)); @@ -515,7 +515,7 @@ protect_tmap(vm_translation_map *map, addr_t start, addr_t end, page_directory_entry *pd = map->arch_data->pgdir_virt; int index; - start = ROUNDOWN(start, B_PAGE_SIZE); + start = ROUNDDOWN(start, B_PAGE_SIZE); end = ROUNDUP(end, B_PAGE_SIZE); TRACE(("protect_tmap: pages 0x%lx to 0x%lx, attributes %lx\n", start, end, @@ -934,3 +934,75 @@ arch_vm_translation_map_early_map(kernel_args *args, addr_t va, addr_t pa, return B_OK; } + +/*! Verifies that the page at the given virtual address can be accessed in the + current context. + + This function is invoked in the kernel debugger. Paranoid checking is in + order. + + \param virtualAddress The virtual address to be checked. + \param protection The area protection for which to check. Valid is a bitwise + or of one or more of \c B_KERNEL_READ_AREA or \c B_KERNEL_WRITE_AREA. + \return \c true, if the address can be accessed in all ways specified by + \a protection, \c false otherwise. +*/ +bool +arch_vm_translation_map_is_kernel_page_accessible(addr_t virtualAddress, + uint32 protection) +{ + // We only trust the kernel team's page directory. So switch to it first. + // Always set it to make sure the TLBs don't contain obsolete data. + addr_t physicalPageDirectory; + read_cr3(physicalPageDirectory); + write_cr3(sKernelPhysicalPageDirectory); + + // get the page directory entry for the address + page_directory_entry pageDirectoryEntry; + uint32 index = VADDR_TO_PDENT(virtualAddress); + + if (physicalPageDirectory == (addr_t)sKernelPhysicalPageDirectory) { + pageDirectoryEntry = sKernelVirtualPageDirectory[index]; + } else { + // map the original page directory and get the entry + void* handle; + addr_t virtualPageDirectory; + status_t error = gPhysicalPageMapper->GetPageDebug( + physicalPageDirectory, &virtualPageDirectory, &handle); + if (error == B_OK) { + pageDirectoryEntry + = ((page_directory_entry*)virtualPageDirectory)[index]; + gPhysicalPageMapper->PutPageDebug(virtualPageDirectory, + handle); + } else + pageDirectoryEntry.present = 0; + } + + // map the page table and get the entry + page_table_entry pageTableEntry; + index = VADDR_TO_PTENT(virtualAddress); + + if (pageDirectoryEntry.present != 0) { + void* handle; + addr_t virtualPageTable; + status_t error = gPhysicalPageMapper->GetPageDebug( + ADDR_REVERSE_SHIFT(pageDirectoryEntry.addr), &virtualPageTable, + &handle); + if (error == B_OK) { + pageTableEntry = ((page_table_entry*)virtualPageTable)[index]; + gPhysicalPageMapper->PutPageDebug(virtualPageTable, handle); + } else + pageTableEntry.present = 0; + } else + pageTableEntry.present = 0; + + // switch back to the original page directory + if (physicalPageDirectory != (addr_t)sKernelPhysicalPageDirectory) + write_cr3(physicalPageDirectory); + + if (pageTableEntry.present == 0) + return false; + + // present means kernel-readable, so check for writable + return (protection & B_KERNEL_WRITE_AREA) == 0 || pageTableEntry.rw != 0; +} diff --git a/src/system/kernel/arch/x86/arch_x86.S b/src/system/kernel/arch/x86/arch_x86.S index ef722dd977..d812515731 100644 --- a/src/system/kernel/arch/x86/arch_x86.S +++ b/src/system/kernel/arch/x86/arch_x86.S @@ -11,6 +11,7 @@ #include +#include "asm_offsets.h" #include "syscall_numbers.h" @@ -285,3 +286,51 @@ FUNCTION(arch_cpu_user_memcpy): ret FUNCTION_END(arch_cpu_user_memcpy) + +/*! \fn void arch_debug_call_with_fault_handler(cpu_ent* cpu, + jmp_buf jumpBuffer, void (*function)(void*), void* parameter) + + Called by debug_call_with_fault_handler() to do the dirty work of setting + the fault handler and calling the function. If the function causes a page + fault, the arch_debug_call_with_fault_handler() calls longjmp() with the + given \a jumpBuffer. Otherwise it returns normally. + + debug_call_with_fault_handler() has already saved the CPU's fault_handler + and fault_handler_stack_pointer and will reset them later, so + arch_debug_call_with_fault_handler() doesn't need to care about it. + + \param cpu The \c cpu_ent for the current CPU. + \param jumpBuffer Buffer to be used for longjmp(). + \param function The function to be called. + \param parameter The parameter to be passed to the function to be called. +*/ +FUNCTION(arch_debug_call_with_fault_handler): + push %ebp + movl %esp, %ebp + + // Set fault handler address, and fault handler stack pointer address. We + // don't need to save the previous values, since that's done by the caller. + movl 8(%ebp), %eax // cpu to %eax + lea 1f, %edx + movl %edx, CPU_ENT_fault_handler(%eax) + movl %ebp, CPU_ENT_fault_handler_stack_pointer(%eax) + + // call the function + movl 20(%ebp), %eax // parameter + push %eax + movl 16(%ebp), %eax // function + call *%eax + + // regular return + movl %ebp, %esp + pop %ebp + ret + + // fault -- return via longjmp(jumpBuffer, 1) +1: + movl %ebp, %esp // restore %esp + pushl $1 + movl 12(%ebp), %eax // jumpBuffer + pushl %eax + call longjmp +FUNCTION_END(arch_debug_call_with_fault_handler) diff --git a/src/system/kernel/arch/x86/asm_offsets.cpp b/src/system/kernel/arch/x86/asm_offsets.cpp index 2f82ee6134..da2d6bf326 100644 --- a/src/system/kernel/arch/x86/asm_offsets.cpp +++ b/src/system/kernel/arch/x86/asm_offsets.cpp @@ -8,7 +8,9 @@ // a header file with macro definitions, that can be included from assembler // code. + #include +#include #include #include @@ -26,6 +28,10 @@ void dummy() { + // struct cpu_ent + DEFINE_OFFSET_MACRO(CPU_ENT, cpu_ent, fault_handler); + DEFINE_OFFSET_MACRO(CPU_ENT, cpu_ent, fault_handler_stack_pointer); + // struct thread DEFINE_OFFSET_MACRO(THREAD, thread, kernel_time); DEFINE_OFFSET_MACRO(THREAD, thread, user_time); diff --git a/src/system/kernel/arch/x86/interrupts.h b/src/system/kernel/arch/x86/interrupts.h index fe064f1baf..1766fa7c6d 100644 --- a/src/system/kernel/arch/x86/interrupts.h +++ b/src/system/kernel/arch/x86/interrupts.h @@ -23,6 +23,7 @@ void trap44();void trap45();void trap46();void trap47();void trap48();void trap4 void trap50();void trap51();void trap52();void trap53();void trap54();void trap55(); void double_fault(); // int 8 +void trap14_double_fault(); void trap98(); void trap99(); diff --git a/src/system/kernel/arch/x86/x86_physical_page_mapper.h b/src/system/kernel/arch/x86/x86_physical_page_mapper.h index 31409d37dc..903618ffce 100644 --- a/src/system/kernel/arch/x86/x86_physical_page_mapper.h +++ b/src/system/kernel/arch/x86/x86_physical_page_mapper.h @@ -36,6 +36,12 @@ public: virtual page_table_entry* InterruptGetPageTableAt( addr_t physicalAddress) = 0; + + virtual status_t GetPageDebug(addr_t physicalAddress, + addr_t* _virtualAddress, + void** _handle) = 0; + virtual status_t PutPageDebug(addr_t virtualAddress, + void* _handle) = 0; }; extern PhysicalPageMapper* gPhysicalPageMapper; diff --git a/src/system/kernel/arch/x86/x86_physical_page_mapper_large_memory.cpp b/src/system/kernel/arch/x86/x86_physical_page_mapper_large_memory.cpp index 043ef6ad0a..216f64e2ef 100644 --- a/src/system/kernel/arch/x86/x86_physical_page_mapper_large_memory.cpp +++ b/src/system/kernel/arch/x86/x86_physical_page_mapper_large_memory.cpp @@ -166,9 +166,9 @@ public: inline status_t PutPageCurrentCPU(addr_t virtualAddress, void* handle); - inline status_t GetPageDebug(addr_t physicalAddress, + virtual status_t GetPageDebug(addr_t physicalAddress, addr_t* virtualAddress, void** handle); - inline status_t PutPageDebug(addr_t virtualAddress, + virtual status_t PutPageDebug(addr_t virtualAddress, void* handle); status_t GetSlot(bool canWait, diff --git a/src/system/kernel/debug/debug.cpp b/src/system/kernel/debug/debug.cpp index be9fb96414..ef1d430823 100644 --- a/src/system/kernel/debug/debug.cpp +++ b/src/system/kernel/debug/debug.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,13 @@ #include "debug_variables.h" +struct debug_memcpy_parameters { + void* to; + const void* from; + size_t size; +}; + + static const char* const kKDLPrompt = "kdebug> "; extern "C" int kgets(char* buffer, int length); @@ -678,19 +686,42 @@ kernel_debugger_loop(const char* message, int32 cpu) kprintf("Welcome to Kernel Debugging Land...\n"); - if (struct thread* thread = thread_get_current_thread()) { - // set a few temporary debug variables + // Set a few temporary debug variables and print on which CPU and in which + // thread we are running. + set_debug_variable("_cpu", sDebuggerOnCPU); + + struct thread* thread = thread_get_current_thread(); + if (thread == NULL) { + kprintf("Running on CPU %ld\n", sDebuggerOnCPU); + } else if (!debug_is_kernel_memory_accessible((addr_t)thread, + sizeof(struct thread), B_KERNEL_READ_AREA)) { + kprintf("Running on CPU %ld\n", sDebuggerOnCPU); + kprintf("Current thread pointer is %p, which is an address we " + "can't read from.\n", thread); + arch_debug_unset_current_thread(); + } else { set_debug_variable("_thread", (uint64)(addr_t)thread); set_debug_variable("_threadID", thread->id); - set_debug_variable("_team", (uint64)(addr_t)thread->team); - if (thread->team != NULL) - set_debug_variable("_teamID", thread->team->id); - set_debug_variable("_cpu", sDebuggerOnCPU); - kprintf("Thread %ld \"%s\" running on CPU %ld\n", thread->id, + kprintf("Thread %ld \"%.64s\" running on CPU %ld\n", thread->id, thread->name, sDebuggerOnCPU); - } else - kprintf("Running on CPU %ld\n", sDebuggerOnCPU); + + if (thread->cpu != gCPU + cpu) { + kprintf("The thread's CPU pointer is %p, but should be %p.\n", + thread->cpu, gCPU + cpu); + arch_debug_unset_current_thread(); + } else if (thread->team != NULL) { + if (debug_is_kernel_memory_accessible((addr_t)thread->team, + sizeof(struct team), B_KERNEL_READ_AREA)) { + set_debug_variable("_team", (uint64)(addr_t)thread->team); + set_debug_variable("_teamID", thread->team->id); + } else { + kprintf("The thread's team pointer is %p, which is an " + "address we can't read from.\n", thread->team); + arch_debug_unset_current_thread(); + } + } + } int32 continuableLine = -1; // Index of the previous command line, if the command returned @@ -1140,6 +1171,14 @@ err1: } +static void +debug_memcpy_trampoline(void* _parameters) +{ + debug_memcpy_parameters* parameters = (debug_memcpy_parameters*)_parameters; + memcpy(parameters->to, parameters->from, parameters->size); +} + + void call_modules_hook(bool enter) { @@ -1410,6 +1449,90 @@ debug_emergency_key_pressed(char key) } +/*! Verifies that the complete given memory range is accessible in the current + context. + + Invoked in the kernel debugger only. + + \param address The start address of the memory range to be checked. + \param size The size of the memory range to be checked. + \param protection The area protection for which to check. Valid is a bitwise + or of one or more of \c B_KERNEL_READ_AREA or \c B_KERNEL_WRITE_AREA. + \return \c true, if the complete memory range can be accessed in all ways + specified by \a protection, \c false otherwise. +*/ +bool +debug_is_kernel_memory_accessible(addr_t address, size_t size, + uint32 protection) +{ + addr_t endAddress = ROUNDUP(address + size, B_PAGE_SIZE); + address = ROUNDDOWN(address, B_PAGE_SIZE); + + if (!IS_KERNEL_ADDRESS(address) || endAddress < address) + return false; + + for (; address < endAddress; address += B_PAGE_SIZE) { + if (!arch_vm_translation_map_is_kernel_page_accessible(address, + protection)) { + return false; + } + } + + return true; +} + + +/*! Calls a function in a setjmp() + fault handler context. + May only be used in the kernel debugger. + + \param jumpBuffer Buffer to be used for setjmp()/longjmp(). + \param function The function to be called. + \param parameter The parameter to be passed to the function to be called. + \return + - \c 0, when the function executed without causing a page fault or + calling longjmp(). + - \c 1, when the function caused a page fault. + - Any other value the function passes to longjmp(). +*/ +int +debug_call_with_fault_handler(jmp_buf jumpBuffer, void (*function)(void*), + void* parameter) +{ + // save current fault handler + cpu_ent* cpu = gCPU + sDebuggerOnCPU; + addr_t oldFaultHandler = cpu->fault_handler; + addr_t oldFaultHandlerStackPointer = cpu->fault_handler_stack_pointer; + + int result = setjmp(jumpBuffer); + if (result == 0) { + arch_debug_call_with_fault_handler(cpu, jumpBuffer, function, + parameter); + } + + // restore old fault handler + cpu->fault_handler = oldFaultHandler; + cpu->fault_handler_stack_pointer = oldFaultHandlerStackPointer; + + return result; +} + + +/*! Similar to user_memcpy(), but can only be invoked from within the kernel + debugger (and must not be used outside). +*/ +status_t +debug_memcpy(void* to, const void* from, size_t size) +{ + debug_memcpy_parameters parameters = {to, from, size}; + + if (debug_call_with_fault_handler(gCPU[sDebuggerOnCPU].fault_jump_buffer, + &debug_memcpy_trampoline, ¶meters) != 0) { + return B_BAD_ADDRESS; + } + return B_OK; +} + + // #pragma mark - public API diff --git a/src/system/kernel/debug/debug_commands.cpp b/src/system/kernel/debug/debug_commands.cpp index b0fd9be35d..a31ae6a85e 100644 --- a/src/system/kernel/debug/debug_commands.cpp +++ b/src/system/kernel/debug/debug_commands.cpp @@ -29,6 +29,14 @@ #define INVOKE_COMMAND_ERROR 2 +struct invoke_command_parameters { + debugger_command* command; + int argc; + char** argv; + int result; +}; + + static const int32 kMaxInvokeCommandDepth = 5; static const int32 kOutputBufferSize = 1024; @@ -153,6 +161,16 @@ static PipeDebugOutputFilter sPipeOutputFilters[ MAX_DEBUGGER_COMMAND_PIPE_LENGTH - 1]; +static void +invoke_command_trampoline(void* _parameters) +{ + invoke_command_parameters* parameters + = (invoke_command_parameters*)_parameters; + parameters->result = parameters->command->func(parameters->argc, + parameters->argv); +} + + static int invoke_pipe_segment(debugger_command_pipe* pipe, int32 index, char* argument) { @@ -268,9 +286,6 @@ invoke_debugger_command(struct debugger_command *command, int argc, char** argv) return 0; } - struct thread* thread = thread_get_current_thread(); - addr_t oldFaultHandler = thread->fault_handler; - // replace argv[0] with the actual command name argv[0] = (char *)command->name; @@ -284,26 +299,18 @@ invoke_debugger_command(struct debugger_command *command, int argc, char** argv) sInCommand = true; - switch (setjmp(sInvokeCommandEnv[sInvokeCommandLevel++])) { + invoke_command_parameters parameters; + parameters.command = command; + parameters.argc = argc; + parameters.argv = argv; + + switch (debug_call_with_fault_handler( + sInvokeCommandEnv[sInvokeCommandLevel++], + &invoke_command_trampoline, ¶meters)) { case 0: - int result; - thread->fault_handler = (addr_t)&&error; - // Fake goto to trick the compiler not to optimize the code at the - // label away. - if (!thread) - goto error; - - result = command->func(argc, argv); - - thread->fault_handler = oldFaultHandler; sInvokeCommandLevel--; sInCommand = false; - return result; - - error: - // jump to INVOKE_COMMAND_FAULT case, cleaning up the stack - longjmp(sInvokeCommandEnv[--sInvokeCommandLevel], - INVOKE_COMMAND_FAULT); + return parameters.result; case INVOKE_COMMAND_FAULT: { @@ -324,7 +331,6 @@ invoke_debugger_command(struct debugger_command *command, int argc, char** argv) break; } - thread->fault_handler = oldFaultHandler; sInCommand = false; return B_KDEBUG_ERROR; } diff --git a/src/system/kernel/debug/debug_parser.cpp b/src/system/kernel/debug/debug_parser.cpp index f31e7504ef..14c68b621e 100644 --- a/src/system/kernel/debug/debug_parser.cpp +++ b/src/system/kernel/debug/debug_parser.cpp @@ -4,6 +4,7 @@ * Distributed under the terms of the MIT License. */ + #include #include @@ -695,7 +696,7 @@ ExpressionParser::_ParseExpression(bool expectAssignment) break; } - if (user_memcpy(address, &buffer, size) != B_OK) { + if (debug_memcpy(address, &buffer, size) != B_OK) { snprintf(sTempBuffer, sizeof(sTempBuffer), "failed to write to address %p", address); parse_exception(sTempBuffer, position); @@ -1032,7 +1033,7 @@ ExpressionParser::_ParseDereference(void** _address, uint32* _size) // read bytes from address into a tempory buffer uint64 buffer; - if (user_memcpy(&buffer, address, size) != B_OK) { + if (debug_memcpy(&buffer, address, size) != B_OK) { snprintf(sTempBuffer, sizeof(sTempBuffer), "failed to dereference address %p", address); parse_exception(sTempBuffer, starPosition); diff --git a/src/system/kernel/debug/gdb.cpp b/src/system/kernel/debug/gdb.cpp index 887c7d4671..9c90434faa 100644 --- a/src/system/kernel/debug/gdb.cpp +++ b/src/system/kernel/debug/gdb.cpp @@ -290,8 +290,8 @@ gdb_parse_command(void) // We cannot directly access the requested memory // for gdb may be trying to access an stray pointer // We copy the memory to a safe buffer using - // the bulletproof user_memcpy(). - if (user_memcpy(sSafeMemory, (char*)address, len) < 0) + // the bulletproof debug_memcpy(). + if (debug_memcpy(sSafeMemory, (char*)address, len) < 0) gdb_reply("E02"); else gdb_memreply(sSafeMemory, len); diff --git a/src/system/kernel/elf.cpp b/src/system/kernel/elf.cpp index e23dc4b59d..2b26cefeaf 100644 --- a/src/system/kernel/elf.cpp +++ b/src/system/kernel/elf.cpp @@ -1786,7 +1786,7 @@ elf_load_user_image(const char *path, struct team *team, int flags, if (programHeaders[i].p_type != PT_LOAD) continue; - regionAddress = (char *)ROUNDOWN(programHeaders[i].p_vaddr, + regionAddress = (char *)ROUNDDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); if (programHeaders[i].p_flags & PF_WRITE) { // rw/data segment @@ -1803,7 +1803,7 @@ elf_load_user_image(const char *path, struct team *team, int flags, id = vm_map_file(team->id, regionName, (void **)®ionAddress, B_EXACT_ADDRESS, fileUpperBound, B_READ_AREA | B_WRITE_AREA, REGION_PRIVATE_MAP, false, - fd, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); + fd, ROUNDDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); if (id < B_OK) { dprintf("error mapping file data: %s!\n", strerror(id)); status = B_NOT_AN_EXECUTABLE; @@ -1851,7 +1851,7 @@ elf_load_user_image(const char *path, struct team *team, int flags, id = vm_map_file(team->id, regionName, (void **)®ionAddress, B_EXACT_ADDRESS, segmentSize, B_READ_AREA | B_EXECUTE_AREA, REGION_PRIVATE_MAP, false, - fd, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); + fd, ROUNDDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); if (id < B_OK) { dprintf("error mapping file text: %s!\n", strerror(id)); status = B_NOT_AN_EXECUTABLE; @@ -2070,7 +2070,7 @@ load_kernel_add_on(const char *path) continue; } - region->start = (addr_t)reservedAddress + ROUNDOWN( + region->start = (addr_t)reservedAddress + ROUNDDOWN( programHeaders[i].p_vaddr, B_PAGE_SIZE); region->size = ROUNDUP(programHeaders[i].p_memsz + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); @@ -2083,7 +2083,7 @@ load_kernel_add_on(const char *path) status = B_NOT_AN_EXECUTABLE; goto error4; } - region->delta = -ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); + region->delta = -ROUNDDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); TRACE(("elf_load_kspace: created area \"%s\" at %p\n", regionName, (void *)region->start)); diff --git a/src/system/kernel/slab/Slab.cpp b/src/system/kernel/slab/Slab.cpp index 629cb08d2a..05e466bbd0 100644 --- a/src/system/kernel/slab/Slab.cpp +++ b/src/system/kernel/slab/Slab.cpp @@ -686,7 +686,7 @@ object_cache_init(object_cache *cache, const char *name, size_t objectSize, static void object_cache_commit_slab(object_cache *cache, slab *slab) { - void *pages = (void *)ROUNDOWN((addr_t)slab->pages, B_PAGE_SIZE); + void *pages = (void *)ROUNDDOWN((addr_t)slab->pages, B_PAGE_SIZE); if (create_area(cache->name, &pages, B_EXACT_ADDRESS, cache->slab_size, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA) < B_OK) panic("failed to create_area()"); diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index eb5cb5c9c9..c0c289be14 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -63,9 +64,6 @@ # define FTRACE(x) ; #endif -#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) -#define ROUNDOWN(a, b) (((a) / (b)) * (b)) - class AddressSpaceReadLocker { public: @@ -2266,7 +2264,7 @@ _vm_map_file(team_id team, const char* name, void** _address, TRACE(("_vm_map_file(fd = %d, offset = %Ld, size = %lu, mapping %ld)\n", fd, offset, size, mapping)); - offset = ROUNDOWN(offset, B_PAGE_SIZE); + offset = ROUNDDOWN(offset, B_PAGE_SIZE); size = PAGE_ALIGN(size); if (mapping == REGION_NO_PRIVATE_MAP) @@ -3332,7 +3330,7 @@ display_mem(int argc, char** argv) kprintf("NOTE: number of bytes has been cut to page size\n"); } - address = ROUNDOWN(address, B_PAGE_SIZE); + address = ROUNDDOWN(address, B_PAGE_SIZE); if (vm_get_physical_page_debug(address, ©Address, &physicalPageHandle) != B_OK) { @@ -3351,7 +3349,7 @@ display_mem(int argc, char** argv) // string mode for (i = 0; true; i++) { char c; - if (user_memcpy(&c, (char*)copyAddress + i, 1) != B_OK + if (debug_memcpy(&c, (char*)copyAddress + i, 1) != B_OK || c == '\0') break; @@ -3382,7 +3380,7 @@ display_mem(int argc, char** argv) for (j = 0; j < displayed; j++) { char c; - if (user_memcpy(&c, (char*)copyAddress + i * itemSize + j, + if (debug_memcpy(&c, (char*)copyAddress + i * itemSize + j, 1) != B_OK) { displayed = j; break; @@ -3400,7 +3398,7 @@ display_mem(int argc, char** argv) kprintf(" "); } - if (user_memcpy(&value, (uint8*)copyAddress + i * itemSize, + if (debug_memcpy(&value, (uint8*)copyAddress + i * itemSize, itemSize) != B_OK) { kprintf("read fault"); break; @@ -3426,7 +3424,7 @@ display_mem(int argc, char** argv) } if (physical) { - copyAddress = ROUNDOWN(copyAddress, B_PAGE_SIZE); + copyAddress = ROUNDDOWN(copyAddress, B_PAGE_SIZE); vm_put_physical_page_debug(copyAddress, physicalPageHandle); } return 0; @@ -4033,7 +4031,7 @@ create_preloaded_image_areas(struct preloaded_image* image) memcpy(name, fileName, length); strcpy(name + length, "_text"); - address = (void*)ROUNDOWN(image->text_region.start, B_PAGE_SIZE); + address = (void*)ROUNDDOWN(image->text_region.start, B_PAGE_SIZE); image->text_region.id = create_area(name, &address, B_EXACT_ADDRESS, PAGE_ALIGN(image->text_region.size), B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); @@ -4041,7 +4039,7 @@ create_preloaded_image_areas(struct preloaded_image* image) // ELF initialization code strcpy(name + length, "_data"); - address = (void*)ROUNDOWN(image->data_region.start, B_PAGE_SIZE); + address = (void*)ROUNDDOWN(image->data_region.start, B_PAGE_SIZE); image->data_region.id = create_area(name, &address, B_EXACT_ADDRESS, PAGE_ALIGN(image->data_region.size), B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); @@ -4304,11 +4302,11 @@ vm_init(kernel_args* args) // allocate areas to represent stuff that already exists - address = (void*)ROUNDOWN(heapBase, B_PAGE_SIZE); + address = (void*)ROUNDDOWN(heapBase, B_PAGE_SIZE); create_area("kernel heap", &address, B_EXACT_ADDRESS, heapSize, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); - address = (void*)ROUNDOWN(slabInitialBase, B_PAGE_SIZE); + address = (void*)ROUNDDOWN(slabInitialBase, B_PAGE_SIZE); create_area("initial slab space", &address, B_EXACT_ADDRESS, slabInitialSize, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); @@ -4431,7 +4429,7 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser, TPF(PageFaultStart(address, isWrite, isUser, faultAddress)); - addr_t pageAddress = ROUNDOWN(address, B_PAGE_SIZE); + addr_t pageAddress = ROUNDDOWN(address, B_PAGE_SIZE); vm_address_space* addressSpace = NULL; status_t status = B_OK; @@ -4829,7 +4827,7 @@ vm_soft_fault(vm_address_space* addressSpace, addr_t originalAddress, PageFaultContext context(addressSpace, isWrite); - addr_t address = ROUNDOWN(originalAddress, B_PAGE_SIZE); + addr_t address = ROUNDDOWN(originalAddress, B_PAGE_SIZE); status_t status = B_OK; atomic_add(&addressSpace->fault_count, 1); @@ -5407,7 +5405,7 @@ lock_memory_etc(team_id team, void* address, size_t numBytes, uint32 flags) struct vm_translation_map* map; addr_t unalignedBase = (addr_t)address; addr_t end = unalignedBase + numBytes; - addr_t base = ROUNDOWN(unalignedBase, B_PAGE_SIZE); + addr_t base = ROUNDDOWN(unalignedBase, B_PAGE_SIZE); bool isUser = IS_USER_ADDRESS(address); bool needsLocking = true; @@ -5513,7 +5511,7 @@ unlock_memory_etc(team_id team, void* address, size_t numBytes, uint32 flags) struct vm_translation_map* map; addr_t unalignedBase = (addr_t)address; addr_t end = unalignedBase + numBytes; - addr_t base = ROUNDOWN(unalignedBase, B_PAGE_SIZE); + addr_t base = ROUNDDOWN(unalignedBase, B_PAGE_SIZE); bool needsLocking = true; if (IS_USER_ADDRESS(address)) {