Ticket #6310: x86_64_kernel_sources.finished.patch
File x86_64_kernel_sources.finished.patch, 256.0 KB (added by , 13 years ago) |
---|
-
src/system/kernel/arch/x86_64/arch_elf.cpp
1 /* 2 * Copyright 2004-2010, Haiku Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Copyright 2002, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 #include <KernelExport.h> 10 11 #include <elf_priv.h> 12 #include <arch/elf.h> 13 14 15 //#define TRACE_ARCH_ELF 16 #ifdef TRACE_ARCH_ELF 17 # define TRACE(x) dprintf x 18 #else 19 # define TRACE(x) ; 20 #endif 21 22 23 #ifdef TRACE_ARCH_ELF 24 static const char *kRelocations[] = { 25 "R_X86_64_NONE", 26 "R_X86_64_32", /* add symbol value */ 27 "R_X86_64_PC32", /* add PC relative symbol value */ 28 "R_X86_64_GOT32", /* add PC relative GOT offset */ 29 "R_X86_64_PLT32", /* add PC relative PLT offset */ 30 "R_X86_64_COPY", /* copy data from shared object */ 31 "R_X86_64_GLOB_DAT", /* set GOT entry to data address */ 32 "R_X86_64_JMP_SLOT", /* set GOT entry to code address */ 33 "R_X86_64_RELATIVE", /* add load address of shared object */ 34 "R_X86_64_GOTOFF", /* add GOT relative symbol address */ 35 }; 36 #endif 37 38 39 static bool 40 is_in_image(struct elf_image_info *image, addr_t address) 41 { 42 return (address >= image->text_region.start 43 && address < image->text_region.start + image->text_region.size) 44 || (address >= image->data_region.start 45 && address < image->data_region.start + image->data_region.size); 46 } 47 48 49 int arch_elf_relocate_rel(struct elf_image_info *image, 50 struct elf_image_info *resolveImage, struct Elf64_Rel *rel, int relLength) 51 { 52 addr_t S; 53 addr_t A; 54 addr_t P; 55 addr_t finalAddress; 56 addr_t *resolveAddress; 57 int i; 58 59 S = A = P = 0; 60 61 for (i = 0; i * (int)sizeof(struct Elf64_Rel) < relLength; i++) { 62 TRACE(("looking at rel type %s, offset 0x%lx\n", 63 kRelocations[ELF64_R_TYPE(rel[i].r_info)], rel[i].r_offset)); 64 65 // calc S 66 switch (ELF64_R_TYPE(rel[i].r_info)) { 67 case R_X86_64_64: 68 case R_X86_64_PC32: 69 case R_X86_64_GLOB_DAT: 70 case R_X86_64_JMP_SLOT: 71 case R_X86_64_GOTOFF: 72 { 73 struct Elf64_Sym *symbol; 74 status_t status; 75 76 symbol = SYMBOL64(image, ELF64_R_SYM(rel[i].r_info)); 77 /* TODO: Add resolove symbol for 64bit elf */ 78 // status = elf_resolve_symbol(image, symbol, resolveImage, &S); 79 80 if (status < B_OK) 81 return status; 82 TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol))); 83 } 84 } 85 // calc A 86 switch (ELF64_R_TYPE(rel[i].r_info)) { 87 case R_X86_64_64: 88 case R_X86_64_PC32: 89 case R_X86_64_GOT32: 90 case R_X86_64_PLT32: 91 case R_X86_64_RELATIVE: 92 case R_X86_64_GOTOFF: 93 A = *(addr_t *)(image->text_region.delta + rel[i].r_offset); 94 TRACE(("A %p\n", (void *)A)); 95 break; 96 } 97 // calc P 98 switch (ELF64_R_TYPE(rel[i].r_info)) { 99 case R_X86_64_PC32: 100 case R_X86_64_GOT32: 101 case R_X86_64_PLT32: 102 P = image->text_region.delta + rel[i].r_offset; 103 TRACE(("P %p\n", (void *)P)); 104 break; 105 } 106 107 switch (ELF64_R_TYPE(rel[i].r_info)) { 108 case R_X86_64_NONE: 109 continue; 110 case R_X86_64_64: 111 finalAddress = S + A; 112 break; 113 case R_X86_64_PC32: 114 finalAddress = S + A - P; 115 break; 116 case R_X86_64_RELATIVE: 117 // B + A; 118 finalAddress = image->text_region.delta + A; 119 break; 120 case R_X86_64_JMP_SLOT: 121 case R_X86_64_GLOB_DAT: 122 finalAddress = S; 123 break; 124 125 default: 126 dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n", 127 ELF64_R_TYPE(rel[i].r_info)); 128 return B_BAD_DATA; 129 } 130 131 resolveAddress = (addr_t *)(image->text_region.delta + rel[i].r_offset); 132 133 if (!is_in_image(image, (addr_t)resolveAddress)) { 134 dprintf("arch_elf_relocate_rel: invalid offset %#lx\n", 135 rel[i].r_offset); 136 return B_BAD_ADDRESS; 137 } 138 139 *resolveAddress = finalAddress; 140 TRACE(("-> offset %#lx = %#lx\n", 141 (image->text_region.delta + rel[i].r_offset), finalAddress)); 142 } 143 144 return B_NO_ERROR; 145 } 146 147 148 int 149 arch_elf_relocate_rela(struct elf_image_info *image, 150 struct elf_image_info *resolveImage, struct Elf64_Rela *rela, int relLength) 151 { 152 addr_t S; 153 addr_t A; 154 addr_t P; 155 addr_t finalAddress; 156 addr_t *resolveAddress; 157 int i; 158 159 S = A = P = 0; 160 161 for (i = 0; i * (int)sizeof(struct Elf64_Rela) < relLength; i++) { 162 TRACE(("looking at rel type %s, offset 0x%lx\n", 163 kRelocations[ELF64_R_TYPE(rela[i].r_info)], rela[i].r_offset)); 164 165 // calc S 166 switch (ELF64_R_TYPE(rela[i].r_info)) { 167 case R_X86_64_32: 168 case R_X86_64_PC32: 169 case R_X86_64_GLOB_DAT: 170 case R_X86_64_JMP_SLOT: 171 { 172 struct Elf64_Sym *symbol; 173 status_t status; 174 175 symbol = SYMBOL64(image, ELF64_R_SYM(rela[i].r_info)); 176 /* TODO: ADD RESOLVE SYMBOL FOR ELF64 */ 177 // status = boot_elf64_resolve_symbol(image, symbol, &S); 178 179 if (status < B_OK) 180 return status; 181 TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol))); 182 } 183 } 184 // calc A 185 switch (ELF64_R_TYPE(rela[i].r_info)) { 186 case R_X86_64_32: 187 case R_X86_64_PC32: 188 case R_X86_64_GOT32: 189 case R_X86_64_PLT32: 190 case R_X86_64_RELATIVE: 191 case R_X86_64_GOTOFF: 192 A = *(addr_t *)(image->text_region.delta + rela[i].r_offset); 193 TRACE(("A %p\n", (void *)A)); 194 break; 195 } 196 // calc P 197 switch (ELF64_R_TYPE(rela[i].r_info)) { 198 case R_X86_64_PC32: 199 case R_X86_64_GOT32: 200 case R_X86_64_PLT32: 201 P = image->text_region.delta + rela[i].r_offset; 202 TRACE(("P %p\n", (void *)P)); 203 break; 204 } 205 206 switch (ELF64_R_TYPE(rela[i].r_info)) { 207 case R_X86_64_NONE: 208 continue; 209 case R_X86_64_32: 210 finalAddress = S + A; 211 break; 212 case R_X86_64_PC32: 213 finalAddress = S + A - P; 214 break; 215 case R_X86_64_RELATIVE: 216 // B + A; 217 finalAddress = image->text_region.delta + A; 218 break; 219 case R_X86_64_JMP_SLOT: 220 case R_X86_64_GLOB_DAT: 221 finalAddress = S; 222 break; 223 224 default: 225 dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n", 226 ELF64_R_TYPE(rela[i].r_info)); 227 return B_BAD_DATA; 228 } 229 230 resolveAddress = (addr_t *)(image->text_region.delta + rela[i].r_offset); 231 232 *resolveAddress = finalAddress; 233 TRACE(("-> offset %#lx = %#lx\n", 234 (image->text_region.delta + rela[i].r_offset), finalAddress)); 235 } 236 237 return B_NO_ERROR; 238 } 239 240 241 int 242 arch_elf_relocate_rel(struct elf_image_info *image, 243 struct elf_image_info *resolveImage, struct Elf32_Rel *rel, int relLength) 244 { 245 addr_t S; 246 addr_t A; 247 addr_t P; 248 addr_t finalAddress; 249 addr_t *resolveAddress; 250 int i; 251 252 S = A = P = 0; 253 254 for (i = 0; i * (int)sizeof(struct Elf32_Rel) < relLength; i++) { 255 TRACE(("looking at rel type %s, offset 0x%lx\n", 256 kRelocations[ELF32_R_TYPE(rel[i].r_info)], rel[i].r_offset)); 257 258 // calc S 259 switch (ELF32_R_TYPE(rel[i].r_info)) { 260 case R_386_32: 261 case R_386_PC32: 262 case R_386_GLOB_DAT: 263 case R_386_JMP_SLOT: 264 case R_386_GOTOFF: 265 { 266 struct Elf32_Sym *symbol; 267 status_t status; 268 269 symbol = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); 270 271 status = elf_resolve_symbol(image, symbol, resolveImage, &S); 272 273 if (status < B_OK) 274 return status; 275 TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol))); 276 } 277 } 278 // calc A 279 switch (ELF32_R_TYPE(rel[i].r_info)) { 280 case R_386_32: 281 case R_386_PC32: 282 case R_386_GOT32: 283 case R_386_PLT32: 284 case R_386_RELATIVE: 285 case R_386_GOTOFF: 286 case R_386_GOTPC: 287 A = *(addr_t *)(image->text_region.delta + rel[i].r_offset); 288 TRACE(("A %p\n", (void *)A)); 289 break; 290 } 291 // calc P 292 switch (ELF32_R_TYPE(rel[i].r_info)) { 293 case R_386_PC32: 294 case R_386_GOT32: 295 case R_386_PLT32: 296 case R_386_GOTPC: 297 P = image->text_region.delta + rel[i].r_offset; 298 TRACE(("P %p\n", (void *)P)); 299 break; 300 } 301 302 switch (ELF32_R_TYPE(rel[i].r_info)) { 303 case R_386_NONE: 304 continue; 305 case R_386_32: 306 finalAddress = S + A; 307 break; 308 case R_386_PC32: 309 finalAddress = S + A - P; 310 break; 311 case R_386_RELATIVE: 312 // B + A; 313 finalAddress = image->text_region.delta + A; 314 break; 315 case R_386_JMP_SLOT: 316 case R_386_GLOB_DAT: 317 finalAddress = S; 318 break; 319 320 default: 321 dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n", 322 ELF32_R_TYPE(rel[i].r_info)); 323 return B_BAD_DATA; 324 } 325 326 resolveAddress = (addr_t *)(image->text_region.delta + rel[i].r_offset); 327 328 if (!is_in_image(image, (addr_t)resolveAddress)) { 329 dprintf("arch_elf_relocate_rel: invalid offset %#lx\n", 330 rel[i].r_offset); 331 return B_BAD_ADDRESS; 332 } 333 334 *resolveAddress = finalAddress; 335 TRACE(("-> offset %#lx = %#lx\n", 336 (image->text_region.delta + rel[i].r_offset), finalAddress)); 337 } 338 339 return B_NO_ERROR; 340 } 341 342 343 344 345 int 346 arch_elf_relocate_rela(struct elf_image_info *image, 347 struct elf_image_info *resolveImage, struct Elf32_Rela *rel, int relLength) 348 { 349 dprintf("arch_elf_relocate_rela: not supported on x86\n"); 350 return B_ERROR; 351 } -
src/system/kernel/arch/x86_64/arch_thread.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 9 * Distributed under the terms of the NewOS License. 10 */ 11 12 13 #include <arch/thread.h> 14 15 #include <string.h> 16 17 #include <arch/user_debugger.h> 18 #include <arch_cpu.h> 19 #include <cpu.h> 20 #include <debug.h> 21 #include <kernel.h> 22 #include <ksignal.h> 23 #include <int.h> 24 #include <team.h> 25 #include <thread.h> 26 #include <tls.h> 27 #include <tracing.h> 28 #include <vm/vm_types.h> 29 #include <vm/VMAddressSpace.h> 30 31 #include "paging/X86_64PagingStructures.h" 32 #include "paging/X86_64VMTranslationMap.h" 33 34 35 //#define TRACE_ARCH_THREAD 36 #ifdef TRACE_ARCH_THREAD 37 # define TRACE(x) dprintf x 38 #else 39 # define TRACE(x) ; 40 #endif 41 42 43 // from arch_interrupts.S 44 extern "C" void x86_64_stack_init(struct farcall *interrupt_stack_offset); 45 extern "C" void x86_64_restore_frame_from_syscall(struct iframe frame); 46 47 // from arch_cpu.cpp 48 extern void (*gX86SwapFPUFunc)(void *oldState, const void *newState); 49 50 //from arch_commpage.cpp 51 extern void x86_64_set_syscall_stack(addr_t stackTop); 52 53 static struct arch_thread sInitialState _ALIGNED(16); 54 // the fpu_state must be aligned on a 16 byte boundary, so that fxsave can use it 55 56 57 static inline void 58 set_fs_register(uint32 segment) 59 { 60 asm("mov %0,%%fs" :: "r" (segment)); 61 } 62 63 64 static void 65 set_tls_context(struct thread *thread) 66 { 67 int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT; 68 69 set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage); 70 set_fs_register((entry << 3) | DPL_USER); 71 } 72 73 74 static struct iframe * 75 find_previous_iframe(struct thread *thread, addr_t frame) 76 { 77 // iterate backwards through the stack frames, until we hit an iframe 78 while (frame >= thread->kernel_stack_base 79 && frame < thread->kernel_stack_top) { 80 addr_t previousFrame = *(addr_t*)frame; 81 if ((previousFrame & ~IFRAME_TYPE_MASK) == 0) { 82 if (previousFrame == 0) 83 return NULL; 84 return (struct iframe*)frame; 85 } 86 87 frame = previousFrame; 88 } 89 90 return NULL; 91 } 92 93 static struct iframe* 94 get_previous_iframe(struct iframe* frame) 95 { 96 if (frame == NULL) 97 return NULL; 98 99 return find_previous_iframe(thread_get_current_thread(), frame->rbp); 100 } 101 102 static struct iframe* 103 get_current_iframe(void) 104 { 105 return find_previous_iframe(thread_get_current_thread(), x86_64_read_rbp()); 106 } 107 108 struct iframe * 109 x86_64_get_current_iframe(void) 110 { 111 return get_current_iframe(); 112 } 113 114 115 /*! 116 \brief Returns the current thread's topmost (i.e. most recent) 117 userland->kernel transition iframe (usually the first one, save for 118 interrupts in signal handlers). 119 \return The iframe, or \c NULL, if there is no such iframe (e.g. when 120 the thread is a kernel thread). 121 */ 122 struct iframe * 123 x86_64_get_user_iframe(void) 124 { 125 struct iframe* frame = get_current_iframe(); 126 127 while (frame != NULL) { 128 if (IFRAME_IS_USER(frame)) 129 return frame; 130 frame = get_previous_iframe(frame); 131 } 132 133 return NULL; 134 } 135 136 137 uint64 138 x86_64_next_page_directory(struct thread *from, struct thread *to) 139 { 140 VMAddressSpace* toAddressSpace = to->team->address_space; 141 if (from->team->address_space == toAddressSpace) { 142 // don't change the pgdir, same address space 143 return 0; 144 } 145 146 if (toAddressSpace == NULL) 147 toAddressSpace = VMAddressSpace::Kernel(); 148 149 return static_cast<X86_64VMTranslationMap*>(toAddressSpace->TranslationMap()) 150 ->PagingStructures()->pgdir_phys; 151 } 152 153 static uint64 * 154 get_signal_stack(struct thread *thread, struct iframe *frame, int signal) 155 { 156 // use the alternate signal stack if we should and can 157 if (thread->signal_stack_enabled 158 && (thread->sig_action[signal - 1].sa_flags & SA_ONSTACK) != 0 159 && (frame->user_rsp < thread->signal_stack_base 160 || frame->user_rsp >= thread->signal_stack_base 161 + thread->signal_stack_size)) { 162 return (uint64 *)(thread->signal_stack_base 163 + thread->signal_stack_size); 164 } 165 166 return (uint64 *)frame->user_rsp; 167 } 168 169 status_t 170 arch_thread_init(struct kernel_args *args) 171 { 172 // save one global valid FPU state; it will be copied in the arch dependent 173 // part of each new thread 174 175 asm volatile ("clts; fninit; fnclex;"); 176 177 x86_64_fxsave(sInitialState.fpu_state); 178 179 return B_OK; 180 } 181 182 183 status_t 184 arch_team_init_team_struct(struct team *team, bool kernel) 185 { 186 return B_OK; 187 } 188 189 190 status_t 191 arch_thread_init_thread_struct(struct thread *thread) 192 { 193 // set up an initial state (stack & fpu) 194 memcpy(&thread->arch_info, &sInitialState, sizeof(struct arch_thread)); 195 return B_OK; 196 } 197 198 199 status_t 200 arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), 201 void (*entry_func)(void), void (*exit_func)(void)) 202 { 203 addr_t *kstack = (addr_t *)t->kernel_stack_base; 204 addr_t *kstack_top = (addr_t *)t->kernel_stack_top; 205 int i; 206 207 TRACE(("arch_thread_initialize_kthread_stack: kstack 0x%p, start_func 0x%p, entry_func 0x%p\n", 208 kstack, start_func, entry_func)); 209 210 // clear the kernel stack 211 #ifdef DEBUG_KERNEL_STACKS 212 # ifdef STACK_GROWS_DOWNWARDS 213 memset((void *)((addr_t)kstack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0, 214 KERNEL_STACK_SIZE); 215 # else 216 memset(kstack, 0, KERNEL_STACK_SIZE); 217 # endif 218 #else 219 memset(kstack, 0, KERNEL_STACK_SIZE); 220 #endif 221 222 // set the final return address to be thread_kthread_exit 223 kstack_top--; 224 *kstack_top = (addr_t)exit_func; 225 226 // set the return address to be the start of the first function 227 kstack_top--; 228 *kstack_top = (addr_t)start_func; 229 230 // set the return address to be the start of the entry (thread setup) 231 // function 232 kstack_top--; 233 *kstack_top = (addr_t)entry_func; 234 235 // simulate pushfl 236 // kstack_top--; 237 // *kstack_top = 0x00; // interrupts still disabled after the switch 238 239 // simulate initial popad 240 for (i = 0; i < 8; i++) { 241 kstack_top--; 242 *kstack_top = 0; 243 } 244 245 // save the stack position 246 t->arch_info.current_stack.rsp = kstack_top; 247 t->arch_info.current_stack.ss = (addr_t *)KERNEL_DATA_SEG; 248 249 return B_OK; 250 } 251 252 253 status_t 254 arch_thread_init_tls(struct thread *thread) 255 { 256 uint32 tls[TLS_USER_THREAD_SLOT + 1]; 257 258 thread->user_local_storage = thread->user_stack_base 259 + thread->user_stack_size; 260 261 // initialize default TLS fields 262 memset(tls, 0, sizeof(tls)); 263 tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage; 264 tls[TLS_THREAD_ID_SLOT] = thread->id; 265 tls[TLS_USER_THREAD_SLOT] = (addr_t)thread->user_thread; 266 267 return user_memcpy((void *)thread->user_local_storage, tls, sizeof(tls)); 268 } 269 270 271 void 272 arch_thread_context_switch(struct thread *from, struct thread *to) 273 { 274 x86_64_set_tss_and_kstack(to->kernel_stack_top); 275 x86_64_set_syscall_stack(to->kernel_stack_top); 276 277 // set TLS GDT entry to the current thread - since this action is 278 // dependent on the current CPU, we have to do it here 279 if (to->user_local_storage != 0) 280 set_tls_context(to); 281 282 struct cpu_ent* cpuData = to->cpu; 283 X86_64PagingStructures* activePagingStructures 284 = cpuData->arch.active_paging_structures; 285 VMAddressSpace* toAddressSpace = to->team->address_space; 286 287 X86_64PagingStructures* toPagingStructures; 288 if (toAddressSpace != NULL 289 && (toPagingStructures = static_cast<X86_64VMTranslationMap*>( 290 toAddressSpace->TranslationMap())->PagingStructures()) 291 != activePagingStructures) { 292 // update on which CPUs the address space is used 293 int cpu = cpuData->cpu_num; 294 atomic_and(&activePagingStructures->active_on_cpus, 295 ~((uint32)1 << cpu)); 296 atomic_or(&toPagingStructures->active_on_cpus, (uint32)1 << cpu); 297 298 // assign the new paging structures to the CPU 299 toPagingStructures->AddReference(); 300 cpuData->arch.active_paging_structures = toPagingStructures; 301 302 // set the page directory, if it changes 303 uint32 newPageDirectory = toPagingStructures->pgdir_phys; 304 if (newPageDirectory != activePagingStructures->pgdir_phys) 305 x86_64_swap_pgdir(newPageDirectory); 306 307 // This CPU no longer uses the previous paging structures. 308 activePagingStructures->RemoveReference(); 309 } 310 311 gX86SwapFPUFunc(from->arch_info.fpu_state, to->arch_info.fpu_state); 312 x86_64_context_switch(&from->arch_info, &to->arch_info); 313 } 314 315 316 void 317 arch_thread_dump_info(void *info) 318 { 319 struct arch_thread *at = (struct arch_thread *)info; 320 321 kprintf("\trsp: %p\n", at->current_stack.rsp); 322 kprintf("\tss: %p\n", at->current_stack.ss); 323 kprintf("\tfpu_state at %p\n", at->fpu_state); 324 } 325 326 327 status_t 328 arch_thread_enter_userspace(struct thread *thread, addr_t entry, void *arg1, void *arg2) 329 { 330 addr_t stackTop = thread->user_stack_base + thread->user_stack_size; 331 uint64 codeSize = (addr_t)x86_64_end_userspace_thread_exit 332 - (addr_t)x86_64_userspace_thread_exit; 333 uint64 args[3]; 334 335 TRACE(("arch_thread_enter_uspace: entry 0x%lx, args %p %p, ustack_top 0x%lx\n", 336 entry, args1, args2, stackTop)); 337 338 // copy the little stub that calls exit_thread() when the thread entry 339 // function returns, as well as the arguments of the entry function 340 stackTop -= codeSize; 341 342 if (user_memcpy((void *)stackTop, (const void *)&x86_64_userspace_thread_exit, codeSize) < B_OK) 343 return B_BAD_ADDRESS; 344 345 args[0] = stackTop; 346 args[1] = (uint64)arg1; 347 args[2] = (uint64)arg2; 348 stackTop -= sizeof(args); 349 350 if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK) 351 return B_BAD_ADDRESS; 352 353 thread_at_kernel_exit(); 354 // also disables interrupts 355 356 // install user breakpoints, if any 357 if ((thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED) != 0) 358 x86_64_init_user_debug_at_kernel_exit(NULL); 359 360 x86_64_set_tss_and_kstack(thread->kernel_stack_top); 361 362 // set the CPU dependent GDT entry for TLS 363 set_tls_context(thread); 364 365 x86_64_set_syscall_stack(thread->kernel_stack_top); 366 x86_64_enter_userspace(entry, stackTop); 367 368 return B_OK; 369 } 370 371 372 bool 373 arch_on_signal_stack(struct thread *thread) 374 { 375 struct iframe *frame = get_current_iframe(); 376 377 return frame->user_rsp >= thread->signal_stack_base 378 && frame->user_rsp < thread->signal_stack_base 379 + thread->signal_stack_size; 380 } 381 382 383 status_t 384 arch_setup_signal_frame(struct thread *thread, struct sigaction *action, int sig, int sigMask) 385 { 386 struct iframe *frame = get_current_iframe(); 387 if (!IFRAME_IS_USER(frame)) { 388 panic("arch_setup_signal_frame(): No user iframe!"); 389 return B_BAD_VALUE; 390 } 391 392 uint64 *signalCode; 393 addr_t *userRegs; 394 struct vregs regs; 395 uint64 buffer[6]; 396 status_t status; 397 398 // start stuffing stuff on the user stack 399 addr_t* userStack = get_signal_stack(thread, frame, sig); 400 401 // copy syscall restart info onto the user stack 402 userStack -= (sizeof(thread->syscall_restart.parameters) + 12 + 3) / 4; 403 uint32 threadFlags = atomic_and(&thread->flags, 404 ~(THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN)); 405 if (user_memcpy(userStack, &threadFlags, 4) < B_OK 406 || user_memcpy(userStack + 1, &frame->orig_rax, 4) < B_OK 407 || user_memcpy(userStack + 2, &frame->orig_rdx, 4) < B_OK) 408 return B_BAD_ADDRESS; 409 status = user_memcpy(userStack + 3, thread->syscall_restart.parameters, 410 sizeof(thread->syscall_restart.parameters)); 411 if (status < B_OK) 412 return status; 413 414 // store the saved regs onto the user stack 415 regs.rip = frame->rip; 416 regs.eflags = frame->flags; 417 regs.rax = frame->rax; 418 regs.rcx = frame->rcx; 419 regs.rdx = frame->rdx; 420 regs.rbp = frame->rbp; 421 regs.rsp = frame->rsp; 422 regs.r8 = frame->r8; 423 regs.r9 = frame->r9; 424 regs.r10 = frame->r10; 425 regs.r11 = frame->r11; 426 regs.r12 = frame->r12; 427 regs.r13 = frame->r13; 428 regs.r14 = frame->r14; 429 regs.r15 = frame->r15; 430 regs._reserved_1 = frame->user_rsp; 431 regs._reserved_2[0] = frame->rdi; 432 regs._reserved_2[1] = frame->rsi; 433 regs._reserved_2[2] = frame->rbx; 434 x86_64_fnsave((void *)(®s.xregs)); 435 436 userStack -= (sizeof(struct vregs) + 3) / 4; 437 userRegs = userStack; 438 status = user_memcpy(userRegs, ®s, sizeof(regs)); 439 if (status < B_OK) 440 return status; 441 442 // now store a code snippet on the stack 443 userStack -= ((uint64)x86_64_end_return_from_signal + 3 444 - (uint64)x86_64_return_from_signal) / 4; 445 signalCode = userStack; 446 status = user_memcpy(signalCode, (const void *)&x86_64_return_from_signal, 447 ((uint64)x86_64_end_return_from_signal 448 - (uint64)x86_64_return_from_signal)); 449 if (status < B_OK) 450 return status; 451 452 // now set up the final part 453 buffer[0] = (uint64)signalCode; // return address when sa_handler done 454 buffer[1] = (uint64)sig; // arguments to sa_handler 455 buffer[2] = (uint64)action->sa_userdata; 456 buffer[3] = (uint64)userRegs; 457 458 buffer[4] = sigMask; // Old signal mask to restore 459 buffer[5] = (uint64)userRegs; // Int frame + extra regs to restore 460 461 userStack -= sizeof(buffer) / 4; 462 463 status = user_memcpy(userStack, buffer, sizeof(buffer)); 464 if (status < B_OK) 465 return status; 466 467 frame->user_rsp = (uint64)userStack; 468 frame->rip = (uint64)action->sa_handler; 469 470 return B_OK; 471 } 472 473 474 int64 475 arch_restore_signal_frame(void) 476 { 477 struct thread *thread = thread_get_current_thread(); 478 struct iframe *frame = get_current_iframe(); 479 int32 signalMask; 480 uint64 *userStack; 481 struct vregs* regsPointer; 482 struct vregs regs; 483 484 TRACE(("### arch_restore_signal_frame: entry\n")); 485 486 userStack = (uint64 *)frame->user_rsp; 487 if (user_memcpy(&signalMask, &userStack[0], 4) < B_OK 488 || user_memcpy(®sPointer, &userStack[1], 4) < B_OK 489 || user_memcpy(®s, regsPointer, sizeof(vregs)) < B_OK) { 490 return B_BAD_ADDRESS; 491 } 492 493 uint64* syscallRestartInfo 494 = (uint64*)regsPointer + (sizeof(struct vregs) + 3) / 4; 495 uint32 threadFlags; 496 if (user_memcpy(&threadFlags, syscallRestartInfo, 4) < B_OK 497 || user_memcpy(&frame->orig_rax, syscallRestartInfo + 1, 4) < B_OK 498 || user_memcpy(&frame->orig_rdx, syscallRestartInfo + 2, 4) < B_OK 499 || user_memcpy(thread->syscall_restart.parameters, 500 syscallRestartInfo + 3, 501 sizeof(thread->syscall_restart.parameters)) < B_OK) { 502 return B_BAD_ADDRESS; 503 } 504 505 // set restart/64bit return value flags from previous syscall 506 atomic_and(&thread->flags, 507 ~(THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN)); 508 atomic_or(&thread->flags, threadFlags 509 & (THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN)); 510 511 // TODO: Verify that just restoring the old signal mask is right! Bash for 512 // instance changes the procmask in a signal handler. Those changes are 513 // lost the way we do it. 514 atomic_set(&thread->sig_block_mask, signalMask); 515 update_current_thread_signals_flag(); 516 517 frame->rip = regs.rip; 518 frame->flags = regs.eflags; 519 frame->rax = regs.rax; 520 frame->rcx = regs.rcx; 521 frame->rdx = regs.rdx; 522 frame->rbp = regs.rbp; 523 frame->rsp = regs.rsp; 524 frame->r8 = regs.r8; 525 frame->r9 = regs.r9; 526 frame->r10 = regs.r10; 527 frame->r11 = regs.r11; 528 frame->r12 = regs.r12; 529 frame->r13 = regs.r13; 530 frame->r14 = regs.r14; 531 frame->r15 = regs.r15; 532 frame->user_rsp = regs._reserved_1; 533 frame->rdi = regs._reserved_2[0]; 534 frame->rsi = regs._reserved_2[1]; 535 frame->rbx = regs._reserved_2[2]; 536 537 x86_64_frstor((void *)(®s.xregs)); 538 539 TRACE(("### arch_restore_signal_frame: exit\n")); 540 541 return (int64)frame->rax | ((int64)frame->rdx << 32); 542 } 543 544 545 void 546 arch_store_fork_frame(struct arch_fork_arg *arg) 547 { 548 struct iframe *frame = get_current_iframe(); 549 550 // we need to copy the threads current iframe 551 arg->iframe = *frame; 552 553 // we also want fork() to return 0 for the child 554 arg->iframe.rax = 0; 555 } 556 557 void 558 arch_restore_fork_frame(struct arch_fork_arg *arg) 559 { 560 struct thread *thread = thread_get_current_thread(); 561 562 disable_interrupts(); 563 564 x86_64_set_tss_and_kstack(thread->kernel_stack_top); 565 566 // set the CPU dependent GDT entry for TLS (set the current %fs register) 567 set_tls_context(thread); 568 569 x86_64_restore_frame_from_syscall(arg->iframe); 570 } 571 572 void 573 arch_syscall_64_bit_return_value(void) 574 { 575 struct thread* thread = thread_get_current_thread(); 576 atomic_or(&thread->flags, THREAD_FLAGS_64_BIT_SYSCALL_RETURN); 577 } -
src/system/kernel/arch/x86_64/arch_debug_console.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com 3 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de 4 * Copyright 2001, Rob Judd <judd@ob-wan.com> 5 * Copyright 2002, Marcus Overhagen <marcus@overhagen.de> 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 9 * Distributed under the terms of the NewOS License. 10 */ 11 12 #include "debugger_keymaps.h" 13 14 #include <KernelExport.h> 15 #include <driver_settings.h> 16 #include <int.h> 17 18 #include <arch/cpu.h> 19 #include <arch/debug_console.h> 20 #include <boot/stage2.h> 21 #include <debug.h> 22 23 #include <string.h> 24 #include <stdlib.h> 25 26 27 #define INT_PS2_KEYBOARD 0x01 28 29 #define PS2_PORT_DATA 0x60 30 #define PS2_PORT_CTRL 0x64 31 32 #define PS2_STATUS_OUTPUT_BUFFER_FULL 0x01 33 #define PS2_STATUS_AUX_DATA 0x20 34 35 36 enum serial_register_offsets { 37 SERIAL_TRANSMIT_BUFFER = 0, 38 SERIAL_RECEIVE_BUFFER = 0, 39 SERIAL_DIVISOR_LATCH_LOW = 0, 40 SERIAL_DIVISOR_LATCH_HIGH = 1, 41 SERIAL_FIFO_CONTROL = 2, 42 SERIAL_LINE_CONTROL = 3, 43 SERIAL_MODEM_CONTROL = 4, 44 SERIAL_LINE_STATUS = 5, 45 SERIAL_MODEM_STATUS = 6, 46 }; 47 48 enum keycodes { 49 LEFT_SHIFT = 42, 50 RIGHT_SHIFT = 54, 51 52 LEFT_CONTROL = 29, 53 54 LEFT_ALT = 56, 55 RIGHT_ALT = 58, 56 57 CURSOR_LEFT = 75, 58 CURSOR_RIGHT = 77, 59 CURSOR_UP = 72, 60 CURSOR_DOWN = 80, 61 CURSOR_HOME = 71, 62 CURSOR_END = 79, 63 PAGE_UP = 73, 64 PAGE_DOWN = 81, 65 66 DELETE = 83, 67 SYS_REQ = 84, 68 F12 = 88, 69 }; 70 71 72 static const uint32 kSerialBaudRate = 115200; 73 static uint16 sSerialBasePort = 0x3f8; 74 // COM1 is the default debug output port 75 76 static bool sKeyboardHandlerInstalled = false; 77 78 static spinlock sSerialOutputSpinlock = B_SPINLOCK_INITIALIZER; 79 80 81 static void 82 put_char(const char c) 83 { 84 // wait until the transmitter empty bit is set 85 while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x20) == 0) 86 asm volatile ("pause;"); 87 88 out8(c, sSerialBasePort + SERIAL_TRANSMIT_BUFFER); 89 } 90 91 92 static void 93 _arch_debug_serial_putchar(const char c) 94 { 95 if (c == '\n') { 96 put_char('\r'); 97 put_char('\n'); 98 } else if (c != '\r') 99 put_char(c); 100 } 101 102 103 /** Minimal keyboard handler to be able to get into the debugger and 104 * reboot the machine before the input_server is up and running. 105 * It is added as soon as interrupts become available, and removed 106 * again if anything else requests the interrupt 1. 107 */ 108 109 static int32 110 debug_keyboard_interrupt(void *data) 111 { 112 static bool controlPressed = false; 113 static bool altPressed = false; 114 static bool sysReqPressed = false; 115 uint8 key; 116 117 key = in8(PS2_PORT_DATA); 118 //dprintf("debug_keyboard_interrupt: key = 0x%x\n", key); 119 120 if (key & 0x80) { 121 if (key == LEFT_CONTROL) 122 controlPressed = false; 123 else if (key == LEFT_ALT) 124 altPressed = false; 125 else if (key == SYS_REQ) 126 sysReqPressed = false; 127 128 return B_HANDLED_INTERRUPT; 129 } 130 131 switch (key) { 132 case LEFT_CONTROL: 133 controlPressed = true; 134 break; 135 136 case LEFT_ALT: 137 case RIGHT_ALT: 138 altPressed = true; 139 break; 140 141 case SYS_REQ: 142 sysReqPressed = true; 143 break; 144 145 case DELETE: 146 if (controlPressed && altPressed) 147 arch_cpu_shutdown(true); 148 break; 149 150 default: 151 if (altPressed && sysReqPressed) { 152 if (debug_emergency_key_pressed(kUnshiftedKeymap[key])) { 153 // we probably have lost some keys, so reset our key states 154 controlPressed = false; 155 sysReqPressed = false; 156 altPressed = false; 157 } 158 } 159 break; 160 } 161 162 return B_HANDLED_INTERRUPT; 163 } 164 165 166 void 167 arch_debug_remove_interrupt_handler(uint32 line) 168 { 169 if (line != INT_PS2_KEYBOARD || !sKeyboardHandlerInstalled) 170 return; 171 172 remove_io_interrupt_handler(INT_PS2_KEYBOARD, &debug_keyboard_interrupt, 173 NULL); 174 sKeyboardHandlerInstalled = false; 175 } 176 177 178 void 179 arch_debug_install_interrupt_handlers(void) 180 { 181 install_io_interrupt_handler(INT_PS2_KEYBOARD, &debug_keyboard_interrupt, 182 NULL, 0); 183 sKeyboardHandlerInstalled = true; 184 } 185 186 187 char 188 arch_debug_blue_screen_getchar(void) 189 { 190 191 /* polling the keyboard, similar to code in keyboard 192 * driver, but without using an interrupt 193 */ 194 static bool shiftPressed = false; 195 static bool controlPressed = false; 196 static bool altPressed = false; 197 static uint8 special = 0; 198 static uint8 special2 = 0; 199 uint8 key = 0; 200 201 if (special & 0x80) { 202 special &= ~0x80; 203 return '['; 204 } 205 if (special != 0) { 206 key = special; 207 special = 0; 208 return key; 209 } 210 if (special2 != 0) { 211 key = special2; 212 special2 = 0; 213 return key; 214 } 215 216 while (true) { 217 uint8 status = in8(PS2_PORT_CTRL); 218 219 if ((status & PS2_STATUS_OUTPUT_BUFFER_FULL) == 0) { 220 // no data in keyboard buffer 221 spin(200); 222 continue; 223 } 224 225 spin(200); 226 key = in8(PS2_PORT_DATA); 227 228 if (status & PS2_STATUS_AUX_DATA) { 229 // we read mouse data, ignore it 230 continue; 231 } 232 233 if (key & 0x80) { 234 // key up 235 switch (key & ~0x80) { 236 case LEFT_SHIFT: 237 case RIGHT_SHIFT: 238 shiftPressed = false; 239 break; 240 case LEFT_CONTROL: 241 controlPressed = false; 242 break; 243 case LEFT_ALT: 244 altPressed = false; 245 break; 246 } 247 } else { 248 // key down 249 switch (key) { 250 case LEFT_SHIFT: 251 case RIGHT_SHIFT: 252 shiftPressed = true; 253 break; 254 255 case LEFT_CONTROL: 256 controlPressed = true; 257 break; 258 259 case LEFT_ALT: 260 altPressed = true; 261 break; 262 263 // start escape sequence for cursor movement 264 case CURSOR_UP: 265 special = 0x80 | 'A'; 266 return '\x1b'; 267 case CURSOR_DOWN: 268 special = 0x80 | 'B'; 269 return '\x1b'; 270 case CURSOR_RIGHT: 271 special = 0x80 | 'C'; 272 return '\x1b'; 273 case CURSOR_LEFT: 274 special = 0x80 | 'D'; 275 return '\x1b'; 276 case CURSOR_HOME: 277 special = 0x80 | 'H'; 278 return '\x1b'; 279 case CURSOR_END: 280 special = 0x80 | 'F'; 281 return '\x1b'; 282 case PAGE_UP: 283 special = 0x80 | '5'; 284 special2 = '~'; 285 return '\x1b'; 286 case PAGE_DOWN: 287 special = 0x80 | '6'; 288 special2 = '~'; 289 return '\x1b'; 290 291 292 case DELETE: 293 if (controlPressed && altPressed) 294 arch_cpu_shutdown(true); 295 296 special = 0x80 | '3'; 297 special2 = '~'; 298 return '\x1b'; 299 300 default: 301 if (controlPressed) { 302 char c = kShiftedKeymap[key]; 303 if (c >= 'A' && c <= 'Z') 304 return 0x1f & c; 305 } 306 307 if (altPressed) 308 return kAltedKeymap[key]; 309 310 return shiftPressed 311 ? kShiftedKeymap[key] : kUnshiftedKeymap[key]; 312 } 313 } 314 } 315 } 316 317 318 char 319 arch_debug_serial_getchar(void) 320 { 321 while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x1) == 0) 322 asm volatile ("pause;"); 323 324 return in8(sSerialBasePort + SERIAL_RECEIVE_BUFFER); 325 } 326 327 328 void 329 arch_debug_serial_putchar(const char c) 330 { 331 cpu_status state = 0; 332 if (!debug_debugger_running()) { 333 state = disable_interrupts(); 334 acquire_spinlock(&sSerialOutputSpinlock); 335 } 336 337 _arch_debug_serial_putchar(c); 338 339 if (!debug_debugger_running()) { 340 release_spinlock(&sSerialOutputSpinlock); 341 restore_interrupts(state); 342 } 343 } 344 345 346 void 347 arch_debug_serial_puts(const char *s) 348 { 349 cpu_status state = 0; 350 if (!debug_debugger_running()) { 351 state = disable_interrupts(); 352 acquire_spinlock(&sSerialOutputSpinlock); 353 } 354 355 while (*s != '\0') { 356 _arch_debug_serial_putchar(*s); 357 s++; 358 } 359 360 if (!debug_debugger_running()) { 361 release_spinlock(&sSerialOutputSpinlock); 362 restore_interrupts(state); 363 } 364 } 365 366 367 void 368 arch_debug_serial_early_boot_message(const char *string) 369 { 370 // this function will only be called in fatal situations 371 // ToDo: also enable output via text console?! 372 arch_debug_console_init(NULL); 373 arch_debug_serial_puts(string); 374 } 375 376 377 status_t 378 arch_debug_console_init(kernel_args *args) 379 { 380 uint16 divisor = (uint16)(115200 / kSerialBaudRate); 381 382 // only use the port if we could find one, else use the standard port 383 if (args != NULL && args->platform_args.serial_base_ports[0] != 0) 384 sSerialBasePort = args->platform_args.serial_base_ports[0]; 385 386 out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL); /* set divisor latch access bit */ 387 out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW); 388 out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH); 389 out8(3, sSerialBasePort + SERIAL_LINE_CONTROL); /* 8N1 */ 390 391 return B_OK; 392 } 393 394 395 status_t 396 arch_debug_console_init_settings(kernel_args *args) 397 { 398 uint32 baudRate = kSerialBaudRate; 399 uint16 basePort = sSerialBasePort; 400 uint16 divisor; 401 void *handle; 402 403 // get debug settings 404 handle = load_driver_settings("kernel"); 405 if (handle != NULL) { 406 const char *value = get_driver_parameter(handle, "serial_debug_port", 407 NULL, NULL); 408 if (value != NULL) { 409 int32 number = strtol(value, NULL, 0); 410 if (number >= MAX_SERIAL_PORTS) { 411 // use as port number directly 412 basePort = number; 413 } else if (number >= 0) { 414 // use as index into port array 415 if (args->platform_args.serial_base_ports[number] != 0) 416 basePort = args->platform_args.serial_base_ports[number]; 417 } else { 418 // ignore value and use default 419 } 420 } 421 422 value = get_driver_parameter(handle, "serial_debug_speed", NULL, NULL); 423 if (value != NULL) { 424 int32 number = strtol(value, NULL, 0); 425 switch (number) { 426 case 9600: 427 case 19200: 428 case 38400: 429 case 57600: 430 case 115200: 431 //case 230400: 432 baudRate = number; 433 } 434 } 435 436 unload_driver_settings(handle); 437 } 438 439 if (sSerialBasePort == basePort && baudRate == kSerialBaudRate) 440 return B_OK; 441 442 sSerialBasePort = basePort; 443 divisor = (uint16)(115200 / baudRate); 444 445 out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL); /* set divisor latch access bit */ 446 out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW); 447 out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH); 448 out8(3, sSerialBasePort + SERIAL_LINE_CONTROL); /* 8N1 */ 449 450 return B_OK; 451 } 452 -
src/system/kernel/arch/x86_64/asm_offsets.cpp
1 /* 2 * Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 // This file is used to get C structure offsets into assembly code. 7 // The build system assembles the file and processes the output to create 8 // a header file with macro definitions, that can be included from assembly 9 // code. 10 11 12 #include <computed_asm_macros.h> 13 14 #include <cpu.h> 15 #include <ksyscalls.h> 16 #include <thread_types.h> 17 18 19 #define DEFINE_MACRO(macro, value) DEFINE_COMPUTED_ASM_MACRO(macro, value) 20 21 #define DEFINE_OFFSET_MACRO(prefix, structure, member) \ 22 DEFINE_MACRO(prefix##_##member, offsetof(struct structure, member)); 23 24 #define DEFINE_SIZEOF_MACRO(prefix, structure) \ 25 DEFINE_MACRO(prefix##_sizeof, sizeof(struct structure)); 26 27 28 void 29 dummy() 30 { 31 // struct thread 32 DEFINE_OFFSET_MACRO(THREAD, thread, kernel_time); 33 DEFINE_OFFSET_MACRO(THREAD, thread, user_time); 34 DEFINE_OFFSET_MACRO(THREAD, thread, last_time); 35 DEFINE_OFFSET_MACRO(THREAD, thread, in_kernel); 36 DEFINE_OFFSET_MACRO(THREAD, thread, flags); 37 DEFINE_OFFSET_MACRO(THREAD, thread, kernel_stack_top); 38 DEFINE_OFFSET_MACRO(THREAD, thread, fault_handler); 39 40 // struct iframe 41 DEFINE_OFFSET_MACRO(IFRAME, iframe, cs); 42 DEFINE_OFFSET_MACRO(IFRAME, iframe, rax); 43 DEFINE_OFFSET_MACRO(IFRAME, iframe, rdx); 44 DEFINE_OFFSET_MACRO(IFRAME, iframe, orig_rax); 45 DEFINE_OFFSET_MACRO(IFRAME, iframe, vector); 46 DEFINE_OFFSET_MACRO(IFRAME, iframe, rip); 47 DEFINE_OFFSET_MACRO(IFRAME, iframe, flags); 48 DEFINE_OFFSET_MACRO(IFRAME, iframe, user_rsp); 49 50 // struct syscall_info 51 DEFINE_SIZEOF_MACRO(SYSCALL_INFO, syscall_info); 52 DEFINE_OFFSET_MACRO(SYSCALL_INFO, syscall_info, function); 53 DEFINE_OFFSET_MACRO(SYSCALL_INFO, syscall_info, parameter_size); 54 55 // struct x86_optimized_functions 56 DEFINE_OFFSET_MACRO(X86_64_OPTIMIZED_FUNCTIONS, x86_64_optimized_functions, 57 memcpy); 58 DEFINE_OFFSET_MACRO(X86_64_OPTIMIZED_FUNCTIONS, x86_64_optimized_functions, 59 memset); 60 } -
src/system/kernel/arch/x86_64/apic.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2010, Michael Lotz, mmlr@mlotz.ch. All rights reserved. 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 9 * Distributed under the terms of the MIT License. 10 * 11 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 12 * Distributed under the terms of the NewOS License. 13 */ 14 15 #include <arch/x86_64/apic.h> 16 17 #include <debug.h> 18 #include <vm/vm.h> 19 20 #include "timers/apic_timer.h" 21 22 23 static void *sLocalAPIC = NULL; 24 25 26 bool 27 apic_available() 28 { 29 return sLocalAPIC != NULL; 30 } 31 32 33 uint32 34 apic_read(uint32 offset) 35 { 36 return *(volatile uint32 *)((char *)sLocalAPIC + offset); 37 } 38 39 40 void 41 apic_write(uint32 offset, uint32 data) 42 { 43 *(volatile uint32 *)((char *)sLocalAPIC + offset) = data; 44 } 45 46 47 uint32 48 apic_local_id() 49 { 50 return (apic_read(APIC_ID) & 0xffffffff) >> 24; 51 } 52 53 54 void 55 apic_end_of_interrupt() 56 { 57 apic_write(APIC_EOI, 0); 58 } 59 60 61 status_t 62 apic_init(kernel_args *args) 63 { 64 if (args->arch_args.apic == NULL) 65 return B_NO_INIT; 66 67 sLocalAPIC = args->arch_args.apic; 68 dprintf("mapping local apic at %p\n", sLocalAPIC); 69 if (vm_map_physical_memory(B_SYSTEM_TEAM, "local apic", &sLocalAPIC, 70 B_EXACT_ADDRESS, B_PAGE_SIZE, 71 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 72 args->arch_args.apic_phys, true) < 0) { 73 panic("mapping the local apic failed"); 74 return B_ERROR; 75 } 76 77 return B_OK; 78 } 79 80 81 status_t 82 apic_per_cpu_init(kernel_args *args, int32 cpu) 83 { 84 dprintf("setting up apic for CPU %ld: apic id %lu, version %lu\n", cpu, 85 apic_local_id(), apic_read(APIC_VERSION)); 86 87 /* set spurious interrupt vector to 0xff */ 88 uint32 config = apic_read(APIC_SPURIOUS_INTR_VECTOR) & 0xffffff00; 89 config |= APIC_ENABLE | 0xff; 90 apic_write(APIC_SPURIOUS_INTR_VECTOR, config); 91 92 93 apic_timer_per_cpu_init(args, cpu); 94 95 /* setup error vector to 0xfe */ 96 config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe; 97 apic_write(APIC_LVT_ERROR, config); 98 99 /* accept all interrupts */ 100 config = apic_read(APIC_TASK_PRIORITY) & 0xffffff00; 101 apic_write(APIC_TASK_PRIORITY, config); 102 103 config = apic_read(APIC_SPURIOUS_INTR_VECTOR); 104 apic_end_of_interrupt(); 105 106 return B_OK; 107 } -
src/system/kernel/arch/x86_64/arch_timer.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 9 * Distributed under the terms of the NewOS License. 10 */ 11 12 13 #include <boot/stage2.h> 14 #include <kernel.h> 15 16 #include <arch/int.h> 17 #include <arch/cpu.h> 18 19 #include <console.h> 20 #include <debug.h> 21 #include <timer.h> 22 #include <int.h> 23 #include <safemode.h> 24 25 #include <arch/timer.h> 26 27 28 //#define TRACE_TIMER 29 #ifdef TRACE_TIMER 30 # define TRACE(x) dprintf x 31 #else 32 # define TRACE(x) ; 33 #endif 34 35 extern timer_info gPITTimer; 36 extern timer_info gAPICTimer; 37 extern timer_info gHPETTimer; 38 39 static timer_info *sTimers[] = { 40 &gHPETTimer, 41 &gAPICTimer, 42 &gPITTimer, 43 NULL 44 }; 45 46 static timer_info *sTimer = NULL; 47 48 49 static void 50 sort_timers(timer_info *timers[], int numTimers) 51 { 52 timer_info *tempPtr; 53 int max = 0; 54 int i = 0; 55 int j = 0; 56 57 for (i = 0; i < numTimers - 1; i++) { 58 max = i; 59 for (j = i + 1; j < numTimers; j++) { 60 if (timers[j]->get_priority() > timers[max]->get_priority()) 61 max = j; 62 } 63 if (max != i) { 64 tempPtr = timers[max]; 65 timers[max] = timers[i]; 66 timers[i] = tempPtr; 67 } 68 } 69 } 70 71 72 void 73 arch_timer_set_hardware_timer(bigtime_t timeout) 74 { 75 TRACE(("arch_timer_set_hardware_timer: timeout %lld\n", timeout)); 76 sTimer->set_hardware_timer(timeout); 77 } 78 79 80 void 81 arch_timer_clear_hardware_timer() 82 { 83 TRACE(("arch_timer_clear_hardware_timer\n")); 84 sTimer->clear_hardware_timer(); 85 } 86 87 88 int 89 arch_init_timer(kernel_args *args) 90 { 91 // Sort timers by priority 92 sort_timers(sTimers, (sizeof(sTimers) / sizeof(sTimers[0])) - 1); 93 94 timer_info *timer = NULL; 95 cpu_status state = disable_interrupts(); 96 97 for (int i = 0; (timer = sTimers[i]) != NULL; i++) { 98 if (timer->init(args) == B_OK) 99 break; 100 } 101 102 sTimer = timer; 103 104 if (sTimer != NULL) { 105 dprintf("arch_init_timer: using %s timer.\n", sTimer->name); 106 } else { 107 panic("No system timers were found usable.\n"); 108 } 109 110 restore_interrupts(state); 111 112 return 0; 113 } 114 -
src/system/kernel/arch/x86_64/irq_routing_table.h
1 /* 2 * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 #ifndef IRQ_ROUTING_TABLE_H 6 #define IRQ_ROUTING_TABLE_H 7 8 9 #include <ACPI.h> 10 #include <PCI.h> 11 12 13 #include "util/Vector.h" 14 15 16 struct irq_routing_entry { 17 int device_address; 18 int8 pin; 19 20 acpi_handle source; 21 int source_index; 22 23 // pci busmanager connection 24 uchar pci_bus; 25 uchar pci_device; 26 }; 27 28 29 typedef Vector<irq_routing_entry> IRQRoutingTable; 30 31 32 struct irq_descriptor { 33 irq_descriptor(); 34 // bit 0 is interrupt 0, bit 2 is interrupt 2, and so on 35 int16 irq; 36 bool shareable; 37 // B_LOW_ACTIVE_POLARITY or B_HIGH_ACTIVE_POLARITY 38 int8 polarity; 39 // B_LEVEL_TRIGGERED or B_EDGE_TRIGGERED 40 int8 interrupt_mode; 41 }; 42 43 44 // Similar to bus_managers/acpi/include/acrestyp.h definition 45 typedef struct acpi_prt { 46 uint32 length; 47 uint32 pin; 48 int address; // here for 64-bit alignment 49 uint32 sourceIndex; 50 char source[4]; // pad to 64 bits so sizeof() works in 51 // all cases 52 } acpi_pci_routing_table; 53 54 55 void print_irq_descriptor(irq_descriptor* descriptor); 56 void print_irq_routing_table(IRQRoutingTable* table); 57 58 59 status_t read_irq_routing_table(pci_module_info *pci, acpi_module_info* acpi, 60 IRQRoutingTable* table); 61 status_t read_irq_descriptor(acpi_module_info* acpi, acpi_handle device, 62 const char* method, irq_descriptor* descriptor); 63 64 status_t read_current_irq(acpi_module_info* acpi, acpi_handle device, 65 irq_descriptor* descriptor); 66 status_t read_possible_irq(acpi_module_info* acpi, acpi_handle device, 67 irq_descriptor* descriptor); 68 69 status_t set_acpi_irq(acpi_module_info* acpi, acpi_handle device, 70 irq_descriptor* descriptor); 71 72 #endif // IRQ_ROUTING_TABLE_H -
src/system/kernel/arch/x86_64/arch_vm.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2008, Jérôme Duval. 5 * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 9 * Distributed under the terms of the NewOS License. 10 */ 11 12 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include <algorithm> 17 #include <new> 18 19 #include <KernelExport.h> 20 21 #include <boot/kernel_args.h> 22 #include <smp.h> 23 #include <util/AutoLock.h> 24 #include <vm/vm.h> 25 #include <vm/vm_page.h> 26 #include <vm/vm_priv.h> 27 #include <vm/VMAddressSpace.h> 28 #include <vm/VMArea.h> 29 30 #include <arch/vm.h> 31 #include <arch/int.h> 32 #include <arch/cpu.h> 33 34 35 //#define TRACE_ARCH_VM 36 #ifdef TRACE_ARCH_VM 37 # define TRACE(x) dprintf x 38 #else 39 # define TRACE(x) ; 40 #endif 41 42 // 0: disabled, 1: some, 2: more 43 #define TRACE_MTRR_ARCH_VM 0 44 45 #if TRACE_MTRR_ARCH_VM >= 1 46 # define TRACE_MTRR(x...) dprintf(x) 47 #else 48 # define TRACE_MTRR(x...) 49 #endif 50 51 #if TRACE_MTRR_ARCH_VM >= 2 52 # define TRACE_MTRR2(x...) dprintf(x) 53 #else 54 # define TRACE_MTRR2(x...) 55 #endif 56 57 void *gDmaAddress; 58 59 60 struct memory_type_range : DoublyLinkedListLinkImpl<memory_type_range> { 61 uint64 base; 62 uint64 size; 63 uint32 type; 64 area_id area; 65 }; 66 67 68 struct memory_type_range_point 69 : DoublyLinkedListLinkImpl<memory_type_range_point> { 70 uint64 address; 71 memory_type_range* range; 72 73 bool IsStart() const { return range->base == address; } 74 75 bool operator<(const memory_type_range_point& other) const 76 { 77 return address < other.address; 78 } 79 }; 80 81 82 struct update_mtrr_info { 83 uint64 ignoreUncacheableSize; 84 uint64 shortestUncacheableSize; 85 }; 86 87 88 typedef DoublyLinkedList<memory_type_range> MemoryTypeRangeList; 89 90 static mutex sMemoryTypeLock = MUTEX_INITIALIZER("memory type ranges"); 91 static MemoryTypeRangeList sMemoryTypeRanges; 92 static int32 sMemoryTypeRangeCount = 0; 93 94 static const uint32 kMaxMemoryTypeRegisters = 32; 95 static x86_64_mtrr_info sMemoryTypeRegisters[kMaxMemoryTypeRegisters]; 96 static uint32 sMemoryTypeRegisterCount; 97 static uint32 sMemoryTypeRegistersUsed; 98 99 static memory_type_range* sTemporaryRanges = NULL; 100 static memory_type_range_point* sTemporaryRangePoints = NULL; 101 static int32 sTemporaryRangeCount = 0; 102 static int32 sTemporaryRangePointCount = 0; 103 104 105 106 static void 107 set_mtrrs() 108 { 109 x86_64_set_mtrrs(IA32_MTR_WRITE_BACK, sMemoryTypeRegisters, 110 sMemoryTypeRegistersUsed); 111 112 #if TRACE_MTRR_ARCH_VM 113 TRACE_MTRR("set MTRRs to:\n"); 114 for (uint32 i = 0; i < sMemoryTypeRegistersUsed; i++) { 115 const x86_64_mtrr_info& info = sMemoryTypeRegisters[i]; 116 TRACE_MTRR(" mtrr: %2" B_PRIu32 ": base: %#10" B_PRIx64 ", size: %#10" 117 B_PRIx64 ", type: %u\n", i, info.base, info.size, 118 info.type); 119 } 120 #endif 121 } 122 123 124 static bool 125 add_used_mtrr(uint64 base, uint64 size, uint32 type) 126 { 127 if (sMemoryTypeRegistersUsed == sMemoryTypeRegisterCount) 128 return false; 129 130 x86_64_mtrr_info& mtrr = sMemoryTypeRegisters[sMemoryTypeRegistersUsed++]; 131 mtrr.base = base; 132 mtrr.size = size; 133 mtrr.type = type; 134 135 return true; 136 } 137 138 139 static bool 140 ensure_temporary_ranges_space(int32 count) 141 { 142 if (sTemporaryRangeCount >= count && sTemporaryRangePointCount >= count) 143 return true; 144 145 // round count to power of 2 146 int32 unalignedCount = count; 147 count = 8; 148 while (count < unalignedCount) 149 count <<= 1; 150 151 // resize ranges array 152 if (sTemporaryRangeCount < count) { 153 memory_type_range* ranges = new(std::nothrow) memory_type_range[count]; 154 if (ranges == NULL) 155 return false; 156 157 delete[] sTemporaryRanges; 158 159 sTemporaryRanges = ranges; 160 sTemporaryRangeCount = count; 161 } 162 163 // resize points array 164 if (sTemporaryRangePointCount < count) { 165 memory_type_range_point* points 166 = new(std::nothrow) memory_type_range_point[count]; 167 if (points == NULL) 168 return false; 169 170 delete[] sTemporaryRangePoints; 171 172 sTemporaryRangePoints = points; 173 sTemporaryRangePointCount = count; 174 } 175 176 return true; 177 } 178 179 180 static bool 181 add_mtrrs_for_range(uint64 base, uint64 size, uint32 type) 182 { 183 for (uint64 interval = B_PAGE_SIZE; size > 0; interval <<= 1) { 184 if ((base & interval) != 0) { 185 if (!add_used_mtrr(base, interval, type)) 186 return false; 187 base += interval; 188 size -= interval; 189 } 190 191 if ((size & interval) != 0) { 192 if (!add_used_mtrr(base + size - interval, interval, type)) 193 return false; 194 size -= interval; 195 } 196 } 197 198 return true; 199 } 200 201 202 static memory_type_range* 203 find_range(area_id areaID) 204 { 205 for (MemoryTypeRangeList::Iterator it = sMemoryTypeRanges.GetIterator(); 206 memory_type_range* range = it.Next();) { 207 if (range->area == areaID) 208 return range; 209 } 210 211 return NULL; 212 } 213 214 215 static void 216 optimize_memory_ranges(MemoryTypeRangeList& ranges, uint32 type, 217 bool removeRanges) 218 { 219 uint64 previousEnd = 0; 220 uint64 nextStart = 0; 221 MemoryTypeRangeList::Iterator it = ranges.GetIterator(); 222 memory_type_range* range = it.Next(); 223 while (range != NULL) { 224 if (range->type != type) { 225 previousEnd = range->base + range->size; 226 nextStart = 0; 227 range = it.Next(); 228 continue; 229 } 230 231 // find the start of the next range we cannot join this one with 232 if (nextStart == 0) { 233 MemoryTypeRangeList::Iterator nextIt = it; 234 while (memory_type_range* nextRange = nextIt.Next()) { 235 if (nextRange->type != range->type) { 236 nextStart = nextRange->base; 237 break; 238 } 239 } 240 241 if (nextStart == 0) { 242 // no upper limit -- set an artificial one, so we don't need to 243 // special case below 244 nextStart = (uint64)1 << 32; 245 } 246 } 247 248 // Align the range's base and end to the greatest power of two possible. 249 // As long as we can align both without intersecting any differently 250 // range, we can extend the range without making it more complicated. 251 // Once one side hit a limit we need to be careful. We can still 252 // continue aligning the other side, if the range crosses the power of 253 // two boundary. 254 uint64 rangeBase = range->base; 255 uint64 rangeEnd = rangeBase + range->size; 256 uint64 interval = B_PAGE_SIZE * 2; 257 while (true) { 258 uint64 alignedBase = rangeBase & ~(interval - 1); 259 uint64 alignedEnd = (rangeEnd + interval - 1) & ~(interval - 1); 260 261 if (alignedBase < previousEnd) 262 alignedBase += interval; 263 264 if (alignedEnd > nextStart) 265 alignedEnd -= interval; 266 267 if (alignedBase >= alignedEnd) 268 break; 269 270 rangeBase = std::min(rangeBase, alignedBase); 271 rangeEnd = std::max(rangeEnd, alignedEnd); 272 273 interval <<= 1; 274 } 275 276 range->base = rangeBase; 277 range->size = rangeEnd - rangeBase; 278 279 if (removeRanges) 280 it.Remove(); 281 282 previousEnd = rangeEnd; 283 284 // Skip the subsequent ranges we have swallowed and possible cut one 285 // we now partially intersect with. 286 while ((range = it.Next()) != NULL) { 287 if (range->base >= rangeEnd) 288 break; 289 290 if (range->base + range->size > rangeEnd) { 291 // we partially intersect -- cut the range 292 range->size = range->base + range->size - rangeEnd; 293 range->base = rangeEnd; 294 break; 295 } 296 297 // we have swallowed this range completely 298 range->size = 0; 299 it.Remove(); 300 } 301 } 302 } 303 304 305 status_t 306 update_mtrrs(update_mtrr_info& updateInfo) 307 { 308 // resize the temporary points/ranges arrays, if necessary 309 if (!ensure_temporary_ranges_space(sMemoryTypeRangeCount * 2)) 310 return B_NO_MEMORY; 311 312 // get the range points and sort them 313 memory_type_range_point* rangePoints = sTemporaryRangePoints; 314 int32 pointCount = 0; 315 for (MemoryTypeRangeList::Iterator it = sMemoryTypeRanges.GetIterator(); 316 memory_type_range* range = it.Next();) { 317 if (range->type == IA32_MTR_UNCACHED) { 318 // Ignore uncacheable ranges below a certain size, if requested. 319 // Since we always enforce uncacheability via the PTE attributes, 320 // this is no problem (though not recommended for performance 321 // reasons). 322 if (range->size <= updateInfo.ignoreUncacheableSize) 323 continue; 324 if (range->size < updateInfo.shortestUncacheableSize) 325 updateInfo.shortestUncacheableSize = range->size; 326 } 327 328 rangePoints[pointCount].address = range->base; 329 rangePoints[pointCount++].range = range; 330 rangePoints[pointCount].address = range->base + range->size; 331 rangePoints[pointCount++].range = range; 332 } 333 334 std::sort(rangePoints, rangePoints + pointCount); 335 336 #if TRACE_MTRR_ARCH_VM >= 2 337 TRACE_MTRR2("memory type range points:\n"); 338 for (int32 i = 0; i < pointCount; i++) { 339 TRACE_MTRR2("%12" B_PRIx64 " (%p)\n", rangePoints[i].address, 340 rangePoints[i].range); 341 } 342 #endif 343 344 // Compute the effective ranges. When ranges overlap, we go with the 345 // stricter requirement. The types are not necessarily totally ordered, so 346 // the order we use below is not always correct. To keep it simple we 347 // consider it the reponsibility of the callers not to define overlapping 348 // memory ranges with uncomparable types. 349 350 memory_type_range* ranges = sTemporaryRanges; 351 typedef DoublyLinkedList<memory_type_range_point> PointList; 352 PointList pendingPoints; 353 memory_type_range* activeRange = NULL; 354 int32 rangeCount = 0; 355 356 for (int32 i = 0; i < pointCount; i++) { 357 memory_type_range_point* point = &rangePoints[i]; 358 bool terminateRange = false; 359 if (point->IsStart()) { 360 // a range start point 361 pendingPoints.Add(point); 362 if (activeRange != NULL && activeRange->type > point->range->type) 363 terminateRange = true; 364 } else { 365 // a range end point -- remove the pending start point 366 for (PointList::Iterator it = pendingPoints.GetIterator(); 367 memory_type_range_point* pendingPoint = it.Next();) { 368 if (pendingPoint->range == point->range) { 369 it.Remove(); 370 break; 371 } 372 } 373 374 if (point->range == activeRange) 375 terminateRange = true; 376 } 377 378 if (terminateRange) { 379 ranges[rangeCount].size = point->address - ranges[rangeCount].base; 380 rangeCount++; 381 activeRange = NULL; 382 } 383 384 if (activeRange != NULL || pendingPoints.IsEmpty()) 385 continue; 386 387 // we need to start a new range -- find the strictest pending range 388 for (PointList::Iterator it = pendingPoints.GetIterator(); 389 memory_type_range_point* pendingPoint = it.Next();) { 390 memory_type_range* pendingRange = pendingPoint->range; 391 if (activeRange == NULL || activeRange->type > pendingRange->type) 392 activeRange = pendingRange; 393 } 394 395 memory_type_range* previousRange = rangeCount > 0 396 ? &ranges[rangeCount - 1] : NULL; 397 if (previousRange == NULL || previousRange->type != activeRange->type 398 || previousRange->base + previousRange->size 399 < activeRange->base) { 400 // we can't join with the previous range -- add a new one 401 ranges[rangeCount].base = point->address; 402 ranges[rangeCount].type = activeRange->type; 403 } else 404 rangeCount--; 405 } 406 407 #if TRACE_MTRR_ARCH_VM >= 2 408 TRACE_MTRR2("effective memory type ranges:\n"); 409 for (int32 i = 0; i < rangeCount; i++) { 410 TRACE_MTRR2("%12" B_PRIx64 " - %12" B_PRIx64 ": %" B_PRIu32 "\n", 411 ranges[i].base, ranges[i].base + ranges[i].size, ranges[i].type); 412 } 413 #endif 414 415 // Extend ranges to be more MTRR-friendly. A range is MTRR friendly, when it 416 // has a power of two size and a base address aligned to the size. For 417 // ranges without this property we need more than one MTRR. We improve 418 // MTRR-friendliness by aligning a range's base and end address to the 419 // greatest power of two (base rounded down, end up) such that the extended 420 // range does not intersect with any other differently typed range. We join 421 // equally typed ranges, if possible. There are two exceptions to the 422 // intersection requirement: Uncached ranges may intersect with any other 423 // range; the resulting type will still be uncached. Hence we can ignore 424 // uncached ranges when extending the other ranges. Write-through ranges may 425 // intersect with write-back ranges; the resulting type will be 426 // write-through. Hence we can ignore write-through ranges when extending 427 // write-back ranges. 428 429 MemoryTypeRangeList rangeList; 430 for (int32 i = 0; i < rangeCount; i++) 431 rangeList.Add(&ranges[i]); 432 433 static const uint32 kMemoryTypes[] = { 434 IA32_MTR_UNCACHED, 435 IA32_MTR_WRITE_COMBINING, 436 IA32_MTR_WRITE_PROTECTED, 437 IA32_MTR_WRITE_THROUGH, 438 IA32_MTR_WRITE_BACK 439 }; 440 static const int32 kMemoryTypeCount = sizeof(kMemoryTypes) 441 / sizeof(*kMemoryTypes); 442 443 for (int32 i = 0; i < kMemoryTypeCount; i++) { 444 uint32 type = kMemoryTypes[i]; 445 446 // Remove uncached and write-through ranges after processing them. This 447 // let's us leverage their intersection property with any other 448 // respectively write-back ranges. 449 bool removeRanges = type == IA32_MTR_UNCACHED 450 || type == IA32_MTR_WRITE_THROUGH; 451 452 optimize_memory_ranges(rangeList, type, removeRanges); 453 } 454 455 #if TRACE_MTRR_ARCH_VM >= 2 456 TRACE_MTRR2("optimized memory type ranges:\n"); 457 for (int32 i = 0; i < rangeCount; i++) { 458 if (ranges[i].size > 0) { 459 TRACE_MTRR2("%12" B_PRIx64 " - %12" B_PRIx64 ": %" B_PRIu32 "\n", 460 ranges[i].base, ranges[i].base + ranges[i].size, 461 ranges[i].type); 462 } 463 } 464 #endif 465 466 // compute the mtrrs from the ranges 467 sMemoryTypeRegistersUsed = 0; 468 for (int32 i = 0; i < kMemoryTypeCount; i++) { 469 uint32 type = kMemoryTypes[i]; 470 471 // skip write-back ranges -- that'll be the default type anyway 472 if (type == IA32_MTR_WRITE_BACK) 473 continue; 474 475 for (int32 i = 0; i < rangeCount; i++) { 476 if (ranges[i].size == 0 || ranges[i].type != type) 477 continue; 478 479 if (!add_mtrrs_for_range(ranges[i].base, ranges[i].size, type)) 480 return B_BUSY; 481 } 482 } 483 484 set_mtrrs(); 485 486 return B_OK; 487 } 488 489 490 status_t 491 update_mtrrs() 492 { 493 // Until we know how many MTRRs we have, pretend everything is OK. 494 if (sMemoryTypeRegisterCount == 0) 495 return B_OK; 496 497 update_mtrr_info updateInfo; 498 updateInfo.ignoreUncacheableSize = 0; 499 500 while (true) { 501 TRACE_MTRR2("update_mtrrs(): Trying with ignoreUncacheableSize %#" 502 B_PRIx64 ".\n", updateInfo.ignoreUncacheableSize); 503 504 updateInfo.shortestUncacheableSize = ~(uint64)0; 505 status_t error = update_mtrrs(updateInfo); 506 if (error != B_BUSY) { 507 if (error == B_OK && updateInfo.ignoreUncacheableSize > 0) { 508 TRACE_MTRR("update_mtrrs(): Succeeded setting MTRRs after " 509 "ignoring uncacheable ranges up to size %#" B_PRIx64 ".\n", 510 updateInfo.ignoreUncacheableSize); 511 } 512 return error; 513 } 514 515 // Not enough MTRRs. Retry with less uncacheable ranges. 516 if (updateInfo.shortestUncacheableSize == ~(uint64)0) { 517 // Ugh, even without any uncacheable ranges the available MTRRs do 518 // not suffice. 519 panic("update_mtrrs(): Out of MTRRs!"); 520 return B_BUSY; 521 } 522 523 ASSERT(updateInfo.ignoreUncacheableSize 524 < updateInfo.shortestUncacheableSize); 525 526 updateInfo.ignoreUncacheableSize = updateInfo.shortestUncacheableSize; 527 } 528 } 529 530 531 static status_t 532 add_memory_type_range(area_id areaID, uint64 base, uint64 size, uint32 type) 533 { 534 // translate the type 535 if (type == 0) 536 return B_OK; 537 538 switch (type) { 539 case B_MTR_UC: 540 type = IA32_MTR_UNCACHED; 541 break; 542 case B_MTR_WC: 543 type = IA32_MTR_WRITE_COMBINING; 544 break; 545 case B_MTR_WT: 546 type = IA32_MTR_WRITE_THROUGH; 547 break; 548 case B_MTR_WP: 549 type = IA32_MTR_WRITE_PROTECTED; 550 break; 551 case B_MTR_WB: 552 type = IA32_MTR_WRITE_BACK; 553 break; 554 default: 555 return B_BAD_VALUE; 556 } 557 558 TRACE_MTRR("add_memory_type_range(%" B_PRId32 ", %#" B_PRIx64 ", %#" 559 B_PRIx64 ", %" B_PRIu32 ")\n", areaID, base, size, type); 560 561 MutexLocker locker(sMemoryTypeLock); 562 563 memory_type_range* range = areaID >= 0 ? find_range(areaID) : NULL; 564 int32 oldRangeType = -1; 565 if (range != NULL) { 566 if (range->base != base || range->size != size) 567 return B_BAD_VALUE; 568 if (range->type == type) 569 return B_OK; 570 571 oldRangeType = range->type; 572 range->type = type; 573 } else { 574 range = new(std::nothrow) memory_type_range; 575 if (range == NULL) 576 return B_NO_MEMORY; 577 578 range->area = areaID; 579 range->base = base; 580 range->size = size; 581 range->type = type; 582 sMemoryTypeRanges.Add(range); 583 sMemoryTypeRangeCount++; 584 } 585 586 status_t error = update_mtrrs(); 587 if (error != B_OK) { 588 // revert the addition of the range/change of its type 589 if (oldRangeType < 0) { 590 sMemoryTypeRanges.Remove(range); 591 sMemoryTypeRangeCount--; 592 delete range; 593 } else 594 range->type = oldRangeType; 595 596 update_mtrrs(); 597 return error; 598 } 599 600 return B_OK; 601 } 602 603 604 static void 605 remove_memory_type_range(area_id areaID) 606 { 607 MutexLocker locker(sMemoryTypeLock); 608 609 memory_type_range* range = find_range(areaID); 610 if (range != NULL) { 611 TRACE_MTRR("remove_memory_type_range(%" B_PRId32 ", %#" B_PRIx64 ", %#" 612 B_PRIx64 ", %" B_PRIu32 ")\n", range->area, range->base, 613 range->size, range->type); 614 615 sMemoryTypeRanges.Remove(range); 616 sMemoryTypeRangeCount--; 617 delete range; 618 619 update_mtrrs(); 620 } else { 621 dprintf("remove_memory_type_range(): no range known for area %" B_PRId32 622 "\n", areaID); 623 } 624 } 625 626 627 status_t 628 arch_vm_init(kernel_args *args) 629 { 630 TRACE(("arch_vm_init: entry\n")); 631 return 0; 632 } 633 634 635 status_t 636 arch_vm_init_post_area(kernel_args *args) 637 { 638 area_id id; 639 640 TRACE(("arch_vm_init_post_area: entry\n")); 641 642 // account for DMA area and mark the pages unusable 643 vm_mark_page_range_inuse(0x0, 0xa0000 / B_PAGE_SIZE); 644 645 // map 0 - 0xa0000 directly 646 id = map_physical_memory("dma_region", 0x0, 0xa0000, 647 B_ANY_KERNEL_ADDRESS | B_MTR_WB, 648 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, &gDmaAddress); 649 if (id < 0) { 650 panic("arch_vm_init_post_area: unable to map dma region\n"); 651 return B_NO_MEMORY; 652 } 653 654 return B_OK; 655 } 656 657 658 status_t 659 arch_vm_init_end(kernel_args *args) 660 { 661 TRACE(("arch_vm_init_endvm: entry\n")); 662 663 // throw away anything in the kernel_args.pgtable[] that's not yet mapped 664 vm_free_unused_boot_loader_range(KERNEL_BASE, 665 args->arch_args.virtual_end - KERNEL_BASE); 666 667 return B_OK; 668 } 669 670 671 status_t 672 arch_vm_init_post_modules(kernel_args *args) 673 { 674 // the x86_64 CPU modules are now accessible 675 676 sMemoryTypeRegisterCount = x86_64_count_mtrrs(); 677 if (sMemoryTypeRegisterCount == 0) 678 return B_OK; 679 680 // not very likely, but play safe here 681 if (sMemoryTypeRegisterCount > kMaxMemoryTypeRegisters) 682 sMemoryTypeRegisterCount = kMaxMemoryTypeRegisters; 683 684 // set the physical memory ranges to write-back mode 685 for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) { 686 add_memory_type_range(-1, args->physical_memory_range[i].start, 687 args->physical_memory_range[i].size, B_MTR_WB); 688 } 689 690 return B_OK; 691 } 692 693 694 void 695 arch_vm_aspace_swap(struct VMAddressSpace *from, struct VMAddressSpace *to) 696 { 697 // This functions is only invoked when a userland thread is in the process 698 // of dying. It switches to the kernel team and does whatever cleanup is 699 // necessary (in case it is the team's main thread, it will delete the 700 // team). 701 // It is however not necessary to change the page directory. Userland team's 702 // page directories include all kernel mappings as well. Furthermore our 703 // arch specific translation map data objects are ref-counted, so they won't 704 // go away as long as they are still used on any CPU. 705 } 706 707 708 bool 709 arch_vm_supports_protection(uint32 protection) 710 { 711 // x86 and x86_64 always has the same read/write properties for userland 712 // and the kernel. 713 // That's why we do not support user-read/kernel-write access. While the 714 // other way around is not supported either, we don't care in this case 715 // and give the kernel full access. 716 if ((protection & (B_READ_AREA | B_WRITE_AREA)) == B_READ_AREA 717 && (protection & B_KERNEL_WRITE_AREA) != 0) { 718 return false; 719 } 720 721 return true; 722 } 723 724 725 void 726 arch_vm_unset_memory_type(VMArea *area) 727 { 728 if (area->MemoryType() == 0) 729 return; 730 731 remove_memory_type_range(area->id); 732 } 733 734 735 status_t 736 arch_vm_set_memory_type(VMArea *area, phys_addr_t physicalBase, uint32 type) 737 { 738 return add_memory_type_range(area->id, physicalBase, area->Size(), type); 739 } -
src/system/kernel/arch/x86_64/arch_platform.cpp
1 /* 2 * Copyright 2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <arch/platform.h> 8 9 10 status_t 11 arch_platform_init(struct kernel_args *kernelArgs) 12 { 13 return B_OK; 14 } 15 16 17 status_t 18 arch_platform_init_post_vm(struct kernel_args *kernelArgs) 19 { 20 return B_OK; 21 } 22 23 24 /* TODO: x86 initalizes APM code here. x86_64 could do that as well. */ 25 status_t 26 arch_platform_init_post_thread(struct kernel_args *kernelArgs) 27 { 28 return B_OK; 29 } -
src/system/kernel/arch/x86_64/timers/x86_64_hpet.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Copyright 2009-2010, Stefano Ceccherini (stefano.ceccherini@gmail.com) 4 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 #include <debug.h> 9 #include <int.h> 10 #include <smp.h> 11 #include <timer.h> 12 13 #include <arch/int.h> 14 #include <arch/cpu.h> 15 #include <arch/x86_64/timer.h> 16 #include <arch/x86_64/arch_hpet.h> 17 18 #include <boot/kernel_args.h> 19 #include <vm/vm.h> 20 21 22 //#define TRACE_HPET 23 #ifdef TRACE_HPET 24 #define TRACE(x) dprintf x 25 #else 26 #define TRACE(x) ; 27 #endif 28 29 #define TEST_HPET 30 31 static struct hpet_regs *sHPETRegs; 32 static volatile struct hpet_timer *sTimer; 33 static uint64 sHPETPeriod; 34 35 static int hpet_get_priority(); 36 static status_t hpet_set_hardware_timer(bigtime_t relativeTimeout); 37 static status_t hpet_clear_hardware_timer(); 38 static status_t hpet_init(struct kernel_args *args); 39 40 41 struct timer_info gHPETTimer = { 42 "HPET", 43 &hpet_get_priority, 44 &hpet_set_hardware_timer, 45 &hpet_clear_hardware_timer, 46 &hpet_init 47 }; 48 49 50 static int 51 hpet_get_priority() 52 { 53 // TODO: Fix HPET for SMP. 54 if (smp_get_num_cpus() > 1) 55 return 0; 56 57 // HPET timers, being off-chip, are more expensive to setup 58 // than the LAPIC. 59 return 0; 60 } 61 62 63 static int32 64 hpet_timer_interrupt(void *arg) 65 { 66 //dprintf_no_syslog("HPET timer_interrupt!!!!\n"); 67 return timer_interrupt(); 68 } 69 70 71 static inline bigtime_t 72 hpet_convert_timeout(const bigtime_t &relativeTimeout) 73 { 74 return ((relativeTimeout * 1000000000ULL) 75 / sHPETPeriod) + sHPETRegs->u0.counter64; 76 } 77 78 79 #define MIN_TIMEOUT 3000 80 81 static status_t 82 hpet_set_hardware_timer(bigtime_t relativeTimeout) 83 { 84 cpu_status state = disable_interrupts(); 85 86 // enable timer interrupt 87 sTimer->config |= HPET_CONF_TIMER_INT_ENABLE; 88 89 90 if (relativeTimeout < MIN_TIMEOUT) 91 relativeTimeout = MIN_TIMEOUT; 92 93 bigtime_t timerValue = hpet_convert_timeout(relativeTimeout); 94 95 sTimer->u0.comparator64 = timerValue; 96 97 restore_interrupts(state); 98 99 return B_OK; 100 } 101 102 103 static status_t 104 hpet_clear_hardware_timer() 105 { 106 // Disable timer interrupt 107 sTimer->config &= ~HPET_CONF_TIMER_INT_ENABLE; 108 return B_OK; 109 } 110 111 112 static status_t 113 hpet_set_enabled(bool enabled) 114 { 115 if (enabled) 116 sHPETRegs->config |= HPET_CONF_MASK_ENABLED; 117 else 118 sHPETRegs->config &= ~HPET_CONF_MASK_ENABLED; 119 return B_OK; 120 } 121 122 123 static status_t 124 hpet_set_legacy(bool enabled) 125 { 126 if (!HPET_IS_LEGACY_CAPABLE(sHPETRegs)) { 127 dprintf("hpet_init: HPET doesn't support legacy mode. Skipping.\n"); 128 return B_NOT_SUPPORTED; 129 } 130 131 if (enabled) 132 sHPETRegs->config |= HPET_CONF_MASK_LEGACY; 133 else 134 sHPETRegs->config &= ~HPET_CONF_MASK_LEGACY; 135 136 return B_OK; 137 } 138 139 140 #ifdef TRACE_HPET 141 static void 142 hpet_dump_timer(volatile struct hpet_timer *timer) 143 { 144 dprintf("HPET Timer %ld:\n", (timer - sHPETRegs->timer)); 145 146 dprintf("\troutable IRQs: "); 147 uint32 interrupts = (uint32)HPET_GET_CAP_TIMER_ROUTE(timer); 148 for (int i = 0; i < 32; i++) { 149 if (interrupts & (1 << i)) 150 dprintf("%d ", i); 151 } 152 dprintf("\n"); 153 dprintf("\tconfiguration: 0x%llx\n", timer->config); 154 dprintf("\tFSB Enabled: %s\n", 155 timer->config & HPET_CONF_TIMER_FSB_ENABLE ? "Yes" : "No"); 156 dprintf("\tInterrupt Enabled: %s\n", 157 timer->config & HPET_CONF_TIMER_INT_ENABLE ? "Yes" : "No"); 158 dprintf("\tTimer type: %s\n", 159 timer->config & HPET_CONF_TIMER_TYPE ? "Periodic" : "OneShot"); 160 dprintf("\tInterrupt Type: %s\n", 161 timer->config & HPET_CONF_TIMER_INT_TYPE ? "Level" : "Edge"); 162 163 dprintf("\tconfigured IRQ: %lld\n", 164 HPET_GET_CONF_TIMER_INT_ROUTE(timer)); 165 166 if (timer->config & HPET_CONF_TIMER_FSB_ENABLE) { 167 dprintf("\tfsb_route[0]: 0x%llx\n", timer->fsb_route[0]); 168 dprintf("\tfsb_route[1]: 0x%llx\n", timer->fsb_route[1]); 169 } 170 } 171 #endif 172 173 174 static void 175 hpet_init_timer(volatile struct hpet_timer *timer) 176 { 177 sTimer = timer; 178 179 uint32 interrupt = 0; 180 181 sTimer->config |= (interrupt << HPET_CONF_TIMER_INT_ROUTE_SHIFT) 182 & HPET_CONF_TIMER_INT_ROUTE_MASK; 183 184 // Non-periodic mode, edge triggered 185 sTimer->config &= ~(HPET_CONF_TIMER_TYPE | HPET_CONF_TIMER_INT_TYPE); 186 187 sTimer->config &= ~HPET_CONF_TIMER_FSB_ENABLE; 188 sTimer->config &= ~HPET_CONF_TIMER_32MODE; 189 190 // Enable timer 191 sTimer->config |= HPET_CONF_TIMER_INT_ENABLE; 192 193 #ifdef TRACE_HPET 194 hpet_dump_timer(sTimer); 195 #endif 196 } 197 198 199 static status_t 200 hpet_test() 201 { 202 uint64 initialValue = sHPETRegs->u0.counter64; 203 spin(10); 204 uint64 finalValue = sHPETRegs->u0.counter64; 205 206 if (initialValue == finalValue) { 207 dprintf("hpet_test: counter does not increment\n"); 208 return B_ERROR; 209 } 210 211 return B_OK; 212 } 213 214 215 static status_t 216 hpet_init(struct kernel_args *args) 217 { 218 /* hpet_acpi_probe() through a similar "scan spots" table 219 to that of smp.cpp. 220 Seems to be the most elegant solution right now. */ 221 if (args->arch_args.hpet == NULL) 222 return B_ERROR; 223 224 if (sHPETRegs == NULL) { 225 sHPETRegs = (struct hpet_regs *)((void*)args->arch_args.hpet); 226 if (vm_map_physical_memory(B_SYSTEM_TEAM, "hpet", 227 (void **)&sHPETRegs, B_EXACT_ADDRESS, B_PAGE_SIZE, 228 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 229 (phys_addr_t)args->arch_args.hpet_phys, true) < B_OK) { 230 // Would it be better to panic here? 231 dprintf("hpet_init: Failed to map memory for the HPET registers."); 232 return B_ERROR; 233 } 234 } 235 236 sHPETPeriod = HPET_GET_PERIOD(sHPETRegs); 237 238 TRACE(("hpet_init: HPET is at %p.\n\tVendor ID: %llx, rev: %llx, period: %lld\n", 239 sHPETRegs, HPET_GET_VENDOR_ID(sHPETRegs), HPET_GET_REVID(sHPETRegs), 240 sHPETPeriod)); 241 242 status_t status = hpet_set_enabled(false); 243 if (status != B_OK) 244 return status; 245 246 status = hpet_set_legacy(true); 247 if (status != B_OK) 248 return status; 249 250 uint32 numTimers = HPET_GET_NUM_TIMERS(sHPETRegs) + 1; 251 252 TRACE(("hpet_init: HPET supports %lu timers, and is %s bits wide.\n", 253 numTimers, HPET_IS_64BIT(sHPETRegs) ? "64" : "32")); 254 255 TRACE(("hpet_init: configuration: 0x%llx, timer_interrupts: 0x%llx\n", 256 sHPETRegs->config, sHPETRegs->interrupt_status)); 257 258 if (numTimers < 3) { 259 dprintf("hpet_init: HPET does not have at least 3 timers. Skipping.\n"); 260 return B_ERROR; 261 } 262 263 #ifdef TRACE_HPET 264 for (uint32 c = 0; c < numTimers; c++) 265 hpet_dump_timer(&sHPETRegs->timer[c]); 266 #endif 267 268 hpet_init_timer(&sHPETRegs->timer[0]); 269 270 status = hpet_set_enabled(true); 271 if (status != B_OK) 272 return status; 273 274 #ifdef TEST_HPET 275 status = hpet_test(); 276 if (status != B_OK) 277 return status; 278 #endif 279 280 int32 configuredIRQ = HPET_GET_CONF_TIMER_INT_ROUTE(sTimer); 281 282 install_io_interrupt_handler(configuredIRQ, &hpet_timer_interrupt, 283 NULL, B_NO_LOCK_VECTOR); 284 285 return status; 286 } 287 -
src/system/kernel/arch/x86_64/timers/apic_timer.h
1 /* 2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 #ifndef _KERNEL_ARCH_x86_64_TIMERS_APIC_H 6 #define _KERNEL_ARCH_x86_64_TIMERS_APIC_H 7 8 #include <SupportDefs.h> 9 10 status_t apic_timer_per_cpu_init(struct kernel_args *args, int32 cpu); 11 12 #endif /* _KERNEL_ARCH_x86_64_TIMERS_APIC_H */ -
src/system/kernel/arch/x86_64/timers/pit.h
1 /* 2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 #ifndef _KERNEL_ARCH_x86_64_TIMERS_PIT_H 6 #define _KERNEL_ARCH_x86_64_TIMERS_PIT_H 7 8 #include <SupportDefs.h> 9 10 /* ports */ 11 #define PIT_CTRL 0x43 12 #define PIT_CNT0 0x40 13 #define PIT_CNT1 0x41 14 #define PIT_CNT2 0x42 15 16 /* commands */ 17 #define PIT_SELCH0 0x00 18 #define PIT_SELCH1 0x40 19 #define PIT_SELCH2 0x80 20 21 #define PIT_RWLOW 0x10 22 #define PIT_RWHIGH 0x20 23 #define PIT_RWBOTH 0x30 24 25 #define PIT_MD_INTON0 0x00 26 #define PIT_MD_ONESHOT 0x02 27 #define PIT_MD_RTGEN 0x04 28 #define PIT_MD_SQGEN 0x06 29 #define PIT_MD_SW_STRB 0x08 30 #define PIT_MD_HW_STRB 0x0A 31 32 #define PIT_BCD 0x01 33 34 #define PIT_LATCH 0x00 35 36 #define PIT_READ 0xF0 37 #define PIT_CNT 0x20 38 #define PIT_STAT 0x10 39 40 #define PIT_CLOCK_RATE 1193180 41 #define PIT_MAX_TIMER_INTERVAL (0xffff * 1000000ll / PIT_CLOCK_RATE) 42 43 /* Method Prototypes */ 44 static int pit_get_prio(void); 45 static status_t pit_set_hardware_timer(bigtime_t relativeTimeout); 46 static status_t pit_clear_hardware_timer(void); 47 static status_t pit_init(struct kernel_args *args); 48 49 #endif /* _KERNEL_ARCH_x86_64_TIMERS_PIT_H */ -
src/system/kernel/arch/x86_64/timers/x86_64_apic.cpp
1 /* 2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. 3 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 #include <timer.h> 11 #include <arch/x86_64/timer.h> 12 13 #include <int.h> 14 #include <arch/x86_64/apic.h> 15 16 #include <arch/cpu.h> 17 #include <arch/smp.h> 18 19 #include "apic_timer.h" 20 21 22 /* Method Prototypes */ 23 static int apic_timer_get_priority(); 24 static status_t apic_timer_set_hardware_timer(bigtime_t relativeTimeout); 25 static status_t apic_timer_clear_hardware_timer(); 26 static status_t apic_timer_init(struct kernel_args *args); 27 28 static uint32 sApicTicsPerSec = 0; 29 30 struct timer_info gAPICTimer = { 31 "APIC", 32 &apic_timer_get_priority, 33 &apic_timer_set_hardware_timer, 34 &apic_timer_clear_hardware_timer, 35 &apic_timer_init 36 }; 37 38 39 static int 40 apic_timer_get_priority() 41 { 42 return 3; 43 } 44 45 46 static int32 47 apic_timer_interrupt(void *data) 48 { 49 return timer_interrupt(); 50 } 51 52 53 #define MIN_TIMEOUT 1 54 55 static status_t 56 apic_timer_set_hardware_timer(bigtime_t relativeTimeout) 57 { 58 if (relativeTimeout < MIN_TIMEOUT) 59 relativeTimeout = MIN_TIMEOUT; 60 61 // calculation should be ok, since it's going to be 64-bit 62 uint32 ticks = ((relativeTimeout * sApicTicsPerSec) / 1000000); 63 64 cpu_status state = disable_interrupts(); 65 66 uint32 config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer 67 apic_write(APIC_LVT_TIMER, config); 68 69 apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer 70 71 config = apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the timer 72 apic_write(APIC_LVT_TIMER, config); 73 74 //TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n", 75 // config, relativeTimeout, sApicTicsPerSec, ticks)); 76 77 apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up 78 79 restore_interrupts(state); 80 81 return B_OK; 82 } 83 84 85 static status_t 86 apic_timer_clear_hardware_timer() 87 { 88 cpu_status state = disable_interrupts(); 89 90 uint32 config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; 91 // mask the timer 92 apic_write(APIC_LVT_TIMER, config); 93 94 apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer 95 96 restore_interrupts(state); 97 return B_OK; 98 } 99 100 101 static status_t 102 apic_timer_init(struct kernel_args *args) 103 { 104 if (!apic_available()) 105 return B_ERROR; 106 107 sApicTicsPerSec = args->arch_args.apic_time_cv_factor; 108 install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, 109 &apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR); 110 111 return B_OK; 112 } 113 114 115 status_t 116 apic_timer_per_cpu_init(struct kernel_args *args, int32 cpu) 117 { 118 /* setup timer */ 119 uint32 config = apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK; 120 config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked 121 apic_write(APIC_LVT_TIMER, config); 122 123 apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock 124 125 config = apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0; 126 config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1 127 apic_write(APIC_TIMER_DIVIDE_CONFIG, config); 128 return B_OK; 129 } -
src/system/kernel/arch/x86_64/timers/x86_64_pit.cpp
1 /* 2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. 3 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 #include <timer.h> 11 #include <arch/x86_64/timer.h> 12 13 #include <arch/int.h> 14 #include <arch/cpu.h> 15 16 #include "pit.h" 17 18 static bool sPITTimerInitialized = false; 19 20 struct timer_info gPITTimer = { 21 "PIT", 22 &pit_get_prio, 23 &pit_set_hardware_timer, 24 &pit_clear_hardware_timer, 25 &pit_init 26 }; 27 28 29 static int 30 pit_get_prio(void) 31 { 32 return 1; 33 } 34 35 36 static int32 37 pit_timer_interrupt(void *data) 38 { 39 return timer_interrupt(); 40 } 41 42 43 static status_t 44 pit_set_hardware_timer(bigtime_t relativeTimeout) 45 { 46 uint16 nextEventClocks; 47 48 if (relativeTimeout <= 0) 49 nextEventClocks = 2; 50 else if (relativeTimeout < PIT_MAX_TIMER_INTERVAL) 51 nextEventClocks = relativeTimeout * PIT_CLOCK_RATE / 1000000; 52 else 53 nextEventClocks = 0xffff; 54 55 out8(PIT_SELCH0 | PIT_RWBOTH | PIT_MD_INTON0, PIT_CTRL); 56 out8(nextEventClocks & 0xff, PIT_CNT0); 57 out8((nextEventClocks >> 8) & 0xff, PIT_CNT0); 58 59 arch_int_enable_io_interrupt(0); 60 return B_OK; 61 } 62 63 64 static status_t 65 pit_clear_hardware_timer(void) 66 { 67 arch_int_disable_io_interrupt(0); 68 return B_OK; 69 } 70 71 72 static status_t 73 pit_init(struct kernel_args *args) 74 { 75 if (sPITTimerInitialized) { 76 return B_OK; 77 } 78 79 install_io_interrupt_handler(0, &pit_timer_interrupt, NULL, 0); 80 pit_clear_hardware_timer(); 81 82 sPITTimerInitialized = true; 83 84 return B_OK; 85 } -
src/system/kernel/arch/x86_64/arch_debug.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. 5 * Distributed under the terms of the MIT License. 6 * 7 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 8 * Distributed under the terms of the NewOS License. 9 */ 10 11 #include <KernelExport.h> 12 13 #include <arch/debug.h> 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 18 #include <TypeConstants.h> 19 20 #include <cpu.h> 21 #include <debug.h> 22 #include <debug_heap.h> 23 #include <elf.h> 24 #include <kernel.h> 25 #include <kimage.h> 26 #include <thread.h> 27 #include <vm/vm.h> 28 #include <vm/vm_types.h> 29 #include <vm/VMAddressSpace.h> 30 #include <vm/VMArea.h> 31 32 #include <arch_cpu.h> 33 34 35 struct stack_frame { 36 struct stack_frame *previous; 37 addr_t return_address; 38 }; 39 40 #define NUM_PREVIOUS_LOCATIONS 32 41 42 43 static status_t 44 lookup_symbol(struct thread* thread, addr_t address, addr_t *_baseAddress, 45 const char **_symbolName, const char **_imageName, bool *_exactMatch) 46 { 47 status_t status = B_ENTRY_NOT_FOUND; 48 49 if (IS_KERNEL_ADDRESS(address)) { 50 // a kernel symbol 51 status = elf_debug_lookup_symbol_address(address, _baseAddress, 52 _symbolName, _imageName, _exactMatch); 53 } else if (thread != NULL && thread->team != NULL) { 54 // try a lookup using the userland runtime loader structures 55 status = elf_debug_lookup_user_symbol_address(thread->team, address, 56 _baseAddress, _symbolName, _imageName, _exactMatch); 57 58 if (status != B_OK) { 59 // try to locate the image in the images loaded into user space 60 status = image_debug_lookup_user_symbol_address(thread->team, 61 address, _baseAddress, _symbolName, _imageName, _exactMatch); 62 } 63 } 64 65 return status; 66 } 67 68 69 static bool 70 is_double_fault_stack_address(int32 cpu, addr_t address) 71 { 72 size_t size; 73 addr_t bottom = (addr_t)x86_64_get_double_fault_stack(cpu, &size); 74 return address >= bottom && address < bottom + size; 75 } 76 77 78 static bool 79 is_kernel_stack_address(struct thread* thread, addr_t address) 80 { 81 // We don't have a thread pointer in the early boot process, but then we are 82 // on the kernel stack for sure. 83 if (thread == NULL) 84 return IS_KERNEL_ADDRESS(address); 85 86 // Also in the early boot process we might have a thread structure, but it 87 // might not have its kernel stack attributes set yet. 88 if (thread->kernel_stack_top == 0) 89 return IS_KERNEL_ADDRESS(address); 90 91 return (address >= thread->kernel_stack_base 92 && address < thread->kernel_stack_top) 93 || (thread->cpu != NULL 94 && is_double_fault_stack_address(thread->cpu->cpu_num, address)); 95 } 96 97 98 static bool 99 is_iframe(struct thread* thread, addr_t frame) 100 { 101 if (!is_kernel_stack_address(thread, frame)) 102 return false; 103 104 addr_t previousFrame = *(addr_t*)frame; 105 return ((previousFrame & ~IFRAME_TYPE_MASK) == 0 && previousFrame != 0); 106 } 107 108 109 static struct iframe * 110 find_previous_iframe(struct thread *thread, addr_t frame) 111 { 112 // iterate backwards through the stack frames, until we hit an iframe 113 while (is_kernel_stack_address(thread, frame)) { 114 if (is_iframe(thread, frame)) 115 return (struct iframe*)frame; 116 117 frame = *(addr_t*)frame; 118 } 119 120 return NULL; 121 } 122 123 static struct iframe* 124 get_previous_iframe(struct thread* thread, struct iframe* frame) 125 { 126 if (frame == NULL) 127 return NULL; 128 129 return find_previous_iframe(thread, frame->rbp); 130 } 131 132 static struct iframe* 133 get_current_iframe(struct thread* thread) 134 { 135 if (thread == thread_get_current_thread()) 136 return x86_64_get_current_iframe(); 137 138 addr_t rbp = thread->arch_info.current_stack.rsp[2]; 139 // NOTE: This doesn't work, if the thread is running (on another CPU). 140 return find_previous_iframe(thread, rbp); 141 } 142 143 uint64* 144 find_debug_variable(const char* variableName, bool& settable) 145 { 146 struct iframe* frame = get_current_iframe(debug_get_debugged_thread()); 147 if (frame == NULL) 148 return NULL; 149 150 settable = false; 151 152 if (strcmp(variableName, "gs") == 0) { 153 return &frame->gs; 154 } else if (strcmp(variableName, "fs") == 0) { 155 return &frame->fs; 156 } else if (strcmp(variableName, "es") == 0) { 157 return &frame->es; 158 } else if (strcmp(variableName, "ds") == 0) { 159 return &frame->ds; 160 } else if (strcmp(variableName, "cs") == 0) { 161 return &frame->cs; 162 } else if (strcmp(variableName, "rdi") == 0) { 163 settable = true; 164 return &frame->rdi; 165 } else if (strcmp(variableName, "rsi") == 0) { 166 settable = true; 167 return &frame->rsi; 168 } else if (strcmp(variableName, "rbp") == 0) { 169 settable = true; 170 return &frame->rbp; 171 } else if (strcmp(variableName, "rsp") == 0) { 172 settable = true; 173 return &frame->rsp; 174 } else if (strcmp(variableName, "rbx") == 0) { 175 settable = true; 176 return &frame->rbx; 177 } else if (strcmp(variableName, "rdx") == 0) { 178 settable = true; 179 return &frame->rdx; 180 } else if (strcmp(variableName, "rcx") == 0) { 181 settable = true; 182 return &frame->rcx; 183 } else if (strcmp(variableName, "rax") == 0) { 184 settable = true; 185 return &frame->rax; 186 } else if (strcmp(variableName, "r8") == 0) { 187 settable = true; 188 return &frame->r8; 189 } else if (strcmp(variableName, "r9") == 0) { 190 settable = true; 191 return &frame->r9; 192 } else if (strcmp(variableName, "r10") == 0) { 193 settable = true; 194 return &frame->r10; 195 } else if (strcmp(variableName, "r11") == 0) { 196 settable = true; 197 return &frame->r11; 198 } else if (strcmp(variableName, "r12") == 0) { 199 settable = true; 200 return &frame->r12; 201 } else if (strcmp(variableName, "r13") == 0) { 202 settable = true; 203 return &frame->r13; 204 } else if (strcmp(variableName, "r14") == 0) { 205 settable = true; 206 return &frame->r14; 207 } else if (strcmp(variableName, "r15") == 0) { 208 settable = true; 209 return &frame->r15; 210 } else if (strcmp(variableName, "orig_rax") == 0) { 211 settable = true; 212 return &frame->orig_rax; 213 } else if (strcmp(variableName, "orig_rdx") == 0) { 214 settable = true; 215 return &frame->orig_rdx; 216 } else if (strcmp(variableName, "rip") == 0) { 217 settable = true; 218 return &frame->rip; 219 } else if (strcmp(variableName, "rflags") == 0) { 220 settable = true; 221 return (uint64*)(&frame->flags); 222 } 223 224 if (IFRAME_IS_USER(frame)) { 225 if (strcmp(variableName, "user_rsp") == 0) { 226 settable = true; 227 return &frame->user_rsp; 228 } else if (strcmp(variableName, "user_ss") == 0) { 229 return &frame->user_ss; 230 } 231 } 232 233 return NULL; 234 } 235 236 237 static void 238 print_iframe(struct iframe *frame) 239 { 240 bool isUser = IFRAME_IS_USER(frame); 241 kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame, 242 isUser ? (uint64*)(frame + 1) : &frame->user_rsp); 243 244 kprintf(" rax 0x%-9llx rbx 0x%-9llx rcx 0x%-9llx rdx 0x%llx\n", 245 frame->rax, frame->rbx, frame->rcx, frame->rdx); 246 kprintf(" rsi 0x%-9llx rdi 0x%-9llx rbp 0x%-9llx rsp 0x%llx\n", 247 frame->rsi, frame->rdi, frame->rbp, frame->rsp); 248 kprintf(" rip 0x%-9llx eflags 0x%-9lx", frame->rip, frame->flags); 249 if (isUser) { 250 // from user space 251 kprintf("user rsp 0x%llx", frame->user_rsp); 252 } 253 kprintf("\n"); 254 kprintf(" vector: 0x%llx, error code: 0x%llx\n", frame->vector, 255 frame->error_code); 256 } 257 258 259 static bool 260 setup_for_thread(char *arg, struct thread **_thread, uint64 *_rbp, 261 uint64 *_oldPageDirectory) 262 { 263 struct thread *thread = NULL; 264 265 if (arg != NULL) { 266 thread_id id = strtoul(arg, NULL, 0); 267 thread = thread_get_thread_struct_locked(id); 268 if (thread == NULL) { 269 kprintf("could not find thread %ld\n", id); 270 return false; 271 } 272 273 if (id != thread_get_current_thread_id()) { 274 // switch to the page directory of the new thread to be 275 // able to follow the stack trace into userland 276 uint32 newPageDirectory = x86_64_next_page_directory( 277 thread_get_current_thread(), thread); 278 279 if (newPageDirectory != 0) { 280 read_cr3(*_oldPageDirectory); 281 write_cr3(newPageDirectory); 282 } 283 284 if (thread->state == B_THREAD_RUNNING) { 285 // The thread is currently running on another CPU. 286 if (thread->cpu == NULL) 287 return false; 288 arch_debug_registers* registers = debug_get_debug_registers( 289 thread->cpu->cpu_num); 290 if (registers == NULL) 291 return false; 292 *_rbp = registers->rbp; 293 } else { 294 // read %ebp from the thread's stack stored by a pushad 295 *_rbp = thread->arch_info.current_stack.rsp[2]; 296 } 297 } else 298 thread = NULL; 299 } 300 301 if (thread == NULL) { 302 // if we don't have a thread yet, we want the current one 303 // (ebp has been set by the caller for this case already) 304 thread = thread_get_current_thread(); 305 } 306 307 *_thread = thread; 308 return true; 309 } 310 311 312 void 313 arch_debug_save_registers(struct arch_debug_registers* registers) 314 { 315 // get the caller's frame pointer 316 stack_frame* frame = (stack_frame*)x86_64_read_rbp(); 317 registers->rbp = (addr_t)frame->previous; 318 } 319 320 321 static bool 322 is_calling(struct thread *thread, addr_t rip, const char *pattern, 323 addr_t start, addr_t end) 324 { 325 if (pattern == NULL) 326 return rip >= start && rip < end; 327 328 if (!IS_KERNEL_ADDRESS(rip)) 329 return false; 330 331 const char *symbol; 332 if (lookup_symbol(thread, rip, NULL, &symbol, NULL, NULL) != B_OK) 333 return false; 334 335 return strstr(symbol, pattern); 336 } 337 338 339 static status_t 340 get_next_frame_no_debugger(addr_t rbp, addr_t *_next, addr_t *_rip) 341 { 342 // TODO: Do this more efficiently in assembly. 343 stack_frame frame; 344 if (user_memcpy(&frame, (void*)rbp, sizeof(frame)) != B_OK) 345 return B_BAD_ADDRESS; 346 347 *_rip = frame.return_address; 348 *_next = (addr_t)frame.previous; 349 350 return B_OK; 351 } 352 353 354 bool 355 arch_debug_contains_call(struct thread *thread, const char *symbol, 356 addr_t start, addr_t end) 357 { 358 DebuggedThreadSetter threadSetter(thread); 359 360 addr_t rbp; 361 if (thread == thread_get_current_thread()) 362 rbp = x86_64_read_rbp(); 363 else { 364 if (thread->state == B_THREAD_RUNNING) { 365 // The thread is currently running on another CPU. 366 if (thread->cpu == NULL) 367 return false; 368 arch_debug_registers* registers = debug_get_debug_registers( 369 thread->cpu->cpu_num); 370 if (registers == NULL) 371 return false; 372 rbp = registers->rbp; 373 } else { 374 // thread not running 375 rbp = thread->arch_info.current_stack.rsp[2]; 376 } 377 } 378 379 for (;;) { 380 if (!is_kernel_stack_address(thread, rbp)) 381 break; 382 383 if (is_iframe(thread, rbp)) { 384 struct iframe *frame = (struct iframe *)rbp; 385 386 if (is_calling(thread, frame->rip, symbol, start, end)) 387 return true; 388 389 rbp = frame->rbp; 390 } else { 391 addr_t rip, nextRbp; 392 393 if (get_next_frame_no_debugger(rbp, &nextRbp, &rip) != B_OK 394 || rip == 0 || rbp == 0) 395 break; 396 397 if (is_calling(thread, rip, symbol, start, end)) 398 return true; 399 400 rbp = nextRbp; 401 } 402 403 if (rbp == 0) 404 break; 405 } 406 407 return false; 408 } 409 410 411 void * 412 arch_debug_get_caller(void) 413 { 414 struct stack_frame *frame = (struct stack_frame *)x86_64_read_rbp(); 415 return (void *)frame->previous->return_address; 416 } 417 418 419 void* 420 arch_debug_get_interrupt_pc(bool* _isSyscall) 421 { 422 struct iframe* frame = get_current_iframe(debug_get_debugged_thread()); 423 if (frame == NULL) 424 return NULL; 425 426 if (_isSyscall != NULL) 427 *_isSyscall = frame->vector == 99; 428 429 return (void*)(addr_t)frame->rip; 430 } 431 432 433 bool 434 arch_is_debug_variable_defined(const char* variableName) 435 { 436 bool settable; 437 return find_debug_variable(variableName, settable); 438 } 439 440 441 status_t 442 arch_set_debug_variable(const char* variableName, uint64 value) 443 { 444 bool settable; 445 uint64* variable = find_debug_variable(variableName, settable); 446 if (variable == NULL) 447 return B_ENTRY_NOT_FOUND; 448 449 if (!settable) 450 return B_NOT_ALLOWED; 451 452 *variable = (uint64)value; 453 return B_OK; 454 } 455 456 457 status_t 458 arch_get_debug_variable(const char* variableName, uint64* value) 459 { 460 bool settable; 461 uint64* variable = find_debug_variable(variableName, settable); 462 if (variable == NULL) 463 return B_ENTRY_NOT_FOUND; 464 465 *value = *variable; 466 return B_OK; 467 } 468 469 /* 470 void 471 arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer, 472 void (*function)(void*), void* parameter) 473 474 moved to arch_x86_64.S 475 */ 476 477 478 void 479 arch_debug_unset_current_thread(void) 480 { 481 write_dr3(NULL); 482 } 483 484 485 static void 486 set_debug_argument_variable(int32 index, uint64 value) 487 { 488 char name[8]; 489 snprintf(name, sizeof(name), "_arg%ld", index); 490 set_debug_variable(name, value); 491 } 492 493 494 template<typename Type> 495 static Type 496 read_function_argument_value(void* argument, bool& _valueKnown) 497 { 498 Type value; 499 if (debug_memcpy(B_CURRENT_TEAM, &value, argument, sizeof(Type)) == B_OK) { 500 _valueKnown = true; 501 return value; 502 } 503 504 _valueKnown = false; 505 return 0; 506 } 507 508 509 static status_t 510 print_demangled_call(const char* image, const char* symbol, addr_t args, 511 bool noObjectMethod, bool addDebugVariables) 512 { 513 static const size_t kBufferSize = 256; 514 char* buffer = (char*)debug_malloc(kBufferSize); 515 if (buffer == NULL) 516 return B_NO_MEMORY; 517 518 bool isObjectMethod; 519 const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize, 520 &isObjectMethod); 521 if (name == NULL) { 522 debug_free(buffer); 523 return B_ERROR; 524 } 525 526 uint64* arg = (uint64*)args; 527 528 if (noObjectMethod) 529 isObjectMethod = false; 530 if (isObjectMethod) { 531 const char* lastName = strrchr(name, ':') - 1; 532 int namespaceLength = lastName - name; 533 534 uint32 argValue = 0; 535 if (debug_memcpy(B_CURRENT_TEAM, &argValue, arg, 4) == B_OK) { 536 kprintf("<%s> %.*s<\33[32m%#" B_PRIx32 "\33[0m>%s", image, 537 namespaceLength, name, argValue, lastName); 538 } else 539 kprintf("<%s> %.*s<???>%s", image, namespaceLength, name, lastName); 540 541 if (addDebugVariables) 542 set_debug_variable("_this", argValue); 543 arg++; 544 } else 545 kprintf("<%s> %s", image, name); 546 547 kprintf("("); 548 549 size_t length; 550 int32 type, i = 0; 551 uint32 cookie = 0; 552 while (debug_get_next_demangled_argument(&cookie, symbol, buffer, 553 kBufferSize, &type, &length) == B_OK) { 554 if (i++ > 0) 555 kprintf(", "); 556 557 // retrieve value and type identifier 558 559 uint64 value; 560 bool valueKnown = false; 561 562 switch (type) { 563 case B_INT64_TYPE: 564 value = read_function_argument_value<int64>(arg, valueKnown); 565 if (valueKnown) 566 kprintf("int64: \33[34m%Ld\33[0m", value); 567 break; 568 case B_INT32_TYPE: 569 value = read_function_argument_value<int32>(arg, valueKnown); 570 if (valueKnown) 571 kprintf("int32: \33[34m%ld\33[0m", (int32)value); 572 break; 573 case B_INT16_TYPE: 574 value = read_function_argument_value<int16>(arg, valueKnown); 575 if (valueKnown) 576 kprintf("int16: \33[34m%d\33[0m", (int16)value); 577 break; 578 case B_INT8_TYPE: 579 value = read_function_argument_value<int8>(arg, valueKnown); 580 if (valueKnown) 581 kprintf("int8: \33[34m%d\33[0m", (int8)value); 582 break; 583 case B_UINT64_TYPE: 584 value = read_function_argument_value<uint64>(arg, valueKnown); 585 if (valueKnown) { 586 kprintf("uint64: \33[34m%#Lx\33[0m", value); 587 if (value < 0x100000) 588 kprintf(" (\33[34m%Lu\33[0m)", value); 589 } 590 break; 591 case B_UINT32_TYPE: 592 value = read_function_argument_value<uint32>(arg, valueKnown); 593 if (valueKnown) { 594 kprintf("uint32: \33[34m%#lx\33[0m", (uint32)value); 595 if (value < 0x100000) 596 kprintf(" (\33[34m%lu\33[0m)", (uint32)value); 597 } 598 break; 599 case B_UINT16_TYPE: 600 value = read_function_argument_value<uint16>(arg, valueKnown); 601 if (valueKnown) { 602 kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)", 603 (uint16)value, (uint16)value); 604 } 605 break; 606 case B_UINT8_TYPE: 607 value = read_function_argument_value<uint8>(arg, valueKnown); 608 if (valueKnown) { 609 kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)", 610 (uint8)value, (uint8)value); 611 } 612 break; 613 case B_BOOL_TYPE: 614 value = read_function_argument_value<uint8>(arg, valueKnown); 615 if (valueKnown) 616 kprintf("\33[34m%s\33[0m", value ? "true" : "false"); 617 break; 618 default: 619 if (buffer[0]) 620 kprintf("%s: ", buffer); 621 622 if (length == 4) { 623 value = read_function_argument_value<uint32>(arg, 624 valueKnown); 625 if (valueKnown) { 626 if (value == 0 627 && (type == B_POINTER_TYPE || type == B_REF_TYPE)) 628 kprintf("NULL"); 629 else 630 kprintf("\33[34m%#lx\33[0m", (uint32)value); 631 } 632 break; 633 } 634 635 636 if (length == 8) { 637 value = read_function_argument_value<uint64>(arg, 638 valueKnown); 639 } else 640 value = (uint64)arg; 641 642 if (valueKnown) 643 kprintf("\33[34m%#Lx\33[0m", value); 644 break; 645 } 646 647 if (!valueKnown) 648 kprintf("???"); 649 650 if (valueKnown && type == B_STRING_TYPE) { 651 if (value == 0) 652 kprintf(" \33[31m\"<NULL>\"\33[0m"); 653 else if (debug_strlcpy(B_CURRENT_TEAM, buffer, (char*)value, 654 kBufferSize) < B_OK) { 655 kprintf(" \33[31m\"<???>\"\33[0m"); 656 } else 657 kprintf(" \33[36m\"%s\"\33[0m", buffer); 658 } 659 660 if (addDebugVariables) 661 set_debug_argument_variable(i, value); 662 arg = (uint64*)((uint8*)arg + length); 663 } 664 665 debug_free(buffer); 666 667 kprintf(")"); 668 return B_OK; 669 } 670 671 672 static void 673 print_call(struct thread *thread, addr_t rip, addr_t rbp, addr_t nextRbp, 674 int32 argCount) 675 { 676 const char *symbol, *image; 677 addr_t baseAddress; 678 bool exactMatch; 679 status_t status; 680 bool demangled = false; 681 int64 *arg = (int64 *)(nextRbp + 8); 682 683 status = lookup_symbol(thread, rip, &baseAddress, &symbol, &image, 684 &exactMatch); 685 686 kprintf("%08lx %08lx ", rbp, rip); 687 688 if (status == B_OK) { 689 if (symbol != NULL) { 690 if (exactMatch && (argCount == 0 || argCount == -1)) { 691 status = print_demangled_call(image, symbol, (addr_t)arg, 692 argCount == -1, true); 693 if (status == B_OK) 694 demangled = true; 695 } 696 if (!demangled) { 697 kprintf("<%s>:%s%s", image, symbol, 698 exactMatch ? "" : " (nearest)"); 699 } 700 } else { 701 kprintf("<%s@%p>:unknown + 0x%04lx", image, 702 (void *)baseAddress, rip - baseAddress); 703 } 704 } else { 705 VMArea *area = NULL; 706 if (thread->team->address_space != NULL) 707 area = thread->team->address_space->LookupArea(rip); 708 if (area != NULL) { 709 kprintf("%ld:%s@%p + %#lx", area->id, area->name, 710 (void *)area->Base(), rip - area->Base()); 711 } 712 } 713 714 if (!demangled) { 715 kprintf("("); 716 717 for (int32 i = 0; i < argCount; i++) { 718 if (i > 0) 719 kprintf(", "); 720 kprintf("%#llx", *arg); 721 if (*arg > -0x10000 && *arg < 0x10000) 722 kprintf(" (%lld)", *arg); 723 724 set_debug_argument_variable(i + 1, *(uint32 *)arg); 725 arg++; 726 } 727 728 kprintf(")\n"); 729 } else 730 kprintf("\n"); 731 732 set_debug_variable("_frame", nextRbp); 733 } 734 735 736 static int 737 dump_iframes(int argc, char **argv) 738 { 739 static const char* usage = "usage: %s [ <thread id> ]\n" 740 "Prints the iframe stack for the current, respectively the specified\n" 741 "thread.\n" 742 " <thread id> - The ID of the thread for which to print the iframe\n" 743 " stack.\n"; 744 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 745 kprintf(usage, argv[0]); 746 return 0; 747 } 748 749 struct thread *thread = NULL; 750 751 if (argc < 2) { 752 thread = thread_get_current_thread(); 753 } else if (argc == 2) { 754 thread_id id = strtoul(argv[1], NULL, 0); 755 thread = thread_get_thread_struct_locked(id); 756 if (thread == NULL) { 757 kprintf("could not find thread %ld\n", id); 758 return 0; 759 } 760 } else if (argc > 2) { 761 kprintf(usage, argv[0]); 762 return 0; 763 } 764 765 if (thread != NULL) 766 kprintf("iframes for thread %ld \"%s\"\n", thread->id, thread->name); 767 768 DebuggedThreadSetter threadSetter(thread); 769 770 struct iframe* frame = find_previous_iframe(thread, x86_64_read_rbp()); 771 while (frame != NULL) { 772 print_iframe(frame); 773 frame = get_previous_iframe(thread, frame); 774 } 775 776 return 0; 777 } 778 779 780 static status_t 781 get_next_frame_debugger(addr_t rbp, addr_t *_next, addr_t *_rip) 782 { 783 stack_frame frame; 784 if (debug_memcpy(B_CURRENT_TEAM, &frame, (void*)rbp, sizeof(frame)) != B_OK) 785 return B_BAD_ADDRESS; 786 787 *_rip = frame.return_address; 788 *_next = (addr_t)frame.previous; 789 790 return B_OK; 791 } 792 793 794 static int 795 show_call(int argc, char **argv) 796 { 797 static const char* usage 798 = "usage: %s [ <thread id> ] <call index> [ -<arg count> ]\n" 799 "Prints a function call with parameters of the current, respectively\n" 800 "the specified thread.\n" 801 " <thread id> - The ID of the thread for which to print the call.\n" 802 " <call index> - The index of the call in the stack trace.\n" 803 " <arg count> - The number of call arguments to print (use 'c' to\n" 804 " force the C++ demangler to use class methods,\n" 805 " use 'd' to disable demangling).\n"; 806 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 807 kprintf(usage, argv[0]); 808 return 0; 809 } 810 811 struct thread *thread = NULL; 812 uint64 oldPageDirectory = 0; 813 uint64 rbp = x86_64_read_rbp(); 814 int32 argCount = 0; 815 816 if (argc >= 2 && argv[argc - 1][0] == '-') { 817 if (argv[argc - 1][1] == 'c') 818 argCount = -1; 819 else if (argv[argc - 1][1] == 'd') 820 argCount = -2; 821 else 822 argCount = strtoul(argv[argc - 1] + 1, NULL, 0); 823 824 if (argCount < -2 || argCount > 16) { 825 kprintf("Invalid argument count \"%ld\".\n", argCount); 826 return 0; 827 } 828 argc--; 829 } 830 831 if (argc < 2 || argc > 3) { 832 kprintf(usage, argv[0]); 833 return 0; 834 } 835 836 if (!setup_for_thread(argc == 3 ? argv[1] : NULL, &thread, &rbp, 837 &oldPageDirectory)) 838 return 0; 839 840 DebuggedThreadSetter threadSetter(thread); 841 842 int32 callIndex = strtoul(argv[argc == 3 ? 2 : 1], NULL, 0); 843 844 if (thread != NULL) 845 kprintf("thread %ld, %s\n", thread->id, thread->name); 846 847 bool onKernelStack = true; 848 849 for (int32 index = 0; index <= callIndex; index++) { 850 onKernelStack = onKernelStack 851 && is_kernel_stack_address(thread, rbp); 852 853 if (onKernelStack && is_iframe(thread, rbp)) { 854 struct iframe *frame = (struct iframe *)rbp; 855 856 if (index == callIndex) 857 print_call(thread, frame->rip, rbp, frame->rbp, argCount); 858 859 rbp = frame->rbp; 860 } else { 861 addr_t rip, nextRbp; 862 863 if (get_next_frame_debugger(rbp, &nextRbp, &rip) != B_OK) { 864 kprintf("%08llx -- read fault\n", rbp); 865 break; 866 } 867 868 if (rip == 0 || rbp == 0) 869 break; 870 871 if (index == callIndex) 872 print_call(thread, rip, rbp, nextRbp, argCount); 873 874 rbp = nextRbp; 875 } 876 877 if (rbp == 0) 878 break; 879 } 880 881 if (oldPageDirectory != 0) { 882 // switch back to the previous page directory to not cause any troubles 883 write_cr3(oldPageDirectory); 884 } 885 886 return 0; 887 } 888 889 890 static void 891 print_stack_frame(struct thread *thread, addr_t rip, addr_t rbp, addr_t nextRbp, 892 int32 callIndex, bool demangle) 893 { 894 const char *symbol, *image; 895 addr_t baseAddress; 896 bool exactMatch; 897 status_t status; 898 addr_t diff; 899 900 diff = nextRbp - rbp; 901 902 // kernel space/user space switch 903 if (diff & 0x80000000) 904 diff = 0; 905 906 status = lookup_symbol(thread, rip, &baseAddress, &symbol, &image, 907 &exactMatch); 908 909 kprintf("%2ld %08lx (+%4ld) %08lx ", callIndex, rbp, diff, rip); 910 911 if (status == B_OK) { 912 if (exactMatch && demangle) { 913 status = print_demangled_call(image, symbol, nextRbp + 8, false, 914 false); 915 } 916 917 if (!exactMatch || !demangle || status != B_OK) { 918 if (symbol != NULL) { 919 kprintf("<%s>:%s%s", image, symbol, 920 exactMatch ? "" : " (nearest)"); 921 } else 922 kprintf("<%s@%p>:unknown", image, (void *)baseAddress); 923 } 924 925 kprintf(" + 0x%04lx\n", rip - baseAddress); 926 } else { 927 VMArea *area = NULL; 928 if (thread != NULL && thread->team != NULL 929 && thread->team->address_space != NULL) { 930 area = thread->team->address_space->LookupArea(rip); 931 } 932 if (area != NULL) { 933 kprintf("%ld:%s@%p + %#lx\n", area->id, area->name, 934 (void*)area->Base(), rip - area->Base()); 935 } else 936 kprintf("\n"); 937 } 938 } 939 940 941 static bool 942 already_visited(uint64 *visited, int32 *_last, int32 *_num, uint64 rbp) 943 { 944 int32 last = *_last; 945 int32 num = *_num; 946 int32 i; 947 948 for (i = 0; i < num; i++) { 949 if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) % NUM_PREVIOUS_LOCATIONS] == rbp) 950 return true; 951 } 952 953 *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; 954 visited[last] = rbp; 955 956 if (num < NUM_PREVIOUS_LOCATIONS) 957 *_num = num + 1; 958 959 return false; 960 } 961 962 963 static int 964 stack_trace(int argc, char **argv) 965 { 966 static const char* usage = "usage: %s [-d] [ <thread id> ]\n" 967 "Prints a stack trace for the current, respectively the specified\n" 968 "thread.\n" 969 " -d - Disables the demangling of the symbols.\n" 970 " <thread id> - The ID of the thread for which to print the stack\n" 971 " trace.\n"; 972 bool demangle = true; 973 int32 threadIndex = 1; 974 if (argc > 1 && !strcmp(argv[1], "-d")) { 975 demangle = false; 976 threadIndex++; 977 } 978 979 if (argc > threadIndex + 1 980 || (argc == 2 && strcmp(argv[1], "--help") == 0)) { 981 kprintf(usage, argv[0]); 982 return 0; 983 } 984 985 uint64 previousLocations[NUM_PREVIOUS_LOCATIONS]; 986 struct thread *thread = NULL; 987 uint64 oldPageDirectory = 0; 988 uint64 rbp = x86_64_read_rbp(); 989 int32 num = 0, last = 0; 990 991 if (!setup_for_thread(argc == threadIndex + 1 ? argv[threadIndex] : NULL, 992 &thread, &rbp, &oldPageDirectory)) 993 return 0; 994 995 DebuggedThreadSetter threadSetter(thread); 996 997 if (thread != NULL) { 998 kprintf("stack trace for thread %ld \"%s\"\n", thread->id, 999 thread->name); 1000 1001 kprintf(" kernel stack: %p to %p\n", 1002 (void *)thread->kernel_stack_base, 1003 (void *)(thread->kernel_stack_top)); 1004 if (thread->user_stack_base != 0) { 1005 kprintf(" user stack: %p to %p\n", 1006 (void *)thread->user_stack_base, 1007 (void *)(thread->user_stack_base + thread->user_stack_size)); 1008 } 1009 } 1010 1011 kprintf("frame caller <image>:function + offset\n"); 1012 1013 bool onKernelStack = true; 1014 1015 for (int32 callIndex = 0;; callIndex++) { 1016 onKernelStack = onKernelStack 1017 && is_kernel_stack_address(thread, rbp); 1018 1019 if (onKernelStack && is_iframe(thread, rbp)) { 1020 struct iframe *frame = (struct iframe *)rbp; 1021 1022 print_iframe(frame); 1023 print_stack_frame(thread, frame->rip, rbp, frame->rbp, callIndex, 1024 demangle); 1025 1026 rbp = frame->rbp; 1027 } else { 1028 addr_t rip, nextRbp; 1029 1030 if (get_next_frame_debugger(rbp, &nextRbp, &rip) != B_OK) { 1031 kprintf("%08llx -- read fault\n", rbp); 1032 break; 1033 } 1034 1035 if (rip == 0 || rbp == 0) 1036 break; 1037 1038 print_stack_frame(thread, rip, rbp, nextRbp, callIndex, demangle); 1039 rbp = nextRbp; 1040 } 1041 1042 if (already_visited(previousLocations, &last, &num, rbp)) { 1043 kprintf("circular stack frame: %p!\n", (void *)rbp); 1044 break; 1045 } 1046 if (rbp == 0) 1047 break; 1048 } 1049 1050 if (oldPageDirectory != 0) { 1051 // switch back to the previous page directory to no cause any troubles 1052 write_cr3(oldPageDirectory); 1053 } 1054 1055 return 0; 1056 } 1057 1058 1059 void 1060 arch_debug_stack_trace(void) 1061 { 1062 stack_trace(0, NULL); 1063 } 1064 1065 1066 static int 1067 cmd_in_context(int argc, char** argv) 1068 { 1069 if (argc != 2) { 1070 print_debugger_command_usage(argv[0]); 1071 return 0; 1072 } 1073 1074 // get the thread ID 1075 const char* commandLine = argv[1]; 1076 char threadIDString[16]; 1077 if (parse_next_debug_command_argument(&commandLine, threadIDString, 1078 sizeof(threadIDString)) != B_OK) { 1079 kprintf("Failed to parse thread ID.\n"); 1080 return 0; 1081 } 1082 1083 if (commandLine == NULL) { 1084 print_debugger_command_usage(argv[0]); 1085 return 0; 1086 } 1087 1088 uint64 threadID; 1089 if (!evaluate_debug_expression(threadIDString, &threadID, false)) 1090 return 0; 1091 1092 // get the thread 1093 struct thread* thread = thread_get_thread_struct_locked(threadID); 1094 if (thread == NULL) { 1095 kprintf("Could not find thread with ID \"%s\".\n", threadIDString); 1096 return 0; 1097 } 1098 1099 // switch the page directory, if necessary 1100 uint32 oldPageDirectory = 0; 1101 if (thread != thread_get_current_thread()) { 1102 uint32 newPageDirectory = x86_64_next_page_directory( 1103 thread_get_current_thread(), thread); 1104 1105 if (newPageDirectory != 0) { 1106 read_cr3(oldPageDirectory); 1107 write_cr3(newPageDirectory); 1108 } 1109 } 1110 1111 // execute the command 1112 { 1113 DebuggedThreadSetter threadSetter(thread); 1114 evaluate_debug_command(commandLine); 1115 } 1116 1117 // reset the page directory 1118 if (oldPageDirectory) 1119 write_cr3(oldPageDirectory); 1120 1121 return 0; 1122 } 1123 1124 1125 status_t 1126 arch_debug_init(kernel_args *args) 1127 { 1128 // at this stage, the debugger command system is alive 1129 1130 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 1131 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 1132 add_debugger_command("sc", &stack_trace, 1133 "Stack crawl for current thread (or any other)"); 1134 add_debugger_command("iframe", &dump_iframes, 1135 "Dump iframes for the specified thread"); 1136 add_debugger_command("call", &show_call, "Show call with arguments"); 1137 add_debugger_command_etc("in_context", &cmd_in_context, 1138 "Executes a command in the context of a given thread", 1139 "<thread ID> <command> ...\n" 1140 "Executes a command in the context of a given thread.\n", 1141 B_KDEBUG_DONT_PARSE_ARGUMENTS); 1142 1143 return B_NO_ERROR; 1144 } 1145 1146 int32 1147 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, 1148 int32 skipIframes, int32 skipFrames, uint32 flags) 1149 { 1150 // Keep skipping normal stack frames until we've skipped the iframes we're 1151 // supposed to skip. 1152 if (skipIframes > 0) 1153 skipFrames = INT_MAX; 1154 1155 struct thread* thread = thread_get_current_thread(); 1156 int32 count = 0; 1157 addr_t rbp = x86_64_read_rbp(); 1158 bool onKernelStack = true; 1159 1160 while (rbp != 0 && count < maxCount) { 1161 onKernelStack = onKernelStack 1162 && is_kernel_stack_address(thread, rbp); 1163 if (!onKernelStack && (flags & STACK_TRACE_USER) == 0) 1164 break; 1165 1166 addr_t rip; 1167 addr_t nextRbp; 1168 1169 if (onKernelStack && is_iframe(thread, rbp)) { 1170 struct iframe *frame = (struct iframe*)rbp; 1171 rip = frame->rip; 1172 nextRbp = frame->rbp; 1173 1174 if (skipIframes > 0) { 1175 if (--skipIframes == 0) 1176 skipFrames = 0; 1177 } 1178 } else { 1179 if (get_next_frame_no_debugger(rbp, &nextRbp, &rip) != B_OK) 1180 break; 1181 } 1182 1183 if (skipFrames <= 0 1184 && ((flags & STACK_TRACE_KERNEL) != 0 || onKernelStack)) { 1185 returnAddresses[count++] = rip; 1186 } else 1187 skipFrames--; 1188 1189 rbp = nextRbp; 1190 } 1191 1192 return count; 1193 } -
src/system/kernel/arch/x86_64/arch_cpu.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2007, François Revol, revol@free.fr. 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. 9 * Distributed under the terms of the MIT License. 10 * 11 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 12 * Distributed under the terms of the NewOS License. 13 */ 14 15 16 #include <cpu.h> 17 18 #include <string.h> 19 #include <stdlib.h> 20 #include <stdio.h> 21 22 #include <ACPI.h> 23 24 #include <boot_device.h> 25 #include <commpage.h> 26 #include <debug.h> 27 #include <elf.h> 28 #include <smp.h> 29 #include <tls.h> 30 #include <vm/vm.h> 31 #include <vm/vm_types.h> 32 #include <vm/VMAddressSpace.h> 33 34 #include <arch_system_info.h> 35 //#include <arch/x86/selector.h> 36 #include <boot/kernel_args.h> 37 38 #include "interrupts.h" 39 40 41 #define CR0_CACHE_DISABLE (1UL << 30) 42 #define CR0_NOT_WRITE_THROUGH (1UL << 29) 43 #define CR0_FPU_EMULATION (1UL << 2) 44 #define CR0_MONITOR_FPU (1UL << 1) 45 46 #define CR4_OS_FXSR (1UL << 9) 47 #define CR4_OS_XMM_EXCEPTION (1UL << 10) 48 49 struct set_mtrrs_parameter { 50 const x86_64_mtrr_info* infos; 51 uint32 count; 52 uint8 defaultType; 53 }; 54 55 56 void (*gX86SwapFPUFunc)(void *oldState, const void *newState); 57 58 segment_descriptor *gGDT = NULL; 59 60 static uint32 sCpuRendezvous; 61 static uint32 sCpuRendezvous2; 62 static uint32 sCpuRendezvous3; 63 64 /* Some specials for the double fault handler */ 65 static uint8* sDoubleFaultStacks; 66 static const size_t kDoubleFaultStackSize = 4096; // size per CPU 67 68 static x86_64_cpu_module_info *sCpuModule; 69 70 71 extern "C" void memcpy_generic(void* dest, const void* source, size_t count); 72 extern int memcpy_generic_end; 73 extern "C" void memset_generic(void* dest, int value, size_t count); 74 extern int memset_generic_end; 75 76 77 x86_64_optimized_functions gOptimizedFunctions = { 78 memcpy_generic, 79 &memcpy_generic_end, 80 memset_generic, 81 &memset_generic_end 82 }; 83 84 85 void* 86 x86_64_get_double_fault_stack(int32 cpu, size_t* _size) 87 { 88 *_size = kDoubleFaultStackSize; 89 return sDoubleFaultStacks + kDoubleFaultStackSize * cpu; 90 } 91 92 93 /*! Returns the index of the current CPU. Can only be called from the double 94 fault handler. 95 */ 96 int64 97 x86_64_double_fault_get_cpu(void) 98 { 99 uint64 stack = x86_64_read_rbp(); 100 return (stack - (uint64)sDoubleFaultStacks) / kDoubleFaultStackSize; 101 } 102 103 104 void* 105 x86_64_set_tss_and_kstack(addr_t kstack) 106 { 107 get_cpu_struct()->arch.tss.sp0 = kstack; 108 return (void*)kstack; 109 } 110 111 112 /* TODO: Check code. Fix eax names and bitwidths */ 113 static int 114 detect_cpu(int currentCPU) 115 { 116 cpu_ent *cpu = get_cpu_struct(); 117 char vendorString[17]; 118 cpuid_info cpuid; 119 120 // clear out the cpu info data 121 cpu->arch.vendor = VENDOR_UNKNOWN; 122 cpu->arch.vendor_name = "UNKNOWN VENDOR"; 123 cpu->arch.feature[FEATURE_COMMON] = 0; 124 cpu->arch.feature[FEATURE_EXT] = 0; 125 cpu->arch.feature[FEATURE_EXT_AMD] = 0; 126 cpu->arch.model_name[0] = 0; 127 128 // print some fun data 129 get_current_cpuid(&cpuid, 0); 130 131 // build the vendor string 132 memset(vendorString, 0, sizeof(vendorString)); 133 memcpy(vendorString, cpuid.eax_0.vendor_id, sizeof(cpuid.eax_0.vendor_id)); 134 135 // get the family, model, stepping 136 get_current_cpuid(&cpuid, 1); 137 cpu->arch.type = cpuid.eax_1.type; 138 cpu->arch.family = cpuid.eax_1.family; 139 cpu->arch.extended_family = cpuid.eax_1.extended_family; 140 cpu->arch.model = cpuid.eax_1.model; 141 cpu->arch.extended_model = cpuid.eax_1.extended_model; 142 cpu->arch.stepping = cpuid.eax_1.stepping; 143 dprintf("CPU %d: type %d family %d extended_family %d model %d " 144 "extended_model %d stepping %d, string '%s'\n", 145 currentCPU, cpu->arch.type, cpu->arch.family, 146 cpu->arch.extended_family, cpu->arch.model, 147 cpu->arch.extended_model, cpu->arch.stepping, vendorString); 148 149 // figure out what vendor we have here 150 151 for (int32 i = 0; i < VENDOR_NUM; i++) { 152 if (vendor_info[i].ident_string[0] 153 && !strcmp(vendorString, vendor_info[i].ident_string[0])) { 154 cpu->arch.vendor = (x86_vendors)i; 155 cpu->arch.vendor_name = vendor_info[i].vendor; 156 break; 157 } 158 if (vendor_info[i].ident_string[1] 159 && !strcmp(vendorString, vendor_info[i].ident_string[1])) { 160 cpu->arch.vendor = (x86_vendors)i; 161 cpu->arch.vendor_name = vendor_info[i].vendor; 162 break; 163 } 164 } 165 166 // see if we can get the model name 167 get_current_cpuid(&cpuid, 0x80000000); 168 if (cpuid.eax_0.max_eax >= 0x80000004) { 169 // build the model string (need to swap ecx/edx data before copying) 170 unsigned int temp; 171 memset(cpu->arch.model_name, 0, sizeof(cpu->arch.model_name)); 172 173 get_current_cpuid(&cpuid, 0x80000002); 174 temp = cpuid.regs.edx; 175 cpuid.regs.edx = cpuid.regs.ecx; 176 cpuid.regs.ecx = temp; 177 memcpy(cpu->arch.model_name, cpuid.as_chars, sizeof(cpuid.as_chars)); 178 179 get_current_cpuid(&cpuid, 0x80000003); 180 temp = cpuid.regs.edx; 181 cpuid.regs.edx = cpuid.regs.ecx; 182 cpuid.regs.ecx = temp; 183 memcpy(cpu->arch.model_name + 16, cpuid.as_chars, 184 sizeof(cpuid.as_chars)); 185 186 get_current_cpuid(&cpuid, 0x80000004); 187 temp = cpuid.regs.edx; 188 cpuid.regs.edx = cpuid.regs.ecx; 189 cpuid.regs.ecx = temp; 190 memcpy(cpu->arch.model_name + 32, cpuid.as_chars, 191 sizeof(cpuid.as_chars)); 192 193 // some cpus return a right-justified string 194 int32 i = 0; 195 while (cpu->arch.model_name[i] == ' ') 196 i++; 197 if (i > 0) { 198 memmove(cpu->arch.model_name, &cpu->arch.model_name[i], 199 strlen(&cpu->arch.model_name[i]) + 1); 200 } 201 202 dprintf("CPU %d: vendor '%s' model name '%s'\n", 203 currentCPU, cpu->arch.vendor_name, cpu->arch.model_name); 204 } else { 205 strcpy(cpu->arch.model_name, "unknown"); 206 } 207 208 // load feature bits 209 get_current_cpuid(&cpuid, 1); 210 cpu->arch.feature[FEATURE_COMMON] = cpuid.eax_1.features; // edx 211 cpu->arch.feature[FEATURE_EXT] = cpuid.eax_1.extended_features; // ecx 212 if (cpu->arch.vendor == VENDOR_AMD) { 213 get_current_cpuid(&cpuid, 0x80000001); 214 cpu->arch.feature[FEATURE_EXT_AMD] = cpuid.regs.edx; // edx 215 } 216 217 #if DUMP_FEATURE_STRING 218 dump_feature_string(currentCPU, cpu); 219 #endif 220 221 return 0; 222 } 223 224 /* 225 static void 226 init_double_fault(int cpuNum) 227 { 228 // set up the double fault TSS 229 struct tss *tss = &gCPU[cpuNum].arch.double_fault_tss; 230 231 memset(tss, 0, sizeof(struct tss)); 232 size_t stackSize; 233 tss->sp0 = (uint64)x86_64_get_double_fault_stack(cpuNum, &stackSize); 234 tss->sp0 += stackSize; 235 tss->ss0 = KERNEL_DATA_SEG; 236 read_cr3(tss->cr3); 237 // copy the current cr3 to the double fault cr3 238 tss->rip = (uint64)&double_fault; 239 tss->es = KERNEL_DATA_SEG; 240 tss->cs = KERNEL_CODE_SEG; 241 tss->ss = KERNEL_DATA_SEG; 242 tss->rsp = tss->sp0; 243 tss->ds = KERNEL_DATA_SEG; 244 tss->fs = KERNEL_DATA_SEG; 245 tss->gs = KERNEL_DATA_SEG; 246 tss->ldt_seg_selector = 0; 247 tss->io_map_base = sizeof(struct tss); 248 249 // add TSS descriptor for this new TSS 250 uint16 tssSegmentDescriptorIndex = DOUBLE_FAULT_TSS_BASE_SEGMENT + cpuNum; 251 set_tss_descriptor(&gGDT[tssSegmentDescriptorIndex], 252 (addr_t)tss, sizeof(struct tss)); 253 254 x86_64_set_task_gate(cpuNum, 8, tssSegmentDescriptorIndex << 3); 255 } 256 */ 257 258 status_t 259 arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) 260 { 261 x86_64_write_cr0(x86_64_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU)); 262 gX86SwapFPUFunc = x86_64_fnsave_swap; 263 #if 0 264 /* TODO: Once x86_64 kernel is more stable enable SMP code */ 265 // On SMP system we want to synchronize the CPUs' TSCs, so system_time() 266 // will return consistent values. 267 if (smp_get_num_cpus() > 1) { 268 // let the first CPU prepare the rendezvous point 269 if (cpu == 0) 270 sTSCSyncRendezvous = smp_get_num_cpus() - 1; 271 272 // One CPU after the other will drop out of this loop and be caught by 273 // the loop below, until the last CPU (0) gets there. Save for +/- a few 274 // cycles the CPUs should pass the second loop at the same time. 275 while (sTSCSyncRendezvous != cpu) { 276 } 277 278 sTSCSyncRendezvous = cpu - 1; 279 280 while (sTSCSyncRendezvous != -1) { 281 } 282 283 // reset TSC to 0 284 x86_write_msr(IA32_MSR_TSC, 0); 285 } 286 #endif 287 return B_OK; 288 } 289 290 291 /*! Disable CPU caches, and invalidate them. */ 292 static void 293 disable_caches() 294 { 295 x86_64_write_cr0((x86_64_read_cr0() | CR0_CACHE_DISABLE) 296 & ~CR0_NOT_WRITE_THROUGH); 297 wbinvd(); 298 arch_cpu_global_TLB_invalidate(); 299 } 300 301 302 /*! Invalidate CPU caches, and enable them. */ 303 static void 304 enable_caches() 305 { 306 wbinvd(); 307 arch_cpu_global_TLB_invalidate(); 308 x86_64_write_cr0(x86_64_read_cr0() 309 & ~(CR0_CACHE_DISABLE | CR0_NOT_WRITE_THROUGH)); 310 } 311 312 313 314 static void 315 init_mtrrs(void *_unused, int cpu) 316 { 317 // wait until all CPUs have arrived here 318 smp_cpu_rendezvous(&sCpuRendezvous, cpu); 319 320 // One CPU has to reset sCpuRendezvous3 -- it is needed to prevent the CPU 321 // that initiated the call_all_cpus() from doing that again and clearing 322 // sCpuRendezvous2 before the last CPU has actually left the loop in 323 // smp_cpu_rendezvous(); 324 if (cpu == 0) 325 atomic_set((vint32*)&sCpuRendezvous3, 0); 326 327 disable_caches(); 328 329 sCpuModule->init_mtrrs(); 330 331 enable_caches(); 332 333 // wait until all CPUs have arrived here 334 smp_cpu_rendezvous(&sCpuRendezvous2, cpu); 335 smp_cpu_rendezvous(&sCpuRendezvous3, cpu); 336 } 337 338 339 uint32 340 x86_64_count_mtrrs(void) 341 { 342 if (sCpuModule == NULL) 343 return 0; 344 345 return sCpuModule->count_mtrrs(); 346 } 347 348 349 extern "C" void 350 init_sse(void) 351 { 352 // enable OS support for SSE 353 x86_64_write_cr4(x86_64_read_cr4() | CR4_OS_FXSR | CR4_OS_XMM_EXCEPTION); 354 x86_64_write_cr0(x86_64_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU)); 355 356 gX86SwapFPUFunc = x86_64_fxsave_swap; 357 } 358 359 360 static void 361 load_tss(int cpu) 362 { 363 short seg = ((TSS_BASE_SEGMENT + cpu) << 3) | DPL_KERNEL; 364 asm("movw %0, %%ax;" 365 "ltr %%ax;" : : "r" (seg) : "rax"); 366 } 367 368 369 status_t 370 arch_cpu_init_percpu(kernel_args *args, int cpuid) 371 { 372 detect_cpu(cpuid); 373 374 // load the TSS for this cpu 375 // note the main cpu gets initialized in arch_cpu_init_post_vm() 376 if (cpuid != 0) { 377 load_tss(cpuid); 378 379 // set the IDT 380 struct { 381 uint16 limit; 382 void* address; //TODO: Should GDT/IDT have 64bit address or 32bit address in longmode 383 } _PACKED descriptor = { 384 256 * 8 - 1, // 256 descriptors, 8 bytes each (-1 for "limit") 385 x86_64_get_idt(cpuid) 386 }; 387 388 asm volatile("lidt %0" : : "m"(descriptor)); 389 } 390 391 return 0; 392 } 393 394 395 status_t 396 arch_cpu_init(kernel_args *args) 397 { 398 // init the TSC -> system_time() conversion factors 399 400 uint32 conversionFactor = args->arch_args.system_time_cv_factor; 401 uint64 conversionFactorNsecs = (uint64)conversionFactor * 1000; 402 403 404 if (conversionFactorNsecs >> 32 != 0) { 405 // the TSC frequency is < 1 GHz, which forces us to shift the factor 406 __x86_64_setup_system_time(conversionFactor, conversionFactorNsecs >> 16, 407 true); 408 } else { 409 // the TSC frequency is >= 1 GHz 410 __x86_64_setup_system_time(conversionFactor, conversionFactorNsecs, false); 411 } 412 413 return B_OK; 414 } 415 416 417 status_t 418 arch_cpu_init_post_vm(kernel_args *args) 419 { 420 /* uint32 i; 421 422 // account for the segment descriptors 423 gGDT = (segment_descriptor *)args->arch_args.vir_gdt; 424 create_area("gdt", (void **)&gGDT, B_EXACT_ADDRESS, B_PAGE_SIZE, 425 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 426 427 // currently taken out of the build, because it's not yet used (and assumes 428 // (a fixed number of used GDT entries) 429 //i386_selector_init(gGDT); // pass the new gdt 430 431 // allocate an area for the double fault stacks 432 virtual_address_restrictions virtualRestrictions = {}; 433 virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS; 434 physical_address_restrictions physicalRestrictions = {}; 435 create_area_etc(B_SYSTEM_TEAM, "double fault stacks", 436 kDoubleFaultStackSize * smp_get_num_cpus(), B_FULL_LOCK, 437 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT, 438 &virtualRestrictions, &physicalRestrictions, 439 (void**)&sDoubleFaultStacks); 440 441 X86PagingStructures* kernelPagingStructures 442 = static_cast<X86VMTranslationMap*>( 443 VMAddressSpace::Kernel()->TranslationMap())->PagingStructures(); 444 445 // setup task-state segments 446 for (i = 0; i < args->num_cpus; i++) { 447 // initialize the regular and double fault tss stored in the per-cpu 448 // structure 449 memset(&gCPU[i].arch.tss, 0, sizeof(struct tss)); 450 gCPU[i].arch.tss.ss0 = KERNEL_DATA_SEG; 451 gCPU[i].arch.tss.io_map_base = sizeof(struct tss); 452 453 // add TSS descriptor for this new TSS 454 set_tss_descriptor(&gGDT[TSS_BASE_SEGMENT + i], 455 (addr_t)&gCPU[i].arch.tss, sizeof(struct tss)); 456 457 // initialize the double fault tss 458 init_double_fault(i); 459 460 // init active translation map 461 gCPU[i].arch.active_paging_structures = kernelPagingStructures; 462 kernelPagingStructures->AddReference(); 463 } 464 465 // set the current hardware task on cpu 0 466 load_tss(0); 467 468 // setup TLS descriptors (one for every CPU) 469 470 for (i = 0; i < args->num_cpus; i++) { 471 set_segment_descriptor(&gGDT[TLS_BASE_SEGMENT + i], 0, TLS_SIZE, 472 DT_DATA_WRITEABLE, DPL_USER); 473 } 474 475 // setup SSE2/3 support 476 init_sse(); 477 478 */ return B_OK; 479 } 480 481 status_t 482 arch_cpu_init_post_modules(kernel_args *args) 483 { 484 // initialize CPU module 485 486 void *cookie = open_module_list("cpu"); 487 488 while (true) { 489 char name[B_FILE_NAME_LENGTH]; 490 size_t nameLength = sizeof(name); 491 492 if (read_next_module_name(cookie, name, &nameLength) != B_OK 493 || get_module(name, (module_info **)&sCpuModule) == B_OK) 494 break; 495 } 496 497 close_module_list(cookie); 498 499 // initialize MTRRs if available 500 if (x86_64_count_mtrrs() > 0) { 501 sCpuRendezvous = sCpuRendezvous2 = 0; 502 call_all_cpus(&init_mtrrs, NULL); 503 } 504 505 // get optimized functions from the CPU module 506 if (sCpuModule != NULL && sCpuModule->get_optimized_functions != NULL) { 507 x86_64_optimized_functions functions; 508 memset(&functions, 0, sizeof(functions)); 509 510 sCpuModule->get_optimized_functions(&functions); 511 512 if (functions.memcpy != NULL) { 513 gOptimizedFunctions.memcpy = functions.memcpy; 514 gOptimizedFunctions.memcpy_end = functions.memcpy_end; 515 } 516 517 if (functions.memset != NULL) { 518 gOptimizedFunctions.memset = functions.memset; 519 gOptimizedFunctions.memset_end = functions.memset_end; 520 } 521 } 522 523 // put the optimized functions into the commpage 524 size_t memcpyLen = (addr_t)gOptimizedFunctions.memcpy_end 525 - (addr_t)gOptimizedFunctions.memcpy; 526 fill_commpage_entry(COMMPAGE_ENTRY_X86_64_MEMCPY, 527 (const void*)gOptimizedFunctions.memcpy, memcpyLen); 528 size_t memsetLen = (addr_t)gOptimizedFunctions.memset_end 529 - (addr_t)gOptimizedFunctions.memset; 530 fill_commpage_entry(COMMPAGE_ENTRY_X86_64_MEMSET, 531 (const void*)gOptimizedFunctions.memset, memsetLen); 532 533 // add the functions to the commpage image 534 image_id image = get_commpage_image(); 535 elf_add_memory_image_symbol(image, "commpage_memcpy", 536 ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_64_MEMCPY], memcpyLen, 537 B_SYMBOL_TYPE_TEXT); 538 elf_add_memory_image_symbol(image, "commpage_memset", 539 ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_64_MEMSET], memsetLen, 540 B_SYMBOL_TYPE_TEXT); 541 542 return B_OK; 543 } 544 545 546 void 547 arch_cpu_sync_icache(void *address, size_t len) 548 { 549 // instruction cache is always consistent on x86 and x86_64 550 } 551 552 553 void 554 arch_cpu_memory_read_barrier(void) 555 { 556 asm volatile ("lock;" : : : "memory"); 557 asm volatile ("add $0, 0(%%rsp);" : : : "memory"); 558 } 559 560 561 void 562 arch_cpu_memory_write_barrier(void) 563 { 564 asm volatile ("lock;" : : : "memory"); 565 asm volatile ("add $0, 0(%%rsp);" : : : "memory"); 566 } 567 568 569 void 570 arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) 571 { 572 int64 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE; 573 while (num_pages-- >= 0) { 574 invalidate_TLB(start); 575 start += B_PAGE_SIZE; 576 } 577 } 578 579 580 void 581 arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) 582 { 583 int i; 584 for (i = 0; i < num_pages; i++) { 585 invalidate_TLB(pages[i]); 586 } 587 } 588 589 590 void 591 arch_cpu_global_TLB_invalidate(void) 592 { 593 uint32 flags = x86_64_read_cr4(); 594 595 if (flags & IA32_CR4_GLOBAL_PAGES) { 596 // disable and reenable the global pages to flush all TLBs regardless 597 // of the global page bit 598 x86_64_write_cr4(flags & ~IA32_CR4_GLOBAL_PAGES); 599 x86_64_write_cr4(flags | IA32_CR4_GLOBAL_PAGES); 600 } else { 601 cpu_status state = disable_interrupts(); 602 arch_cpu_user_TLB_invalidate(); 603 restore_interrupts(state); 604 } 605 } 606 607 608 ssize_t 609 arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) 610 { 611 int fromLength = 0; 612 addr_t oldFaultHandler = *faultHandler; 613 614 // this check is to trick the gcc4 compiler and have it keep the error label 615 if (to == NULL && size > 0) 616 goto error; 617 618 *faultHandler = (addr_t)&&error; 619 620 if (size > 0) { 621 to[--size] = '\0'; 622 // copy 623 for ( ; size; size--, fromLength++, to++, from++) { 624 if ((*to = *from) == '\0') 625 break; 626 } 627 } 628 // count any leftover from chars 629 while (*from++ != '\0') { 630 fromLength++; 631 } 632 633 *faultHandler = oldFaultHandler; 634 return fromLength; 635 636 error: 637 *faultHandler = oldFaultHandler; 638 return B_BAD_ADDRESS; 639 } 640 641 642 status_t 643 arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) 644 { 645 char *xs = (char *)s; 646 addr_t oldFaultHandler = *faultHandler; 647 648 // this check is to trick the gcc4 compiler and have it keep the error label 649 if (s == NULL) 650 goto error; 651 652 *faultHandler = (addr_t)&&error; 653 654 while (count--) 655 *xs++ = c; 656 657 *faultHandler = oldFaultHandler; 658 return 0; 659 660 error: 661 *faultHandler = oldFaultHandler; 662 return B_BAD_ADDRESS; 663 } 664 665 666 static status_t 667 acpi_shutdown(bool reboot) 668 { 669 if (debug_debugger_running() || !are_interrupts_enabled()) 670 return B_ERROR; 671 672 acpi_module_info* acpi; 673 if (get_module(B_ACPI_MODULE_NAME, (module_info**)&acpi) != B_OK) 674 return B_NOT_SUPPORTED; 675 676 status_t status; 677 if (reboot) { 678 status = acpi->reboot(); 679 } else { 680 status = acpi->prepare_sleep_state(ACPI_POWER_STATE_OFF, NULL, 0); 681 if (status == B_OK) { 682 //cpu_status state = disable_interrupts(); 683 status = acpi->enter_sleep_state(ACPI_POWER_STATE_OFF); 684 //restore_interrupts(state); 685 } 686 } 687 688 put_module(B_ACPI_MODULE_NAME); 689 return status; 690 } 691 692 693 status_t 694 arch_cpu_shutdown(bool reboot) 695 { 696 // Make sure we run on the boot CPU (apparently needed for ACPI) 697 _user_set_cpu_enabled(0, true); 698 for (int32 cpu = 1; cpu < smp_get_num_cpus(); cpu++) { 699 _user_set_cpu_enabled(cpu, false); 700 } 701 thread_yield(true); 702 703 if (acpi_shutdown(reboot) == B_OK) 704 return B_OK; 705 706 /* TODO: once APM code is in place shutdown apm here if !reboot */ 707 708 cpu_status state = disable_interrupts(); 709 710 // try to reset the system using the keyboard controller 711 out8(0xfe, 0x64); 712 713 // Give some time to the controller to do its job (0.5s) 714 snooze(500000); 715 716 // if that didn't help, try it this way 717 // reboot(); /* TODO: write a function for arch_x86_64.S */ 718 719 restore_interrupts(state); 720 return B_ERROR; 721 } 722 723 724 void 725 arch_cpu_idle(void) 726 { 727 asm("hlt"); 728 } 729 730 731 static void 732 set_mtrrs(void* _parameter, int cpu) 733 { 734 set_mtrrs_parameter* parameter = (set_mtrrs_parameter*)_parameter; 735 736 // wait until all CPUs have arrived here 737 smp_cpu_rendezvous(&sCpuRendezvous, cpu); 738 739 // One CPU has to reset sCpuRendezvous3 -- it is needed to prevent the CPU 740 // that initiated the call_all_cpus() from doing that again and clearing 741 // sCpuRendezvous2 before the last CPU has actually left the loop in 742 // smp_cpu_rendezvous(); 743 if (cpu == 0) 744 atomic_set((vint32*)&sCpuRendezvous3, 0); 745 746 disable_caches(); 747 748 sCpuModule->set_mtrrs(parameter->defaultType, parameter->infos, 749 parameter->count); 750 751 enable_caches(); 752 753 // wait until all CPUs have arrived here 754 smp_cpu_rendezvous(&sCpuRendezvous2, cpu); 755 smp_cpu_rendezvous(&sCpuRendezvous3, cpu); 756 } 757 758 759 void 760 x86_64_set_mtrrs(uint8 defaultType, const x86_64_mtrr_info* infos, uint32 count) 761 { 762 if (sCpuModule == NULL) 763 return; 764 765 struct set_mtrrs_parameter parameter; 766 parameter.defaultType = defaultType; 767 parameter.infos = infos; 768 parameter.count = count; 769 770 sCpuRendezvous = sCpuRendezvous2 = 0; 771 call_all_cpus(&set_mtrrs, ¶meter); 772 } -
src/system/kernel/arch/x86_64/interrupts.h
1 /* 2 * Copyright 2005-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 #ifndef _KERNEL_ARCH_x86_64_INTERRUPTS_H 9 #define _KERNEL_ARCH_x86_64_INTERRUPTS_H 10 11 12 #ifdef __cplusplus 13 extern "C" { 14 #endif 15 16 void trap0();void trap1();void trap2();void trap3();void trap4();void trap5(); 17 void trap6();void trap7();void trap9();void trap10();void trap11(); 18 void trap12();void trap13();void trap14();void trap16();void trap17(); 19 void trap18();void trap19(); 20 21 void trap32();void trap33();void trap34();void trap35();void trap36(); 22 void trap37();void trap38();void trap39();void trap40();void trap41(); 23 void trap42();void trap43();void trap44();void trap45();void trap46(); 24 void trap47();void trap48();void trap49();void trap50();void trap51(); 25 void trap52();void trap53();void trap54();void trap55();void trap56(); 26 void trap57();void trap58();void trap59();void trap60();void trap61(); 27 void trap62();void trap63();void trap64();void trap65();void trap66(); 28 void trap67();void trap68();void trap69();void trap70();void trap71(); 29 void trap72();void trap73();void trap74();void trap75();void trap76(); 30 void trap77();void trap78();void trap79();void trap80();void trap81(); 31 void trap82();void trap83();void trap84();void trap85();void trap86(); 32 void trap87();void trap88();void trap89();void trap90();void trap91(); 33 void trap92();void trap93();void trap94();void trap95();void trap96(); 34 void trap97(); 35 36 void double_fault(); // int 8 37 void trap14_double_fault(); 38 39 void trap98(); 40 void trap99(); 41 42 void trap100();void trap101();void trap102();void trap103();void trap104(); 43 void trap105();void trap106();void trap107();void trap108();void trap109(); 44 void trap110();void trap111();void trap112();void trap113();void trap114(); 45 void trap115();void trap116();void trap117();void trap118();void trap119(); 46 void trap120();void trap121();void trap122();void trap123();void trap124(); 47 void trap125();void trap126();void trap127();void trap128();void trap129(); 48 void trap130();void trap131();void trap132();void trap133();void trap134(); 49 void trap135();void trap136();void trap137();void trap138();void trap139(); 50 void trap140();void trap141();void trap142();void trap143();void trap144(); 51 void trap145();void trap146();void trap147();void trap148();void trap149(); 52 void trap150();void trap151();void trap152();void trap153();void trap154(); 53 void trap155();void trap156();void trap157();void trap158();void trap159(); 54 void trap160();void trap161();void trap162();void trap163();void trap164(); 55 void trap165();void trap166();void trap167();void trap168();void trap169(); 56 void trap170();void trap171();void trap172();void trap173();void trap174(); 57 void trap175();void trap176();void trap177();void trap178();void trap179(); 58 void trap180();void trap181();void trap182();void trap183();void trap184(); 59 void trap185();void trap186();void trap187();void trap188();void trap189(); 60 void trap190();void trap191();void trap192();void trap193();void trap194(); 61 void trap195();void trap196();void trap197();void trap198();void trap199(); 62 void trap200();void trap201();void trap202();void trap203();void trap204(); 63 void trap205();void trap206();void trap207();void trap208();void trap209(); 64 void trap210();void trap211();void trap212();void trap213();void trap214(); 65 void trap215();void trap216();void trap217();void trap218();void trap219(); 66 void trap220();void trap221();void trap222();void trap223();void trap224(); 67 void trap225();void trap226();void trap227();void trap228();void trap229(); 68 void trap230();void trap231();void trap232();void trap233();void trap234(); 69 void trap235();void trap236();void trap237();void trap238();void trap239(); 70 void trap240();void trap241();void trap242();void trap243();void trap244(); 71 void trap245();void trap246();void trap247();void trap248();void trap249(); 72 void trap250(); 73 74 void trap251();void trap252();void trap253();void trap254();void trap255(); 75 76 #ifdef __cplusplus 77 } 78 #endif 79 80 #endif /* _KERNEL_ARCH_x86_64_INTERRUPTS_H */ -
src/system/kernel/arch/x86_64/paging/X86_64VMTranslationMap.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 5 * Distributed under the terms of the MIT License. 6 * 7 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 8 * Distributed under the terms of the NewOS License. 9 */ 10 11 12 #include "paging/X86_64VMTranslationMap.h" 13 14 #include <int.h> 15 #include <slab/Slab.h> 16 #include <thread.h> 17 #include <util/AutoLock.h> 18 #include <vm/vm_page.h> 19 #include <vm/VMAddressSpace.h> 20 #include <vm/VMCache.h> 21 22 #include "paging/X86_64PagingMethod.h" 23 #include "paging/X86_64PagingStructures.h" 24 #include "paging/x86_64_physical_page_mapper.h" 25 26 27 //#define TRACE_X86_64_VM_TRANSLATION_MAP 28 #ifdef TRACE_X86_64_VM_TRANSLATION_MAP 29 # define TRACE(x...) dprintf(x) 30 #else 31 # define TRACE(x...) ; 32 #endif 33 34 35 X86_64VMTranslationMap::X86_64VMTranslationMap() 36 : 37 fPagingStructures(NULL) 38 { 39 } 40 41 42 X86_64VMTranslationMap::~X86_64VMTranslationMap() 43 { 44 if (fPagingStructures == NULL) 45 return; 46 47 if (fPageMapper != NULL) 48 fPageMapper->Delete(); 49 50 // cycle through and free all of the user space page tables 51 52 STATIC_ASSERT(KERNEL_BASE == 0x80000000 && KERNEL_SIZE == 0x80000000); 53 // assuming 1-1 split of the address space 54 55 for (uint32 k = 0; k < 2; k++) { 56 page_directory_entry* pageDir 57 = fPagingStructures->VirtualPageDirs()[k]; 58 if (pageDir == NULL) 59 continue; 60 61 for (uint32 i = 0; i < kPageDirEntryCount; i++) { 62 if ((pageDir[i] & X86_64_PDE_PRESENT) != 0) { 63 phys_addr_t address = pageDir[i] & X86_64_PDE_ADDRESS_MASK; 64 vm_page* page = vm_lookup_page(address / B_PAGE_SIZE); 65 if (page == NULL) 66 panic("X86_64VMTranslationMap::~X86_64VMTranslationMap: " 67 "didn't find page table page: page address: %#" 68 B_PRIxPHYSADDR ", virtual base: %#" B_PRIxADDR "\n", 69 address, 70 (k * kPageDirEntryCount + i) * kPageTableRange); 71 DEBUG_PAGE_ACCESS_START(page); 72 vm_page_set_state(page, PAGE_STATE_FREE); 73 } 74 } 75 } 76 77 fPagingStructures->RemoveReference(); 78 } 79 80 81 status_t 82 X86_64VMTranslationMap::Init(bool kernel) 83 { 84 TRACE("X86_64VMTranslationMap::Init()\n"); 85 86 X86_64VMTranslationMap::Init(kernel); 87 88 fPagingStructures = new(std::nothrow) X86_64PagingStructures; 89 if (fPagingStructures == NULL) 90 return B_NO_MEMORY; 91 92 X86_64PagingMethod* method = X86_64PagingMethod::Method(); 93 94 if (kernel) { 95 // kernel 96 // get the physical page mapper 97 fPageMapper = method->KernelPhysicalPageMapper(); 98 99 // we already know the kernel pgdir mapping 100 fPagingStructures->Init(method->KernelVirtualPageDirPointerTable(), 101 method->KernelPhysicalPageDirPointerTable(), NULL, 102 method->KernelVirtualPageDirs(), method->KernelPhysicalPageDirs()); 103 } else { 104 // user 105 // allocate a physical page mapper 106 status_t error = method->PhysicalPageMapper() 107 ->CreateTranslationMapPhysicalPageMapper(&fPageMapper); 108 if (error != B_OK) 109 return error; 110 111 // The following code assumes that the kernel address space occupies the 112 // upper half of the virtual address space. This simplifies things a 113 // lot, since it allows us to just use the upper two page directories 114 // of the kernel and create two new lower page directories for the 115 // userland. 116 STATIC_ASSERT(KERNEL_BASE == 0x80000000 && KERNEL_SIZE == 0x80000000); 117 118 // allocate the page directories (both at once) 119 page_directory_entry* virtualPageDirs[4]; 120 phys_addr_t physicalPageDirs[4]; 121 virtualPageDirs[0] = (page_directory_entry*)memalign(B_PAGE_SIZE, 122 2 * B_PAGE_SIZE); 123 if (virtualPageDirs[0] == NULL) 124 return B_NO_MEMORY; 125 virtualPageDirs[1] = virtualPageDirs[0] + kPageTableEntryCount; 126 127 // clear the userland page directories 128 memset(virtualPageDirs[0], 0, 2 * B_PAGE_SIZE); 129 130 // use the upper two kernel page directories 131 for (int32 i = 2; i < 4; i++) { 132 virtualPageDirs[i] = method->KernelVirtualPageDirs()[i]; 133 physicalPageDirs[i] = method->KernelPhysicalPageDirs()[i]; 134 } 135 136 // look up the page directories' physical addresses 137 for (int32 i = 0; i < 2; i++) { 138 vm_get_page_mapping(VMAddressSpace::KernelID(), 139 (addr_t)virtualPageDirs[i], &physicalPageDirs[i]); 140 } 141 142 // allocate the PDPT -- needs to have a 32 bit physical address 143 phys_addr_t physicalPDPT; 144 void* pdptHandle; 145 page_directory_pointer_table_entry* pdpt 146 = (page_directory_pointer_table_entry*) 147 method->Allocate32BitPage(physicalPDPT, pdptHandle); 148 if (pdpt == NULL) 149 free(virtualPageDirs[0]); 150 151 // init the PDPT entries 152 for (int32 i = 0; i < 4; i++) { 153 pdpt[i] = (physicalPageDirs[i] & X86_64_PDPTE_ADDRESS_MASK) 154 | X86_64_PDPTE_PRESENT; 155 } 156 157 // init the paging structures 158 fPagingStructures->Init(pdpt, physicalPDPT, pdptHandle, virtualPageDirs, 159 physicalPageDirs); 160 } 161 162 return B_OK; 163 } 164 165 166 size_t 167 X86_64VMTranslationMap::MaxPagesNeededToMap(addr_t start, addr_t end) const 168 { 169 // If start == 0, the actual base address is not yet known to the caller and 170 // we shall assume the worst case. 171 if (start == 0) { 172 // offset the range so it has the worst possible alignment 173 start = kPageTableRange - B_PAGE_SIZE; 174 end += kPageTableRange - B_PAGE_SIZE; 175 } 176 177 return end / kPageTableRange + 1 - start / kPageTableRange; 178 } 179 180 181 status_t 182 X86_64VMTranslationMap::Map(addr_t virtualAddress, phys_addr_t physicalAddress, 183 uint32 attributes, uint32 memoryType, vm_page_reservation* reservation) 184 { 185 TRACE("X86_64VMTranslationMap::Map(): %#" B_PRIxADDR " -> %#" B_PRIxPHYSADDR 186 "\n", virtualAddress, physicalAddress); 187 188 // check to see if a page table exists for this range 189 page_directory_entry* pageDirEntry 190 = X86_64PagingMethod::PageDirEntryForAddress( 191 fPagingStructures->VirtualPageDirs(), virtualAddress); 192 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) { 193 // we need to allocate a page table 194 vm_page *page = vm_page_allocate_page(reservation, 195 PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR); 196 197 DEBUG_PAGE_ACCESS_END(page); 198 199 phys_addr_t physicalPageTable 200 = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE; 201 202 TRACE("X86_64VMTranslationMap::Map(): asked for free page for " 203 "page table: %#" B_PRIxPHYSADDR "\n", physicalPageTable); 204 205 // put it in the page dir 206 X86_64PagingMethod::PutPageTableInPageDir(pageDirEntry, 207 physicalPageTable, 208 attributes 209 | ((attributes & B_USER_PROTECTION) != 0 210 ? B_WRITE_AREA : B_KERNEL_WRITE_AREA)); 211 212 fMapCount++; 213 } 214 215 // now, fill in the page table entry 216 struct thread* thread = thread_get_current_thread(); 217 ThreadCPUPinner pinner(thread); 218 219 page_table_entry* pageTable 220 = (page_table_entry*)fPageMapper->GetPageTableAt( 221 *pageDirEntry & X86_64_PDE_ADDRESS_MASK); 222 page_table_entry* entry = pageTable 223 + virtualAddress / B_PAGE_SIZE % kPageTableEntryCount; 224 225 ASSERT_PRINT((*entry & X86_64_PTE_PRESENT) == 0, 226 "virtual address: %#" B_PRIxADDR ", existing pte: %#" B_PRIx64, 227 virtualAddress, *entry); 228 229 X86_64PagingMethod::PutPageTableEntryInTable(entry, physicalAddress, 230 attributes, memoryType, fIsKernelMap); 231 232 pinner.Unlock(); 233 234 // Note: We don't need to invalidate the TLB for this address, as previously 235 // the entry was not present and the TLB doesn't cache those entries. 236 237 fMapCount++; 238 239 return 0; 240 } 241 242 243 status_t 244 X86_64VMTranslationMap::Unmap(addr_t start, addr_t end) 245 { 246 start = ROUNDDOWN(start, B_PAGE_SIZE); 247 if (start >= end) 248 return B_OK; 249 250 TRACE("X86_64VMTranslationMap::Unmap(): %#" B_PRIxADDR " - %#" B_PRIxADDR 251 "\n", start, end); 252 253 do { 254 page_directory_entry* pageDirEntry 255 = X86_64PagingMethod::PageDirEntryForAddress( 256 fPagingStructures->VirtualPageDirs(), start); 257 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) { 258 // no page table here, move the start up to access the next page 259 // table 260 start = ROUNDUP(start + 1, kPageTableRange); 261 continue; 262 } 263 264 struct thread* thread = thread_get_current_thread(); 265 ThreadCPUPinner pinner(thread); 266 267 page_table_entry* pageTable 268 = (page_table_entry*)fPageMapper->GetPageTableAt( 269 *pageDirEntry & X86_64_PDE_ADDRESS_MASK); 270 271 uint32 index = start / B_PAGE_SIZE % kPageTableEntryCount; 272 for (; index < kPageTableEntryCount && start < end; 273 index++, start += B_PAGE_SIZE) { 274 if ((pageTable[index] & X86_64_PTE_PRESENT) == 0) { 275 // page mapping not valid 276 continue; 277 } 278 279 TRACE("X86_64VMTranslationMap::Unmap(): removing page %#" 280 B_PRIxADDR "\n", start); 281 282 page_table_entry oldEntry 283 = X86_64PagingMethod::ClearPageTableEntryFlags( 284 &pageTable[index], X86_64_PTE_PRESENT); 285 fMapCount--; 286 287 if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { 288 // Note, that we only need to invalidate the address, if the 289 // accessed flags was set, since only then the entry could have 290 // been in any TLB. 291 InvalidatePage(start); 292 } 293 } 294 } while (start != 0 && start < end); 295 296 return B_OK; 297 } 298 299 300 /*! Caller must have locked the cache of the page to be unmapped. 301 This object shouldn't be locked. 302 */ 303 status_t 304 X86_64VMTranslationMap::UnmapPage(VMArea* area, addr_t address, 305 bool updatePageQueue) 306 { 307 ASSERT(address % B_PAGE_SIZE == 0); 308 309 page_directory_entry* pageDirEntry 310 = X86_64PagingMethod::PageDirEntryForAddress( 311 fPagingStructures->VirtualPageDirs(), address); 312 313 TRACE("X86_64VMTranslationMap::UnmapPage(%#" B_PRIxADDR ")\n", address); 314 315 RecursiveLocker locker(fLock); 316 317 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) 318 return B_ENTRY_NOT_FOUND; 319 320 ThreadCPUPinner pinner(thread_get_current_thread()); 321 322 page_table_entry* pageTable 323 = (page_table_entry*)fPageMapper->GetPageTableAt( 324 *pageDirEntry & X86_64_PDE_ADDRESS_MASK); 325 326 page_table_entry oldEntry = X86_64PagingMethod::ClearPageTableEntry( 327 &pageTable[address / B_PAGE_SIZE % kPageTableEntryCount]); 328 329 pinner.Unlock(); 330 331 if ((oldEntry & X86_64_PTE_PRESENT) == 0) { 332 // page mapping not valid 333 return B_ENTRY_NOT_FOUND; 334 } 335 336 fMapCount--; 337 338 if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { 339 // Note, that we only need to invalidate the address, if the 340 // accessed flags was set, since only then the entry could have been 341 // in any TLB. 342 InvalidatePage(address); 343 344 Flush(); 345 346 // NOTE: Between clearing the page table entry and Flush() other 347 // processors (actually even this processor with another thread of the 348 // same team) could still access the page in question via their cached 349 // entry. We can obviously lose a modified flag in this case, with the 350 // effect that the page looks unmodified (and might thus be recycled), 351 // but is actually modified. 352 // In most cases this is harmless, but for vm_remove_all_page_mappings() 353 // this is actually a problem. 354 // Interestingly FreeBSD seems to ignore this problem as well 355 // (cf. pmap_remove_all()), unless I've missed something. 356 } 357 358 locker.Detach(); 359 // PageUnmapped() will unlock for us 360 361 PageUnmapped(area, (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE, 362 (oldEntry & X86_64_PTE_ACCESSED) != 0, 363 (oldEntry & X86_64_PTE_DIRTY) != 0, updatePageQueue); 364 365 return B_OK; 366 } 367 368 369 void 370 X86_64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size, 371 bool updatePageQueue) 372 { 373 if (size == 0) 374 return; 375 376 addr_t start = base; 377 addr_t end = base + size - 1; 378 379 TRACE("X86_64VMTranslationMap::UnmapPages(%p, %#" B_PRIxADDR ", %#" 380 B_PRIxADDR ")\n", area, start, end); 381 382 VMAreaMappings queue; 383 384 RecursiveLocker locker(fLock); 385 386 do { 387 page_directory_entry* pageDirEntry 388 = X86_64PagingMethod::PageDirEntryForAddress( 389 fPagingStructures->VirtualPageDirs(), start); 390 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) { 391 // no page table here, move the start up to access the next page 392 // table 393 start = ROUNDUP(start + 1, kPageTableRange); 394 continue; 395 } 396 397 struct thread* thread = thread_get_current_thread(); 398 ThreadCPUPinner pinner(thread); 399 400 page_table_entry* pageTable 401 = (page_table_entry*)fPageMapper->GetPageTableAt( 402 *pageDirEntry & X86_64_PDE_ADDRESS_MASK); 403 404 uint32 index = start / B_PAGE_SIZE % kPageTableEntryCount; 405 for (; index < kPageTableEntryCount && start < end; 406 index++, start += B_PAGE_SIZE) { 407 page_table_entry oldEntry 408 = X86_64PagingMethod::ClearPageTableEntry(&pageTable[index]); 409 if ((oldEntry & X86_64_PTE_PRESENT) == 0) 410 continue; 411 412 fMapCount--; 413 414 if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { 415 // Note, that we only need to invalidate the address, if the 416 // accessed flags was set, since only then the entry could have 417 // been in any TLB. 418 InvalidatePage(start); 419 } 420 421 if (area->cache_type != CACHE_TYPE_DEVICE) { 422 // get the page 423 vm_page* page = vm_lookup_page( 424 (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE); 425 ASSERT(page != NULL); 426 427 DEBUG_PAGE_ACCESS_START(page); 428 429 // transfer the accessed/dirty flags to the page 430 if ((oldEntry & X86_64_PTE_ACCESSED) != 0) 431 page->accessed = true; 432 if ((oldEntry & X86_64_PTE_DIRTY) != 0) 433 page->modified = true; 434 435 // remove the mapping object/decrement the wired_count of the 436 // page 437 if (area->wiring == B_NO_LOCK) { 438 vm_page_mapping* mapping = NULL; 439 vm_page_mappings::Iterator iterator 440 = page->mappings.GetIterator(); 441 while ((mapping = iterator.Next()) != NULL) { 442 if (mapping->area == area) 443 break; 444 } 445 446 ASSERT(mapping != NULL); 447 448 area->mappings.Remove(mapping); 449 page->mappings.Remove(mapping); 450 queue.Add(mapping); 451 } else 452 page->DecrementWiredCount(); 453 454 if (!page->IsMapped()) { 455 atomic_add(&gMappedPagesCount, -1); 456 457 if (updatePageQueue) { 458 if (page->Cache()->temporary) 459 vm_page_set_state(page, PAGE_STATE_INACTIVE); 460 else if (page->modified) 461 vm_page_set_state(page, PAGE_STATE_MODIFIED); 462 else 463 vm_page_set_state(page, PAGE_STATE_CACHED); 464 } 465 } 466 467 DEBUG_PAGE_ACCESS_END(page); 468 } 469 } 470 471 Flush(); 472 // flush explicitly, since we directly use the lock 473 } while (start != 0 && start < end); 474 475 // TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not 476 // really critical here, as in all cases this method is used, the unmapped 477 // area range is unmapped for good (resized/cut) and the pages will likely 478 // be freed. 479 480 locker.Unlock(); 481 482 // free removed mappings 483 bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); 484 uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY 485 | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); 486 while (vm_page_mapping* mapping = queue.RemoveHead()) 487 object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); 488 } 489 490 491 void 492 X86_64VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace, 493 bool ignoreTopCachePageFlags) 494 { 495 if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) { 496 X86_64VMTranslationMap::UnmapPages(area, area->Base(), area->Size(), 497 true); 498 return; 499 } 500 501 bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags; 502 503 RecursiveLocker locker(fLock); 504 505 VMAreaMappings mappings; 506 mappings.MoveFrom(&area->mappings); 507 508 for (VMAreaMappings::Iterator it = mappings.GetIterator(); 509 vm_page_mapping* mapping = it.Next();) { 510 vm_page* page = mapping->page; 511 page->mappings.Remove(mapping); 512 513 VMCache* cache = page->Cache(); 514 515 bool pageFullyUnmapped = false; 516 if (!page->IsMapped()) { 517 atomic_add(&gMappedPagesCount, -1); 518 pageFullyUnmapped = true; 519 } 520 521 if (unmapPages || cache != area->cache) { 522 addr_t address = area->Base() 523 + ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset); 524 525 page_directory_entry* pageDirEntry 526 = X86_64PagingMethod::PageDirEntryForAddress( 527 fPagingStructures->VirtualPageDirs(), address); 528 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) { 529 panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " 530 "has no page dir entry", page, area, address); 531 continue; 532 } 533 534 ThreadCPUPinner pinner(thread_get_current_thread()); 535 536 page_table_entry* pageTable 537 = (page_table_entry*)fPageMapper->GetPageTableAt( 538 *pageDirEntry & X86_64_PDE_ADDRESS_MASK); 539 page_table_entry oldEntry 540 = X86_64PagingMethod::ClearPageTableEntry( 541 &pageTable[address / B_PAGE_SIZE 542 % kPageTableEntryCount]); 543 544 pinner.Unlock(); 545 546 if ((oldEntry & X86_64_PTE_PRESENT) == 0) { 547 panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " 548 "has no page table entry", page, area, address); 549 continue; 550 } 551 552 // transfer the accessed/dirty flags to the page and invalidate 553 // the mapping, if necessary 554 if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { 555 page->accessed = true; 556 557 if (!deletingAddressSpace) 558 InvalidatePage(address); 559 } 560 561 if ((oldEntry & X86_64_PTE_DIRTY) != 0) 562 page->modified = true; 563 564 if (pageFullyUnmapped) { 565 DEBUG_PAGE_ACCESS_START(page); 566 567 if (cache->temporary) 568 vm_page_set_state(page, PAGE_STATE_INACTIVE); 569 else if (page->modified) 570 vm_page_set_state(page, PAGE_STATE_MODIFIED); 571 else 572 vm_page_set_state(page, PAGE_STATE_CACHED); 573 574 DEBUG_PAGE_ACCESS_END(page); 575 } 576 } 577 578 fMapCount--; 579 } 580 581 Flush(); 582 // flush explicitely, since we directly use the lock 583 584 locker.Unlock(); 585 586 bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); 587 uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY 588 | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); 589 while (vm_page_mapping* mapping = mappings.RemoveHead()) 590 object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); 591 } 592 593 594 status_t 595 X86_64VMTranslationMap::Query(addr_t virtualAddress, 596 phys_addr_t* _physicalAddress, uint32* _flags) 597 { 598 // default the flags to not present 599 *_flags = 0; 600 *_physicalAddress = 0; 601 602 // get the page directory entry 603 page_directory_entry* pageDirEntry 604 = X86_64PagingMethod::PageDirEntryForAddress( 605 fPagingStructures->VirtualPageDirs(), virtualAddress); 606 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) { 607 // no pagetable here 608 return B_OK; 609 } 610 611 // get the page table entry 612 struct thread* thread = thread_get_current_thread(); 613 ThreadCPUPinner pinner(thread); 614 615 page_table_entry* pageTable 616 = (page_table_entry*)fPageMapper->GetPageTableAt( 617 *pageDirEntry & X86_64_PDE_ADDRESS_MASK); 618 page_table_entry entry 619 = pageTable[virtualAddress / B_PAGE_SIZE % kPageTableEntryCount]; 620 621 pinner.Unlock(); 622 623 *_physicalAddress = entry & X86_64_PTE_ADDRESS_MASK; 624 625 // translate the page state flags 626 if ((entry & X86_64_PTE_USER) != 0) { 627 *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0) 628 | B_READ_AREA; 629 } 630 631 *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0) 632 | B_KERNEL_READ_AREA 633 | ((entry & X86_64_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0) 634 | ((entry & X86_64_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0) 635 | ((entry & X86_64_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0); 636 637 TRACE("X86_64VMTranslationMap::Query(%#" B_PRIxADDR ") -> %#" 638 B_PRIxPHYSADDR ":\n", *_physicalAddress, virtualAddress); 639 640 return B_OK; 641 } 642 643 644 status_t 645 X86_64VMTranslationMap::QueryInterrupt(addr_t virtualAddress, 646 phys_addr_t* _physicalAddress, uint32* _flags) 647 { 648 // default the flags to not present 649 *_flags = 0; 650 *_physicalAddress = 0; 651 652 // get the page directory entry 653 page_directory_entry* pageDirEntry 654 = X86_64PagingMethod::PageDirEntryForAddress( 655 fPagingStructures->VirtualPageDirs(), virtualAddress); 656 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) { 657 // no pagetable here 658 return B_OK; 659 } 660 661 // get the page table entry 662 page_table_entry* pageTable 663 = (page_table_entry*)X86_64PagingMethod::Method() 664 ->PhysicalPageMapper()->InterruptGetPageTableAt( 665 *pageDirEntry & X86_64_PDE_ADDRESS_MASK); 666 page_table_entry entry 667 = pageTable[virtualAddress / B_PAGE_SIZE % kPageTableEntryCount]; 668 669 *_physicalAddress = entry & X86_64_PTE_ADDRESS_MASK; 670 671 // translate the page state flags 672 if ((entry & X86_64_PTE_USER) != 0) { 673 *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0) 674 | B_READ_AREA; 675 } 676 677 *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0) 678 | B_KERNEL_READ_AREA 679 | ((entry & X86_64_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0) 680 | ((entry & X86_64_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0) 681 | ((entry & X86_64_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0); 682 683 TRACE("X86_64VMTranslationMap::Query(%#" B_PRIxADDR ") -> %#" 684 B_PRIxPHYSADDR ":\n", *_physicalAddress, virtualAddress); 685 686 return B_OK; 687 } 688 689 690 status_t 691 X86_64VMTranslationMap::Protect(addr_t start, addr_t end, uint32 attributes, 692 uint32 memoryType) 693 { 694 start = ROUNDDOWN(start, B_PAGE_SIZE); 695 if (start >= end) 696 return B_OK; 697 698 TRACE("X86_64VMTranslationMap::Protect(): %#" B_PRIxADDR " - %#" B_PRIxADDR 699 ", attributes: %#" B_PRIx32 "\n", start, end, attributes); 700 701 // compute protection flags 702 uint64 newProtectionFlags = 0; 703 if ((attributes & B_USER_PROTECTION) != 0) { 704 newProtectionFlags = X86_64_PTE_USER; 705 if ((attributes & B_WRITE_AREA) != 0) 706 newProtectionFlags |= X86_64_PTE_WRITABLE; 707 } else if ((attributes & B_KERNEL_WRITE_AREA) != 0) 708 newProtectionFlags = X86_64_PTE_WRITABLE; 709 710 do { 711 page_directory_entry* pageDirEntry 712 = X86_64PagingMethod::PageDirEntryForAddress( 713 fPagingStructures->VirtualPageDirs(), start); 714 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) { 715 // no page table here, move the start up to access the next page 716 // table 717 start = ROUNDUP(start + 1, kPageTableRange); 718 continue; 719 } 720 721 struct thread* thread = thread_get_current_thread(); 722 ThreadCPUPinner pinner(thread); 723 724 page_table_entry* pageTable 725 = (page_table_entry*)fPageMapper->GetPageTableAt( 726 *pageDirEntry & X86_64_PDE_ADDRESS_MASK); 727 728 uint32 index = start / B_PAGE_SIZE % kPageTableEntryCount; 729 for (; index < kPageTableEntryCount && start < end; 730 index++, start += B_PAGE_SIZE) { 731 page_table_entry entry = pageTable[index]; 732 if ((pageTable[index] & X86_64_PTE_PRESENT) == 0) { 733 // page mapping not valid 734 continue; 735 } 736 737 TRACE("X86_64VMTranslationMap::Protect(): protect page %#" 738 B_PRIxADDR "\n", start); 739 740 // set the new protection flags -- we want to do that atomically, 741 // without changing the accessed or dirty flag 742 page_table_entry oldEntry; 743 while (true) { 744 oldEntry = X86_64PagingMethod::TestAndSetPageTableEntry( 745 &pageTable[index], 746 (entry & ~(X86_64_PTE_PROTECTION_MASK 747 | X86_64_PTE_MEMORY_TYPE_MASK)) 748 | newProtectionFlags 749 | X86_64PagingMethod::MemoryTypeToPageTableEntryFlags( 750 memoryType), 751 entry); 752 if (oldEntry == entry) 753 break; 754 entry = oldEntry; 755 } 756 757 if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { 758 // Note, that we only need to invalidate the address, if the 759 // accessed flag was set, since only then the entry could have been 760 // in any TLB. 761 InvalidatePage(start); 762 } 763 } 764 } while (start != 0 && start < end); 765 766 return B_OK; 767 } 768 769 770 status_t 771 X86_64VMTranslationMap::ClearFlags(addr_t address, uint32 flags) 772 { 773 page_directory_entry* pageDirEntry 774 = X86_64PagingMethod::PageDirEntryForAddress( 775 fPagingStructures->VirtualPageDirs(), address); 776 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) { 777 // no pagetable here 778 return B_OK; 779 } 780 781 uint64 flagsToClear = ((flags & PAGE_MODIFIED) ? X86_64_PTE_DIRTY : 0) 782 | ((flags & PAGE_ACCESSED) ? X86_64_PTE_ACCESSED : 0); 783 784 struct thread* thread = thread_get_current_thread(); 785 ThreadCPUPinner pinner(thread); 786 787 page_table_entry* entry 788 = (page_table_entry*)fPageMapper->GetPageTableAt( 789 *pageDirEntry & X86_64_PDE_ADDRESS_MASK) 790 + address / B_PAGE_SIZE % kPageTableEntryCount; 791 792 // clear out the flags we've been requested to clear 793 page_table_entry oldEntry 794 = X86_64PagingMethod::ClearPageTableEntryFlags(entry, flagsToClear); 795 796 pinner.Unlock(); 797 798 if ((oldEntry & flagsToClear) != 0) 799 InvalidatePage(address); 800 801 return B_OK; 802 } 803 804 805 bool 806 X86_64VMTranslationMap::ClearAccessedAndModified(VMArea* area, addr_t address, 807 bool unmapIfUnaccessed, bool& _modified) 808 { 809 ASSERT(address % B_PAGE_SIZE == 0); 810 811 TRACE("X86_64VMTranslationMap32Bit::ClearAccessedAndModified(%#" B_PRIxADDR 812 ")\n", address); 813 814 page_directory_entry* pageDirEntry 815 = X86_64PagingMethod::PageDirEntryForAddress( 816 fPagingStructures->VirtualPageDirs(), address); 817 818 RecursiveLocker locker(fLock); 819 820 if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) 821 return false; 822 823 ThreadCPUPinner pinner(thread_get_current_thread()); 824 825 page_table_entry* entry 826 = (page_table_entry*)fPageMapper->GetPageTableAt( 827 *pageDirEntry & X86_64_PDE_ADDRESS_MASK) 828 + address / B_PAGE_SIZE % kPageTableEntryCount; 829 830 // perform the deed 831 page_table_entry oldEntry; 832 833 if (unmapIfUnaccessed) { 834 while (true) { 835 oldEntry = *entry; 836 if ((oldEntry & X86_64_PTE_PRESENT) == 0) { 837 // page mapping not valid 838 return false; 839 } 840 841 if (oldEntry & X86_64_PTE_ACCESSED) { 842 // page was accessed -- just clear the flags 843 oldEntry = X86_64PagingMethod::ClearPageTableEntryFlags(entry, 844 X86_64_PTE_ACCESSED | X86_64_PTE_DIRTY); 845 break; 846 } 847 848 // page hasn't been accessed -- unmap it 849 if (X86_64PagingMethod::TestAndSetPageTableEntry(entry, 0, oldEntry) 850 == oldEntry) { 851 break; 852 } 853 854 // something changed -- check again 855 } 856 } else { 857 oldEntry = X86_64PagingMethod::ClearPageTableEntryFlags(entry, 858 X86_64_PTE_ACCESSED | X86_64_PTE_DIRTY); 859 } 860 861 pinner.Unlock(); 862 863 _modified = (oldEntry & X86_64_PTE_DIRTY) != 0; 864 865 if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { 866 // Note, that we only need to invalidate the address, if the 867 // accessed flags was set, since only then the entry could have been 868 // in any TLB. 869 InvalidatePage(address); 870 Flush(); 871 872 return true; 873 } 874 875 if (!unmapIfUnaccessed) 876 return false; 877 878 // We have unmapped the address. Do the "high level" stuff. 879 880 fMapCount--; 881 882 locker.Detach(); 883 // UnaccessedPageUnmapped() will unlock for us 884 885 UnaccessedPageUnmapped(area, 886 (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE); 887 888 return false; 889 } 890 891 892 /*! Acquires the map's recursive lock, and resets the invalidate pages counter 893 in case it's the first locking recursion. 894 */ 895 bool 896 X86_64VMTranslationMap::Lock() 897 { 898 TRACE("%p->X86_64VMTranslationMap::Lock()\n", this); 899 900 recursive_lock_lock(&fLock); 901 if (recursive_lock_get_recursion(&fLock) == 1) { 902 // we were the first one to grab the lock 903 TRACE("clearing invalidated page count\n"); 904 fInvalidPagesCount = 0; 905 } 906 907 return true; 908 } 909 910 911 /*! Unlocks the map, and, if we are actually losing the recursive lock, 912 flush all pending changes of this map (ie. flush TLB caches as 913 needed). 914 */ 915 void 916 X86_64VMTranslationMap::Unlock() 917 { 918 TRACE("%p->X86_64VMTranslationMap::Unlock()\n", this); 919 920 if (recursive_lock_get_recursion(&fLock) == 1) { 921 // we're about to release it for the last time 922 Flush(); 923 } 924 925 recursive_lock_unlock(&fLock); 926 } 927 928 929 addr_t 930 X86_64VMTranslationMap::MappedSize() const 931 { 932 return fMapCount; 933 } 934 935 936 void 937 X86_64VMTranslationMap::Flush() 938 { 939 if (fInvalidPagesCount <= 0) 940 return; 941 942 struct thread* thread = thread_get_current_thread(); 943 thread_pin_to_current_cpu(thread); 944 945 if (fInvalidPagesCount > PAGE_INVALIDATE_CACHE_SIZE) { 946 // invalidate all pages 947 TRACE("flush_tmap: %d pages to invalidate, invalidate all\n", 948 fInvalidPagesCount); 949 950 if (fIsKernelMap) { 951 arch_cpu_global_TLB_invalidate(); 952 smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVALIDATE_PAGES, 0, 0, 0, 953 NULL, SMP_MSG_FLAG_SYNC); 954 } else { 955 cpu_status state = disable_interrupts(); 956 arch_cpu_user_TLB_invalidate(); 957 restore_interrupts(state); 958 959 int cpu = smp_get_current_cpu(); 960 uint32 cpuMask = PagingStructures()->active_on_cpus 961 & ~((uint32)1 << cpu); 962 if (cpuMask != 0) { 963 smp_send_multicast_ici(cpuMask, SMP_MSG_USER_INVALIDATE_PAGES, 964 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC); 965 } 966 } 967 } else { 968 TRACE("flush_tmap: %d pages to invalidate, invalidate list\n", 969 fInvalidPagesCount); 970 971 arch_cpu_invalidate_TLB_list(fInvalidPages, fInvalidPagesCount); 972 973 if (fIsKernelMap) { 974 smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_LIST, 975 (uint64)fInvalidPages, fInvalidPagesCount, 0, NULL, 976 SMP_MSG_FLAG_SYNC); 977 } else { 978 int cpu = smp_get_current_cpu(); 979 uint32 cpuMask = PagingStructures()->active_on_cpus 980 & ~((uint32)1 << cpu); 981 if (cpuMask != 0) { 982 smp_send_multicast_ici(cpuMask, SMP_MSG_INVALIDATE_PAGE_LIST, 983 (uint64)fInvalidPages, fInvalidPagesCount, 0, NULL, 984 SMP_MSG_FLAG_SYNC); 985 } 986 } 987 } 988 fInvalidPagesCount = 0; 989 990 thread_unpin_from_current_cpu(thread); 991 } -
src/system/kernel/arch/x86_64/paging/x86_64_physical_page_mapper.h
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 6 * Distributed under the terms of the MIT License. 7 */ 8 #ifndef KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_H 9 #define KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_H 10 11 12 #include <vm/VMTranslationMap.h> 13 14 15 struct kernel_args; 16 struct vm_translation_map_ops; 17 18 19 class TranslationMapPhysicalPageMapper { 20 public: 21 virtual ~TranslationMapPhysicalPageMapper(); 22 23 virtual void Delete() = 0; 24 25 virtual void* GetPageTableAt(phys_addr_t physicalAddress) = 0; 26 // Must be invoked with thread pinned to current CPU. 27 }; 28 29 30 class X86_64PhysicalPageMapper : public VMPhysicalPageMapper { 31 public: 32 virtual ~X86_64PhysicalPageMapper(); 33 34 virtual status_t CreateTranslationMapPhysicalPageMapper( 35 TranslationMapPhysicalPageMapper** _mapper) 36 = 0; 37 38 virtual void* InterruptGetPageTableAt( 39 phys_addr_t physicalAddress) = 0; 40 }; 41 42 43 #endif // KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_H -
src/system/kernel/arch/x86_64/paging/x86_64_physical_page_mapper_large_memory.h
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 6 * Distributed under the terms of the MIT License. 7 */ 8 #ifndef KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_LARGE_MEMORY_H 9 #define KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_LARGE_MEMORY_H 10 11 12 #include <OS.h> 13 14 #include <util/DoublyLinkedList.h> 15 16 17 class TranslationMapPhysicalPageMapper; 18 class X86_64PhysicalPageMapper; 19 struct kernel_args; 20 21 22 namespace X86_64LargePhysicalPageMapper { 23 24 25 struct PhysicalPageSlotPool; 26 27 28 struct PhysicalPageSlot { 29 PhysicalPageSlot* next; 30 PhysicalPageSlotPool* pool; 31 addr_t address; 32 33 inline void Map(phys_addr_t physicalAddress); 34 }; 35 36 37 struct PhysicalPageSlotPool : DoublyLinkedListLinkImpl<PhysicalPageSlotPool> { 38 39 virtual ~PhysicalPageSlotPool(); 40 41 inline bool IsEmpty() const; 42 43 inline PhysicalPageSlot* GetSlot(); 44 inline void PutSlot(PhysicalPageSlot* slot); 45 46 virtual status_t AllocatePool(PhysicalPageSlotPool*& _pool) = 0; 47 virtual void Map(phys_addr_t physicalAddress, 48 addr_t virtualAddress) = 0; 49 50 protected: 51 PhysicalPageSlot* fSlots; 52 }; 53 54 55 } 56 57 58 status_t large_memory_physical_page_ops_init(kernel_args* args, 59 X86_64LargePhysicalPageMapper::PhysicalPageSlotPool* initialPool, 60 X86_64PhysicalPageMapper*& _pageMapper, 61 TranslationMapPhysicalPageMapper*& _kernelPageMapper); 62 63 64 #endif // KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_LARGE_MEMORY_H -
src/system/kernel/arch/x86_64/paging/X86_64VMTranslationMap.h
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 #ifndef KERNEL_ARCH_X86_64_PAGING_X86_64_VM_TRANSLATION_MAP_H 7 #define KERNEL_ARCH_X86_64_PAGING_X86_64_VM_TRANSLATION_MAP_H 8 9 10 #include <vm/VMTranslationMap.h> 11 12 13 #define PAGE_INVALIDATE_CACHE_SIZE 64 14 15 16 struct X86_64PagingStructures; 17 class TranslationMapPhysicalPageMapper; 18 19 20 struct X86_64VMTranslationMap : VMTranslationMap { 21 X86_64VMTranslationMap(); 22 virtual ~X86_64VMTranslationMap(); 23 24 status_t Init(bool kernel); 25 26 virtual bool Lock(); 27 virtual void Unlock(); 28 29 virtual addr_t MappedSize() const; 30 31 virtual void Flush(); 32 33 inline void InvalidatePage(addr_t address); 34 35 inline X86_64PagingStructures* PagingStructures(); 36 37 virtual size_t MaxPagesNeededToMap(addr_t start, 38 addr_t end) const; 39 40 virtual status_t Map(addr_t virtualAddress, 41 phys_addr_t physicalAddress, 42 uint32 attributes, uint32 memoryType, 43 vm_page_reservation* reservation); 44 virtual status_t Unmap(addr_t start, addr_t end); 45 46 virtual status_t UnmapPage(VMArea* area, addr_t address, 47 bool updatePageQueue); 48 virtual void UnmapPages(VMArea* area, addr_t base, 49 size_t size, bool updatePageQueue); 50 virtual void UnmapArea(VMArea* area, 51 bool deletingAddressSpace, 52 bool ignoreTopCachePageFlags); 53 54 virtual status_t Query(addr_t virtualAddress, 55 phys_addr_t* _physicalAddress, 56 uint32* _flags); 57 virtual status_t QueryInterrupt(addr_t virtualAddress, 58 phys_addr_t* _physicalAddress, 59 uint32* _flags); 60 61 virtual status_t Protect(addr_t base, addr_t top, 62 uint32 attributes, uint32 memoryType); 63 64 virtual status_t ClearFlags(addr_t virtualAddress, 65 uint32 flags); 66 67 virtual bool ClearAccessedAndModified( 68 VMArea* area, addr_t address, 69 bool unmapIfUnaccessed, 70 bool& _modified); 71 72 protected: 73 TranslationMapPhysicalPageMapper* fPageMapper; 74 int fInvalidPagesCount; 75 addr_t fInvalidPages[PAGE_INVALIDATE_CACHE_SIZE]; 76 bool fIsKernelMap; 77 78 X86_64PagingStructures* fPagingStructures; 79 }; 80 81 82 void 83 X86_64VMTranslationMap::InvalidatePage(addr_t address) 84 { 85 if (fInvalidPagesCount < PAGE_INVALIDATE_CACHE_SIZE) 86 fInvalidPages[fInvalidPagesCount] = address; 87 88 fInvalidPagesCount++; 89 } 90 91 inline X86_64PagingStructures* 92 X86_64VMTranslationMap::PagingStructures() 93 { 94 return fPagingStructures; 95 } 96 97 #endif // KERNEL_ARCH_X86_64_PAGING_X86_64_VM_TRANSLATION_MAP_H -
src/system/kernel/arch/x86_64/paging/X86_64PagingStructures.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 6 * Distributed under the terms of the MIT License. 7 */ 8 9 10 #include "paging/X86_64PagingStructures.h" 11 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include <KernelExport.h> 16 17 #include <int.h> 18 19 #include "paging/X86_64PagingMethod.h" 20 21 22 X86_64PagingStructures::X86_64PagingStructures() 23 { 24 fVirtualPageDirs[0] = NULL; 25 } 26 27 28 X86_64PagingStructures::~X86_64PagingStructures() 29 { 30 // free the user page dirs 31 free(fVirtualPageDirs[0]); 32 33 // free the PDPT page 34 X86_64PagingMethod::Method()->Free32BitPage(fPageDirPointerTable, 35 pgdir_phys, fPageDirPointerTableHandle); 36 } 37 38 39 void 40 X86_64PagingStructures::Init( 41 page_directory_pointer_table_entry* virtualPDPT, 42 phys_addr_t physicalPDPT, void* pdptHandle, 43 page_directory_entry* const* virtualPageDirs, 44 const phys_addr_t* physicalPageDirs) 45 { 46 fPageDirPointerTable = virtualPDPT; 47 pgdir_phys = physicalPDPT; 48 fPageDirPointerTableHandle = pdptHandle; 49 memcpy(fVirtualPageDirs, virtualPageDirs, sizeof(fVirtualPageDirs)); 50 memcpy(fPhysicalPageDirs, physicalPageDirs, sizeof(fPhysicalPageDirs)); 51 } 52 53 54 void 55 X86_64PagingStructures::Delete() 56 { 57 if (are_interrupts_enabled()) 58 delete this; 59 else 60 deferred_delete(this); 61 } -
src/system/kernel/arch/x86_64/paging/paging.h
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 6 * Distributed under the terms of the MIT License. 7 */ 8 #ifndef KERNEL_ARCH_X86_64_PAGING_PAGING_H 9 #define KERNEL_ARCH_X86_64_PAGING_PAGING_H 10 11 12 #include <OS.h> 13 14 15 // page directory pointer table entry bits 16 #define X86_64_PDPTE_PRESENT 0x0000000000000001LL 17 #define X86_64_PDPTE_WRITE_THROUGH 0x0000000000000008LL 18 #define X86_64_PDPTE_CACHING_DISABLED 0x0000000000000010LL 19 #define X86_64_PDPTE_ADDRESS_MASK 0x000ffffffffff000LL 20 21 // page directory entry bits 22 #define X86_64_PDE_PRESENT 0x0000000000000001LL 23 #define X86_64_PDE_WRITABLE 0x0000000000000002LL 24 #define X86_64_PDE_USER 0x0000000000000004LL 25 #define X86_64_PDE_WRITE_THROUGH 0x0000000000000008LL 26 #define X86_64_PDE_CACHING_DISABLED 0x0000000000000010LL 27 #define X86_64_PDE_ACCESSED 0x0000000000000020LL 28 #define X86_64_PDE_IGNORED1 0x0000000000000040LL 29 #define X86_64_PDE_LARGE_PAGE 0x0000000000000080LL 30 #define X86_64_PDE_IGNORED2 0x0000000000000100LL 31 #define X86_64_PDE_IGNORED3 0x0000000000000200LL 32 #define X86_64_PDE_IGNORED4 0x0000000000000400LL 33 #define X86_64_PDE_IGNORED5 0x0000000000000800LL 34 #define X86_64_PDE_ADDRESS_MASK 0x000ffffffffff000LL 35 #define X86_64_PDE_NOT_EXECUTABLE 0x8000000000000000LL 36 37 // page table entry bits 38 #define X86_64_PTE_PRESENT 0x0000000000000001LL 39 #define X86_64_PTE_WRITABLE 0x0000000000000002LL 40 #define X86_64_PTE_USER 0x0000000000000004LL 41 #define X86_64_PTE_WRITE_THROUGH 0x0000000000000008LL 42 #define X86_64_PTE_CACHING_DISABLED 0x0000000000000010LL 43 #define X86_64_PTE_ACCESSED 0x0000000000000020LL 44 #define X86_64_PTE_DIRTY 0x0000000000000040LL 45 #define X86_64_PTE_PAT 0x0000000000000080LL 46 #define X86_64_PTE_GLOBAL 0x0000000000000100LL 47 #define X86_64_PTE_IGNORED1 0x0000000000000200LL 48 #define X86_64_PTE_IGNORED2 0x0000000000000400LL 49 #define X86_64_PTE_IGNORED3 0x0000000000000800LL 50 #define X86_64_PTE_ADDRESS_MASK 0x000ffffffffff000LL 51 #define X86_64_PTE_NOT_EXECUTABLE 0x8000000000000000LL 52 #define X86_64_PTE_PROTECTION_MASK (X86_64_PTE_WRITABLE \ 53 | X86_64_PTE_USER) 54 #define X86_64_PTE_MEMORY_TYPE_MASK (X86_64_PTE_WRITE_THROUGH \ 55 | X86_64_PTE_CACHING_DISABLED) 56 57 58 static const uint32 kPageDirEntryCount = 512; 59 static const uint32 kPageTableEntryCount = 512; 60 static const size_t kPageTableRange = kPageTableEntryCount * B_PAGE_SIZE; 61 static const size_t kPageDirRange 62 = kPageDirEntryCount * kPageTableRange; 63 64 65 typedef uint64 page_directory_pointer_table_entry; 66 typedef uint64 page_directory_entry; 67 typedef uint64 page_table_entry; 68 69 70 #endif // KERNEL_ARCH_X86_64_PAGING_PAGING_H -
src/system/kernel/arch/x86_64/paging/x86_64_physical_page_mapper.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 6 * Distributed under the terms of the MIT License. 7 */ 8 9 #include "paging/x86_64_physical_page_mapper.h" 10 11 12 TranslationMapPhysicalPageMapper::~TranslationMapPhysicalPageMapper() 13 { 14 } 15 16 17 X86_64PhysicalPageMapper::~X86_64PhysicalPageMapper() 18 { 19 } -
src/system/kernel/arch/x86_64/paging/x86_64_physical_page_mapper_large_memory.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 6 * Distributed under the terms of the MIT License. 7 */ 8 9 10 /*! Implementation of a physical page mapping strategy (PhysicalPageMapper, 11 TranslationMapPhysicalPageMapper) suitable for machines with a lot of 12 memory, i.e. more than we can afford to completely map into the kernel 13 address space. 14 15 We allocate a single page table (one page) that can map 1024 pages and 16 a corresponding virtual address space region (4 MB). Each of those 1024 17 slots can map a physical page. We reserve a fixed amount of slots per CPU. 18 They will be used for physical operations on that CPU (memset()/memcpy() 19 and {get,put}_physical_page_current_cpu()). A few slots we reserve for each 20 translation map (TranslationMapPhysicalPageMapper). Those will only be used 21 with the translation map locked, mapping a page table page. The remaining 22 slots remain in the global pool and are given out by get_physical_page(). 23 24 When we run out of slots, we allocate another page table (and virtual 25 address space region). 26 */ 27 28 29 #include "paging/x86_64_physical_page_mapper_large_memory.h" 30 31 #include <new> 32 33 #include <AutoDeleter.h> 34 35 #include <cpu.h> 36 #include <lock.h> 37 #include <smp.h> 38 #include <util/AutoLock.h> 39 #include <vm/vm.h> 40 #include <vm/vm_types.h> 41 #include <vm/VMAddressSpace.h> 42 43 #include "paging/x86_64_physical_page_mapper.h" 44 #include "paging/X86_64PagingStructures.h" 45 #include "paging/X86_64VMTranslationMap.h" 46 47 48 // The number of slots we reserve per translation map from mapping page tables. 49 // One slot would suffice, since the map is locked while mapping a page table, 50 // but we re-use several slots on a LRU-basis so that we can keep the mappings 51 // a little longer, thus avoiding re-mapping. 52 #define SLOTS_PER_TRANSLATION_MAP 4 53 54 #define USER_SLOTS_PER_CPU 16 55 #define KERNEL_SLOTS_PER_CPU 16 56 #define TOTAL_SLOTS_PER_CPU (USER_SLOTS_PER_CPU + KERNEL_SLOTS_PER_CPU + 1) 57 58 // one slot is for use in interrupts 59 60 61 using X86_64LargePhysicalPageMapper::PhysicalPageSlot; 62 using X86_64LargePhysicalPageMapper::PhysicalPageSlotPool; 63 64 65 class PhysicalPageSlotQueue { 66 public: 67 PhysicalPageSlotQueue(); 68 69 inline PhysicalPageSlot* GetSlot(); 70 inline void GetSlots(PhysicalPageSlot*& slot1, 71 PhysicalPageSlot*& slot2); 72 inline void PutSlot(PhysicalPageSlot* slot); 73 inline void PutSlots(PhysicalPageSlot* slot1, 74 PhysicalPageSlot* slot2); 75 76 private: 77 PhysicalPageSlot* fSlots; 78 ConditionVariable fFreeSlotCondition; 79 ConditionVariable fFreeSlotsCondition; 80 }; 81 82 83 struct PhysicalPageOpsCPUData { 84 PhysicalPageSlotQueue user; 85 // Used when copying from/to user memory. This can cause a page fault 86 // which might need to memcpy()/memset() a page when being handled. 87 PhysicalPageSlotQueue kernel; 88 // Used when memset()ing or when memcpy()ing memory non-user memory. 89 PhysicalPageSlot* interruptSlot; 90 91 void Init(); 92 93 private: 94 static PhysicalPageSlot* _GetInitialSlot(); 95 }; 96 97 98 // #pragma mark - 99 100 101 class LargeMemoryTranslationMapPhysicalPageMapper 102 : public TranslationMapPhysicalPageMapper { 103 public: 104 LargeMemoryTranslationMapPhysicalPageMapper(); 105 virtual ~LargeMemoryTranslationMapPhysicalPageMapper(); 106 107 status_t Init(); 108 109 virtual void Delete(); 110 111 virtual void* GetPageTableAt(phys_addr_t physicalAddress); 112 113 private: 114 struct page_slot { 115 PhysicalPageSlot* slot; 116 phys_addr_t physicalAddress; 117 cpu_mask_t valid; 118 }; 119 120 page_slot fSlots[SLOTS_PER_TRANSLATION_MAP]; 121 int32 fSlotCount; // must be a power of 2 122 int32 fNextSlot; 123 }; 124 125 126 class LargeMemoryPhysicalPageMapper : public X86_64PhysicalPageMapper { 127 public: 128 LargeMemoryPhysicalPageMapper(); 129 130 status_t Init(kernel_args* args, 131 PhysicalPageSlotPool* initialPool, 132 TranslationMapPhysicalPageMapper*& 133 _kernelPageMapper); 134 135 virtual status_t CreateTranslationMapPhysicalPageMapper( 136 TranslationMapPhysicalPageMapper** _mapper); 137 138 virtual void* InterruptGetPageTableAt( 139 phys_addr_t physicalAddress); 140 141 virtual status_t GetPage(phys_addr_t physicalAddress, 142 addr_t* virtualAddress, void** handle); 143 virtual status_t PutPage(addr_t virtualAddress, void* handle); 144 145 virtual status_t GetPageCurrentCPU(phys_addr_t physicalAddress, 146 addr_t* virtualAddress, void** handle); 147 virtual status_t PutPageCurrentCPU(addr_t virtualAddress, 148 void* handle); 149 150 virtual status_t GetPageDebug(phys_addr_t physicalAddress, 151 addr_t* virtualAddress, void** handle); 152 virtual status_t PutPageDebug(addr_t virtualAddress, 153 void* handle); 154 155 virtual status_t MemsetPhysical(phys_addr_t address, int value, 156 phys_size_t length); 157 virtual status_t MemcpyFromPhysical(void* to, phys_addr_t from, 158 size_t length, bool user); 159 virtual status_t MemcpyToPhysical(phys_addr_t to, 160 const void* from, size_t length, bool user); 161 virtual void MemcpyPhysicalPage(phys_addr_t to, 162 phys_addr_t from); 163 164 status_t GetSlot(bool canWait, 165 PhysicalPageSlot*& slot); 166 void PutSlot(PhysicalPageSlot* slot); 167 168 inline PhysicalPageSlotQueue* GetSlotQueue(int32 cpu, bool user); 169 170 private: 171 typedef DoublyLinkedList<PhysicalPageSlotPool> PoolList; 172 173 mutex fLock; 174 PoolList fEmptyPools; 175 PoolList fNonEmptyPools; 176 PhysicalPageSlot* fDebugSlot; 177 PhysicalPageSlotPool* fInitialPool; 178 LargeMemoryTranslationMapPhysicalPageMapper fKernelMapper; 179 PhysicalPageOpsCPUData fPerCPUData[B_MAX_CPU_COUNT]; 180 }; 181 182 static LargeMemoryPhysicalPageMapper sPhysicalPageMapper; 183 184 185 // #pragma mark - PhysicalPageSlot / PhysicalPageSlotPool 186 187 188 inline void 189 PhysicalPageSlot::Map(phys_addr_t physicalAddress) 190 { 191 pool->Map(physicalAddress, address); 192 } 193 194 195 PhysicalPageSlotPool::~PhysicalPageSlotPool() 196 { 197 } 198 199 200 inline bool 201 PhysicalPageSlotPool::IsEmpty() const 202 { 203 return fSlots == NULL; 204 } 205 206 207 inline PhysicalPageSlot* 208 PhysicalPageSlotPool::GetSlot() 209 { 210 PhysicalPageSlot* slot = fSlots; 211 fSlots = slot->next; 212 return slot; 213 } 214 215 216 inline void 217 PhysicalPageSlotPool::PutSlot(PhysicalPageSlot* slot) 218 { 219 slot->next = fSlots; 220 fSlots = slot; 221 } 222 223 224 // #pragma mark - PhysicalPageSlotQueue 225 226 227 PhysicalPageSlotQueue::PhysicalPageSlotQueue() 228 : 229 fSlots(NULL) 230 { 231 fFreeSlotCondition.Init(this, "physical page ops slot queue"); 232 fFreeSlotsCondition.Init(this, "physical page ops slots queue"); 233 } 234 235 236 PhysicalPageSlot* 237 PhysicalPageSlotQueue::GetSlot() 238 { 239 InterruptsLocker locker; 240 241 // wait for a free slot to turn up 242 while (fSlots == NULL) { 243 ConditionVariableEntry entry; 244 fFreeSlotCondition.Add(&entry); 245 locker.Unlock(); 246 entry.Wait(); 247 locker.Lock(); 248 } 249 250 PhysicalPageSlot* slot = fSlots; 251 fSlots = slot->next; 252 253 return slot; 254 } 255 256 257 void 258 PhysicalPageSlotQueue::GetSlots(PhysicalPageSlot*& slot1, 259 PhysicalPageSlot*& slot2) 260 { 261 InterruptsLocker locker; 262 263 // wait for two free slot to turn up 264 while (fSlots == NULL || fSlots->next == NULL) { 265 ConditionVariableEntry entry; 266 fFreeSlotsCondition.Add(&entry); 267 locker.Unlock(); 268 entry.Wait(); 269 locker.Lock(); 270 } 271 272 slot1 = fSlots; 273 slot2 = slot1->next; 274 fSlots = slot2->next; 275 } 276 277 278 void 279 PhysicalPageSlotQueue::PutSlot(PhysicalPageSlot* slot) 280 { 281 InterruptsLocker locker; 282 283 slot->next = fSlots; 284 fSlots = slot; 285 286 if (slot->next == NULL) 287 fFreeSlotCondition.NotifyAll(); 288 else if (slot->next->next == NULL) 289 fFreeSlotCondition.NotifyAll(); 290 } 291 292 293 void 294 PhysicalPageSlotQueue::PutSlots(PhysicalPageSlot* slot1, 295 PhysicalPageSlot* slot2) 296 { 297 InterruptsLocker locker; 298 299 slot1->next = slot2; 300 slot2->next = fSlots; 301 fSlots = slot1; 302 303 if (slot2->next == NULL) 304 fFreeSlotCondition.NotifyAll(); 305 else if (slot2->next->next == NULL) 306 fFreeSlotCondition.NotifyAll(); 307 } 308 309 310 // #pragma mark - PhysicalPageOpsCPUData 311 312 313 void 314 PhysicalPageOpsCPUData::Init() 315 { 316 for (int32 i = 0; i < USER_SLOTS_PER_CPU; i++) 317 user.PutSlot(_GetInitialSlot()); 318 for (int32 i = 0; i < KERNEL_SLOTS_PER_CPU; i++) 319 kernel.PutSlot(_GetInitialSlot()); 320 interruptSlot = _GetInitialSlot(); 321 } 322 323 324 /* static */ PhysicalPageSlot* 325 PhysicalPageOpsCPUData::_GetInitialSlot() 326 { 327 PhysicalPageSlot* slot; 328 status_t error = sPhysicalPageMapper.GetSlot(false, slot); 329 if (error != B_OK) { 330 panic("PhysicalPageOpsCPUData::Init(): Failed to get initial " 331 "physical page slots! Probably too many CPUs."); 332 return NULL; 333 } 334 335 return slot; 336 } 337 338 339 // #pragma mark - LargeMemoryTranslationMapPhysicalPageMapper 340 341 342 LargeMemoryTranslationMapPhysicalPageMapper 343 ::LargeMemoryTranslationMapPhysicalPageMapper() 344 : 345 fSlotCount(sizeof(fSlots) / sizeof(page_slot)), 346 fNextSlot(0) 347 { 348 memset(fSlots, 0, sizeof(fSlots)); 349 } 350 351 352 LargeMemoryTranslationMapPhysicalPageMapper 353 ::~LargeMemoryTranslationMapPhysicalPageMapper() 354 { 355 // put our slots back to the global pool 356 for (int32 i = 0; i < fSlotCount; i++) { 357 if (fSlots[i].slot != NULL) 358 sPhysicalPageMapper.PutSlot(fSlots[i].slot); 359 } 360 } 361 362 363 status_t 364 LargeMemoryTranslationMapPhysicalPageMapper::Init() 365 { 366 // get our slots from the global pool 367 for (int32 i = 0; i < fSlotCount; i++) { 368 status_t error = sPhysicalPageMapper.GetSlot(true, fSlots[i].slot); 369 if (error != B_OK) 370 return error; 371 372 // set to invalid physical address, so it won't be used accidentally 373 fSlots[i].physicalAddress = ~(phys_addr_t)0; 374 } 375 376 return B_OK; 377 } 378 379 380 void 381 LargeMemoryTranslationMapPhysicalPageMapper::Delete() 382 { 383 delete this; 384 } 385 386 387 void* 388 LargeMemoryTranslationMapPhysicalPageMapper::GetPageTableAt( 389 phys_addr_t physicalAddress) 390 { 391 ASSERT(physicalAddress % B_PAGE_SIZE == 0); 392 393 int32 currentCPU = smp_get_current_cpu(); 394 395 // maybe the address is already mapped 396 for (int32 i = 0; i < fSlotCount; i++) { 397 page_slot& slot = fSlots[i]; 398 if (slot.physicalAddress == physicalAddress) { 399 fNextSlot = (i + 1) & (fSlotCount - 1); 400 if ((slot.valid & (1 << currentCPU)) == 0) { 401 // not valid on this CPU -- invalidate the TLB entry 402 invalidate_TLB(slot.slot->address); 403 slot.valid |= 1 << currentCPU; 404 } 405 return (void*)slot.slot->address; 406 } 407 } 408 409 // not found -- need to map a fresh one 410 page_slot& slot = fSlots[fNextSlot]; 411 fNextSlot = (fNextSlot + 1) & (fSlotCount - 1); 412 413 slot.physicalAddress = physicalAddress; 414 slot.slot->Map(physicalAddress); 415 slot.valid = 1 << currentCPU; 416 417 return (void*)slot.slot->address; 418 } 419 420 421 // #pragma mark - LargeMemoryPhysicalPageMapper 422 423 424 LargeMemoryPhysicalPageMapper::LargeMemoryPhysicalPageMapper() 425 : 426 fInitialPool(NULL) 427 { 428 mutex_init(&fLock, "large memory physical page mapper"); 429 } 430 431 432 status_t 433 LargeMemoryPhysicalPageMapper::Init(kernel_args* args, 434 PhysicalPageSlotPool* initialPool, 435 TranslationMapPhysicalPageMapper*& _kernelPageMapper) 436 { 437 fInitialPool = initialPool; 438 fNonEmptyPools.Add(fInitialPool); 439 440 // get the debug slot 441 GetSlot(true, fDebugSlot); 442 443 // init the kernel translation map physical page mapper 444 status_t error = fKernelMapper.Init(); 445 if (error != B_OK) { 446 panic("LargeMemoryPhysicalPageMapper::Init(): Failed to init " 447 "kernel translation map physical page mapper!"); 448 return error; 449 } 450 _kernelPageMapper = &fKernelMapper; 451 452 // init the per-CPU data 453 int32 cpuCount = smp_get_num_cpus(); 454 for (int32 i = 0; i < cpuCount; i++) 455 fPerCPUData[i].Init(); 456 457 return B_OK; 458 } 459 460 461 status_t 462 LargeMemoryPhysicalPageMapper::CreateTranslationMapPhysicalPageMapper( 463 TranslationMapPhysicalPageMapper** _mapper) 464 { 465 LargeMemoryTranslationMapPhysicalPageMapper* mapper 466 = new(std::nothrow) LargeMemoryTranslationMapPhysicalPageMapper; 467 if (mapper == NULL) 468 return B_NO_MEMORY; 469 470 status_t error = mapper->Init(); 471 if (error != B_OK) { 472 delete mapper; 473 return error; 474 } 475 476 *_mapper = mapper; 477 return B_OK; 478 } 479 480 481 void* 482 LargeMemoryPhysicalPageMapper::InterruptGetPageTableAt( 483 phys_addr_t physicalAddress) 484 { 485 ASSERT(physicalAddress % B_PAGE_SIZE == 0); 486 487 PhysicalPageSlot* slot = fPerCPUData[smp_get_current_cpu()].interruptSlot; 488 slot->Map(physicalAddress); 489 return (void*)slot->address; 490 } 491 492 493 status_t 494 LargeMemoryPhysicalPageMapper::GetPage(phys_addr_t physicalAddress, 495 addr_t* virtualAddress, void** handle) 496 { 497 PhysicalPageSlot* slot; 498 status_t error = GetSlot(true, slot); 499 if (error != B_OK) 500 return error; 501 502 slot->Map(physicalAddress); 503 504 *handle = slot; 505 *virtualAddress = slot->address + physicalAddress % B_PAGE_SIZE; 506 507 smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_RANGE, *virtualAddress, 508 *virtualAddress, 0, NULL, SMP_MSG_FLAG_SYNC); 509 510 return B_OK; 511 } 512 513 514 status_t 515 LargeMemoryPhysicalPageMapper::PutPage(addr_t virtualAddress, void* handle) 516 { 517 PutSlot((PhysicalPageSlot*)handle); 518 return B_OK; 519 } 520 521 522 status_t 523 LargeMemoryPhysicalPageMapper::GetPageCurrentCPU(phys_addr_t physicalAddress, 524 addr_t* virtualAddress, void** handle) 525 { 526 // get a slot from the per-cpu user pool 527 PhysicalPageSlotQueue& slotQueue 528 = fPerCPUData[smp_get_current_cpu()].user; 529 PhysicalPageSlot* slot = slotQueue.GetSlot(); 530 slot->Map(physicalAddress); 531 532 *virtualAddress = slot->address + physicalAddress % B_PAGE_SIZE; 533 *handle = slot; 534 535 return B_OK; 536 } 537 538 539 status_t 540 LargeMemoryPhysicalPageMapper::PutPageCurrentCPU(addr_t virtualAddress, 541 void* handle) 542 { 543 // return the slot to the per-cpu user pool 544 PhysicalPageSlotQueue& slotQueue 545 = fPerCPUData[smp_get_current_cpu()].user; 546 slotQueue.PutSlot((PhysicalPageSlot*)handle); 547 return B_OK; 548 } 549 550 551 status_t 552 LargeMemoryPhysicalPageMapper::GetPageDebug(phys_addr_t physicalAddress, 553 addr_t* virtualAddress, void** handle) 554 { 555 fDebugSlot->Map(physicalAddress); 556 557 *handle = fDebugSlot; 558 *virtualAddress = fDebugSlot->address + physicalAddress % B_PAGE_SIZE; 559 return B_OK; 560 } 561 562 563 status_t 564 LargeMemoryPhysicalPageMapper::PutPageDebug(addr_t virtualAddress, void* handle) 565 { 566 return B_OK; 567 } 568 569 570 status_t 571 LargeMemoryPhysicalPageMapper::MemsetPhysical(phys_addr_t address, int value, 572 phys_size_t length) 573 { 574 phys_addr_t pageOffset = address % B_PAGE_SIZE; 575 576 struct thread* thread = thread_get_current_thread(); 577 ThreadCPUPinner _(thread); 578 579 PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, 580 false); 581 PhysicalPageSlot* slot = slotQueue->GetSlot(); 582 583 while (length > 0) { 584 slot->Map(address - pageOffset); 585 586 size_t toSet = min_c(length, B_PAGE_SIZE - pageOffset); 587 memset((void*)(slot->address + pageOffset), value, toSet); 588 589 length -= toSet; 590 address += toSet; 591 pageOffset = 0; 592 } 593 594 slotQueue->PutSlot(slot); 595 596 return B_OK; 597 } 598 599 600 status_t 601 LargeMemoryPhysicalPageMapper::MemcpyFromPhysical(void* _to, phys_addr_t from, 602 size_t length, bool user) 603 { 604 uint8* to = (uint8*)_to; 605 phys_addr_t pageOffset = from % B_PAGE_SIZE; 606 607 struct thread* thread = thread_get_current_thread(); 608 ThreadCPUPinner _(thread); 609 610 PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, user); 611 PhysicalPageSlot* slot = slotQueue->GetSlot(); 612 613 status_t error = B_OK; 614 615 while (length > 0) { 616 size_t toCopy = min_c(length, B_PAGE_SIZE - pageOffset); 617 618 slot->Map(from - pageOffset); 619 620 if (user) { 621 error = user_memcpy(to, (void*)(slot->address + pageOffset), 622 toCopy); 623 if (error != B_OK) 624 break; 625 } else 626 memcpy(to, (void*)(slot->address + pageOffset), toCopy); 627 628 to += toCopy; 629 from += toCopy; 630 length -= toCopy; 631 pageOffset = 0; 632 } 633 634 slotQueue->PutSlot(slot); 635 636 return error; 637 } 638 639 640 status_t 641 LargeMemoryPhysicalPageMapper::MemcpyToPhysical(phys_addr_t to, 642 const void* _from, size_t length, bool user) 643 { 644 const uint8* from = (const uint8*)_from; 645 phys_addr_t pageOffset = to % B_PAGE_SIZE; 646 647 struct thread* thread = thread_get_current_thread(); 648 ThreadCPUPinner _(thread); 649 650 PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, user); 651 PhysicalPageSlot* slot = slotQueue->GetSlot(); 652 653 status_t error = B_OK; 654 655 while (length > 0) { 656 size_t toCopy = min_c(length, B_PAGE_SIZE - pageOffset); 657 658 slot->Map(to - pageOffset); 659 660 if (user) { 661 error = user_memcpy((void*)(slot->address + pageOffset), from, 662 toCopy); 663 if (error != B_OK) 664 break; 665 } else 666 memcpy((void*)(slot->address + pageOffset), from, toCopy); 667 668 to += toCopy; 669 from += toCopy; 670 length -= toCopy; 671 pageOffset = 0; 672 } 673 674 slotQueue->PutSlot(slot); 675 676 return error; 677 } 678 679 680 void 681 LargeMemoryPhysicalPageMapper::MemcpyPhysicalPage(phys_addr_t to, 682 phys_addr_t from) 683 { 684 struct thread* thread = thread_get_current_thread(); 685 ThreadCPUPinner _(thread); 686 687 PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, 688 false); 689 PhysicalPageSlot* fromSlot; 690 PhysicalPageSlot* toSlot; 691 slotQueue->GetSlots(fromSlot, toSlot); 692 693 fromSlot->Map(from); 694 toSlot->Map(to); 695 696 memcpy((void*)toSlot->address, (void*)fromSlot->address, B_PAGE_SIZE); 697 698 slotQueue->PutSlots(fromSlot, toSlot); 699 } 700 701 702 status_t 703 LargeMemoryPhysicalPageMapper::GetSlot(bool canWait, PhysicalPageSlot*& slot) 704 { 705 MutexLocker locker(fLock); 706 707 PhysicalPageSlotPool* pool = fNonEmptyPools.Head(); 708 if (pool == NULL) { 709 if (!canWait) 710 return B_WOULD_BLOCK; 711 712 // allocate new pool 713 locker.Unlock(); 714 status_t error = fInitialPool->AllocatePool(pool); 715 if (error != B_OK) 716 return error; 717 locker.Lock(); 718 719 fNonEmptyPools.Add(pool); 720 pool = fNonEmptyPools.Head(); 721 } 722 723 slot = pool->GetSlot(); 724 725 if (pool->IsEmpty()) { 726 fNonEmptyPools.Remove(pool); 727 fEmptyPools.Add(pool); 728 } 729 730 return B_OK; 731 } 732 733 734 void 735 LargeMemoryPhysicalPageMapper::PutSlot(PhysicalPageSlot* slot) 736 { 737 MutexLocker locker(fLock); 738 739 PhysicalPageSlotPool* pool = slot->pool; 740 if (pool->IsEmpty()) { 741 fEmptyPools.Remove(pool); 742 fNonEmptyPools.Add(pool); 743 } 744 745 pool->PutSlot(slot); 746 } 747 748 749 inline PhysicalPageSlotQueue* 750 LargeMemoryPhysicalPageMapper::GetSlotQueue(int32 cpu, bool user) 751 { 752 return user ? &fPerCPUData[cpu].user : &fPerCPUData[cpu].kernel; 753 } 754 755 756 // #pragma mark - Initialization 757 758 759 status_t 760 large_memory_physical_page_ops_init(kernel_args* args, 761 X86_64LargePhysicalPageMapper::PhysicalPageSlotPool* initialPool, 762 X86_64PhysicalPageMapper*& _pageMapper, 763 TranslationMapPhysicalPageMapper*& _kernelPageMapper) 764 { 765 new(&sPhysicalPageMapper) LargeMemoryPhysicalPageMapper; 766 sPhysicalPageMapper.Init(args, initialPool, _kernelPageMapper); 767 768 _pageMapper = &sPhysicalPageMapper; 769 return B_OK; 770 } -
src/system/kernel/arch/x86_64/paging/X86_64PagingStructures.h
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. 5 * Distributed under the terms of the MIT License. 6 * 7 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 8 * Distributed under the terms of the NewOS License. 9 */ 10 #ifndef KERNEL_ARCH_X86_64_PAGING_X86_64_PAGING_STRUCTURES_H 11 #define KERNEL_ARCH_X86_64_PAGING_X86_64_PAGING_STRUCTURES_H 12 13 14 #include <SupportDefs.h> 15 16 #include <heap.h> 17 #include "paging/paging.h" 18 19 20 struct X86_64PagingStructures : DeferredDeletable { 21 uint64 pgdir_phys; 22 vint32 ref_count; 23 vint32 active_on_cpus; 24 // mask indicating on which CPUs the map is currently used 25 26 X86_64PagingStructures(); 27 virtual ~X86_64PagingStructures(); 28 29 inline void AddReference(); 30 inline void RemoveReference(); 31 32 void Init(page_directory_pointer_table_entry* 33 virtualPDPT, phys_addr_t physicalPDPT, void* pdptHandle, 34 page_directory_entry* const* virtualPageDirs, 35 const phys_addr_t* physicalPageDirs); 36 37 virtual void Delete(); 38 39 page_directory_entry* const* VirtualPageDirs() const 40 { return fVirtualPageDirs; } 41 42 private: 43 page_directory_pointer_table_entry* fPageDirPointerTable; 44 void* fPageDirPointerTableHandle; 45 page_directory_entry* fVirtualPageDirs[4]; 46 phys_addr_t fPhysicalPageDirs[4]; 47 }; 48 49 50 inline void 51 X86_64PagingStructures::AddReference() 52 { 53 atomic_add(&ref_count, 1); 54 } 55 56 57 inline void 58 X86_64PagingStructures::RemoveReference() 59 { 60 if (atomic_add(&ref_count, -1) == 1) 61 Delete(); 62 } 63 64 65 #endif // KERNEL_ARCH_X86_64_PAGING_X86_64_PAGING_STRUCTURES_H -
src/system/kernel/arch/x86_64/arch_commpage.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2007, Travis Geiselbrecht. All rights reserved. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include <string.h> 10 11 #include <KernelExport.h> 12 13 #include <commpage.h> 14 #include <cpu.h> 15 #include <elf.h> 16 #include <smp.h> 17 18 #include <SupportDefs.h> 19 20 21 extern "C" void x86_64_sysenter(); 22 23 void (*gX86_64SetSyscallStack)(addr_t stackTop) = NULL; 24 25 extern "C" void _user_syscall_int(void); 26 extern unsigned int _user_syscall_int_end; 27 extern "C" void _user_syscall_sysenter(void); 28 extern unsigned int _user_syscall_sysenter_end; 29 30 31 void 32 x86_64_set_syscall_stack(addr_t stackTop) 33 { 34 if (gX86_64SetSyscallStack != NULL) 35 gX86_64SetSyscallStack(stackTop); 36 } 37 38 39 static void 40 init_x86_64_syscall_registers(void* dummy, int cpuNum) 41 { 42 x86_64_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SEG); 43 x86_64_write_msr(IA32_MSR_SYSENTER_ESP, 0); 44 x86_64_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_64_sysenter); 45 46 gX86_64SetSyscallStack = &x86_64_set_syscall_stack; 47 } 48 49 50 static bool 51 all_cpus_have_feature(enum x86_feature_type type, int feature) 52 { 53 int i; 54 int cpuCount = smp_get_num_cpus(); 55 56 for (i = 0; i < cpuCount; i++) { 57 if (!(gCPU[i].arch.feature[type] & feature)) 58 return false; 59 } 60 61 return true; 62 } 63 64 65 status_t 66 arch_commpage_init_post_cpus(void) 67 { 68 void* syscallCode = (void *)&_user_syscall_int; 69 void* syscallCodeEnd = &_user_syscall_int_end; 70 71 // check syscall 72 if (all_cpus_have_feature(FEATURE_COMMON, IA32_FEATURE_SEP) 73 && !(gCPU[0].arch.family == 6 && gCPU[0].arch.model < 3 74 && gCPU[0].arch.stepping < 3)) { 75 // Intel sysenter/sysexit 76 dprintf("initialize_commpage_syscall(): sysenter/sysexit supported\n"); 77 78 // the code to be used in userland 79 syscallCode = (void *)&_user_syscall_sysenter; 80 syscallCodeEnd = &_user_syscall_sysenter_end; 81 82 // tell all CPUs to init their sysenter/sysexit related registers 83 call_all_cpus_sync(&init_x86_64_syscall_registers, NULL); 84 } else if (all_cpus_have_feature(FEATURE_EXT_AMD, 85 IA32_FEATURE_AMD_EXT_SYSCALL)) { 86 // AMD syscall/sysret 87 dprintf("initialize_commpage_syscall(): syscall/sysret supported " 88 "-- not yet by Haiku, though"); 89 } else { 90 // no special syscall support 91 dprintf("initialize_commpage_syscall(): no special syscall support\n"); 92 } 93 94 // fill in the table entry 95 size_t len = (size_t)((addr_t)syscallCodeEnd - (addr_t)syscallCode); 96 fill_commpage_entry(COMMPAGE_ENTRY_X86_64_SYSCALL, syscallCode, len); 97 98 // add syscall to the commpage image 99 image_id image = get_commpage_image(); 100 elf_add_memory_image_symbol(image, "commpage_syscall", 101 ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_64_SYSCALL], len, 102 B_SYMBOL_TYPE_TEXT); 103 104 return B_OK; 105 } 106 107 108 status_t 109 arch_commpage_init(void) 110 { 111 return B_OK; 112 } -
src/system/kernel/arch/x86_64/arch_int.cpp
1 /* 2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. 3 * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de. 4 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 5 * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 9 * Distributed under the terms of the NewOS License. 10 */ 11 12 13 #include <cpu.h> 14 #include <int.h> 15 #include <kscheduler.h> 16 #include <ksyscalls.h> 17 #include <smp.h> 18 #include <team.h> 19 #include <thread.h> 20 #include <vm/vm.h> 21 #include <vm/vm_priv.h> 22 23 #include <arch/cpu.h> 24 #include <arch/int.h> 25 #include <arch/smp.h> 26 #include <arch/user_debugger.h> 27 #include <arch/vm.h> 28 29 #include <arch/x86_64/apic.h> 30 #include <arch/x86_64/descriptors.h> 31 32 #include "interrupts.h" 33 #include "irq_routing_table.h" 34 35 #include <ACPI.h> 36 #include <AutoDeleter.h> 37 #include <safemode.h> 38 #include <string.h> 39 #include <stdio.h> 40 41 42 //#define TRACE_ARCH_INT 43 #ifdef TRACE_ARCH_INT 44 # define TRACE(x) dprintf x 45 #else 46 # define TRACE(x) ; 47 #endif 48 49 50 // Definitions for the PIC 8259 controller 51 // (this is not a complete list, only what we're actually using) 52 53 #define PIC_MASTER_CONTROL 0x20 54 #define PIC_MASTER_MASK 0x21 55 #define PIC_SLAVE_CONTROL 0xa0 56 #define PIC_SLAVE_MASK 0xa1 57 #define PIC_MASTER_INIT1 PIC_MASTER_CONTROL 58 #define PIC_MASTER_INIT2 PIC_MASTER_MASK 59 #define PIC_MASTER_INIT3 PIC_MASTER_MASK 60 #define PIC_MASTER_INIT4 PIC_MASTER_MASK 61 #define PIC_SLAVE_INIT1 PIC_SLAVE_CONTROL 62 #define PIC_SLAVE_INIT2 PIC_SLAVE_MASK 63 #define PIC_SLAVE_INIT3 PIC_SLAVE_MASK 64 #define PIC_SLAVE_INIT4 PIC_SLAVE_MASK 65 66 // the edge/level trigger control registers 67 #define PIC_MASTER_TRIGGER_MODE 0x4d0 68 #define PIC_SLAVE_TRIGGER_MODE 0x4d1 69 70 #define PIC_INIT1 0x10 71 #define PIC_INIT1_SEND_INIT4 0x01 72 #define PIC_INIT3_IR2_IS_SLAVE 0x04 73 #define PIC_INIT3_SLAVE_ID2 0x02 74 #define PIC_INIT4_x86_MODE 0x01 75 76 #define PIC_CONTROL3 0x08 77 #define PIC_CONTROL3_READ_ISR 0x03 78 #define PIC_CONTROL3_READ_IRR 0x02 79 80 #define PIC_NON_SPECIFIC_EOI 0x20 81 82 #define PIC_SLAVE_INT_BASE 8 83 #define PIC_NUM_INTS 0x0f 84