1 /* 2 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "long.h" 8 9 #include <algorithm> 10 11 #include <KernelExport.h> 12 13 // Include the x86_64 version of descriptors.h 14 #define __x86_64__ 15 #include <arch/x86/descriptors.h> 16 #undef __x86_64__ 17 18 #include <arch_system_info.h> 19 #include <boot/platform.h> 20 #include <boot/heap.h> 21 #include <boot/stage2.h> 22 #include <boot/stdio.h> 23 #include <kernel.h> 24 25 #include "debug.h" 26 #include "mmu.h" 27 #include "smp.h" 28 29 30 static const uint64 kTableMappingFlags = 0x7; 31 static const uint64 kLargePageMappingFlags = 0x183; 32 static const uint64 kPageMappingFlags = 0x103; 33 // Global, R/W, Present 34 35 extern "C" void long_enter_kernel(int currentCPU, uint64 stackTop); 36 37 extern uint64 gLongGDT; 38 extern uint32 gLongPhysicalPML4; 39 extern uint64 gLongKernelEntry; 40 41 42 /*! Convert a 32-bit address to a 64-bit address. */ 43 static inline uint64 44 fix_address(uint64 address) 45 { 46 if(address >= KERNEL_LOAD_BASE) 47 return address - KERNEL_LOAD_BASE + KERNEL_LOAD_BASE_64_BIT; 48 else 49 return address; 50 } 51 52 53 template<typename Type> 54 inline void 55 fix_address(FixedWidthPointer<Type>& p) 56 { 57 if (p != NULL) 58 p.SetTo(fix_address(p.Get())); 59 } 60 61 62 static void 63 long_gdt_init() 64 { 65 clear_segment_descriptor(&gBootGDT[0]); 66 67 // Set up code/data segments (TSS segments set up later in the kernel). 68 set_segment_descriptor(&gBootGDT[KERNEL_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY, 69 DPL_KERNEL); 70 set_segment_descriptor(&gBootGDT[KERNEL_DATA_SEGMENT], DT_DATA_WRITEABLE, 71 DPL_KERNEL); 72 set_segment_descriptor(&gBootGDT[USER_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY, 73 DPL_USER); 74 set_segment_descriptor(&gBootGDT[USER_DATA_SEGMENT], DT_DATA_WRITEABLE, 75 DPL_USER); 76 77 // Used by long_enter_kernel(). 78 gLongGDT = fix_address((addr_t)gBootGDT); 79 dprintf("GDT at 0x%llx\n", gLongGDT); 80 } 81 82 83 static void 84 long_mmu_init() 85 { 86 uint64* pml4; 87 uint64* pdpt; 88 uint64* pageDir; 89 uint64* pageTable; 90 addr_t physicalAddress; 91 92 // Allocate the top level PML4. 93 pml4 = (uint64*)mmu_allocate_page(&gKernelArgs.arch_args.phys_pgdir); 94 memset(pml4, 0, B_PAGE_SIZE); 95 gKernelArgs.arch_args.vir_pgdir = fix_address((uint64)(addr_t)pml4); 96 97 // Store the virtual memory usage information. 98 gKernelArgs.virtual_allocated_range[0].start = KERNEL_LOAD_BASE_64_BIT; 99 gKernelArgs.virtual_allocated_range[0].size = mmu_get_virtual_usage(); 100 gKernelArgs.num_virtual_allocated_ranges = 1; 101 gKernelArgs.arch_args.virtual_end = ROUNDUP(KERNEL_LOAD_BASE_64_BIT 102 + gKernelArgs.virtual_allocated_range[0].size, 0x200000); 103 104 // Find the highest physical memory address. We map all physical memory 105 // into the kernel address space, so we want to make sure we map everything 106 // we have available. 107 uint64 maxAddress = 0; 108 for (uint32 i = 0; i < gKernelArgs.num_physical_memory_ranges; i++) { 109 maxAddress = std::max(maxAddress, 110 gKernelArgs.physical_memory_range[i].start 111 + gKernelArgs.physical_memory_range[i].size); 112 } 113 114 // Want to map at least 4GB, there may be stuff other than usable RAM that 115 // could be in the first 4GB of physical address space. 116 maxAddress = std::max(maxAddress, (uint64)0x100000000ll); 117 maxAddress = ROUNDUP(maxAddress, 0x40000000); 118 119 // Currently only use 1 PDPT (512GB). This will need to change if someone 120 // wants to use Haiku on a box with more than 512GB of RAM but that's 121 // probably not going to happen any time soon. 122 if (maxAddress / 0x40000000 > 512) 123 panic("Can't currently support more than 512GB of RAM!"); 124 125 // Create page tables for the physical map area. Also map this PDPT 126 // temporarily at the bottom of the address space so that we are identity 127 // mapped. 128 129 pdpt = (uint64*)mmu_allocate_page(&physicalAddress); 130 memset(pdpt, 0, B_PAGE_SIZE); 131 pml4[510] = physicalAddress | kTableMappingFlags; 132 pml4[0] = physicalAddress | kTableMappingFlags; 133 134 for (uint64 i = 0; i < maxAddress; i += 0x40000000) { 135 pageDir = (uint64*)mmu_allocate_page(&physicalAddress); 136 memset(pageDir, 0, B_PAGE_SIZE); 137 pdpt[i / 0x40000000] = physicalAddress | kTableMappingFlags; 138 139 for (uint64 j = 0; j < 0x40000000; j += 0x200000) { 140 pageDir[j / 0x200000] = (i + j) | kLargePageMappingFlags; 141 } 142 143 mmu_free(pageDir, B_PAGE_SIZE); 144 } 145 146 mmu_free(pdpt, B_PAGE_SIZE); 147 148 // Allocate tables for the kernel mappings. 149 150 pdpt = (uint64*)mmu_allocate_page(&physicalAddress); 151 memset(pdpt, 0, B_PAGE_SIZE); 152 pml4[511] = physicalAddress | kTableMappingFlags; 153 154 pageDir = (uint64*)mmu_allocate_page(&physicalAddress); 155 memset(pageDir, 0, B_PAGE_SIZE); 156 pdpt[510] = physicalAddress | kTableMappingFlags; 157 158 // We can now allocate page tables and duplicate the mappings across from 159 // the 32-bit address space to them. 160 pageTable = NULL; 161 for (uint32 i = 0; i < gKernelArgs.virtual_allocated_range[0].size 162 / B_PAGE_SIZE; i++) { 163 if ((i % 512) == 0) { 164 if (pageTable) 165 mmu_free(pageTable, B_PAGE_SIZE); 166 167 pageTable = (uint64*)mmu_allocate_page(&physicalAddress); 168 memset(pageTable, 0, B_PAGE_SIZE); 169 pageDir[i / 512] = physicalAddress | kTableMappingFlags; 170 } 171 172 // Get the physical address to map. 173 if (!mmu_get_virtual_mapping(KERNEL_LOAD_BASE + (i * B_PAGE_SIZE), 174 &physicalAddress)) 175 continue; 176 177 pageTable[i % 512] = physicalAddress | kPageMappingFlags; 178 } 179 180 if (pageTable) 181 mmu_free(pageTable, B_PAGE_SIZE); 182 mmu_free(pageDir, B_PAGE_SIZE); 183 mmu_free(pdpt, B_PAGE_SIZE); 184 185 // Sort the address ranges. 186 sort_address_ranges(gKernelArgs.physical_memory_range, 187 gKernelArgs.num_physical_memory_ranges); 188 sort_address_ranges(gKernelArgs.physical_allocated_range, 189 gKernelArgs.num_physical_allocated_ranges); 190 sort_address_ranges(gKernelArgs.virtual_allocated_range, 191 gKernelArgs.num_virtual_allocated_ranges); 192 193 dprintf("phys memory ranges:\n"); 194 for (uint32 i = 0; i < gKernelArgs.num_physical_memory_ranges; i++) { 195 dprintf(" base %#018" B_PRIx64 ", length %#018" B_PRIx64 "\n", 196 gKernelArgs.physical_memory_range[i].start, 197 gKernelArgs.physical_memory_range[i].size); 198 } 199 200 dprintf("allocated phys memory ranges:\n"); 201 for (uint32 i = 0; i < gKernelArgs.num_physical_allocated_ranges; i++) { 202 dprintf(" base %#018" B_PRIx64 ", length %#018" B_PRIx64 "\n", 203 gKernelArgs.physical_allocated_range[i].start, 204 gKernelArgs.physical_allocated_range[i].size); 205 } 206 207 dprintf("allocated virt memory ranges:\n"); 208 for (uint32 i = 0; i < gKernelArgs.num_virtual_allocated_ranges; i++) { 209 dprintf(" base %#018" B_PRIx64 ", length %#018" B_PRIx64 "\n", 210 gKernelArgs.virtual_allocated_range[i].start, 211 gKernelArgs.virtual_allocated_range[i].size); 212 } 213 214 gLongPhysicalPML4 = gKernelArgs.arch_args.phys_pgdir; 215 } 216 217 218 static void 219 convert_preloaded_image(preloaded_elf64_image* image) 220 { 221 fix_address(image->next); 222 fix_address(image->name); 223 fix_address(image->debug_string_table); 224 fix_address(image->syms); 225 fix_address(image->rel); 226 fix_address(image->rela); 227 fix_address(image->pltrel); 228 fix_address(image->debug_symbols); 229 } 230 231 232 /*! Convert all addresses in kernel_args to 64-bit addresses. */ 233 static void 234 convert_kernel_args() 235 { 236 fix_address(gKernelArgs.boot_volume); 237 fix_address(gKernelArgs.vesa_modes); 238 fix_address(gKernelArgs.edid_info); 239 fix_address(gKernelArgs.debug_output); 240 fix_address(gKernelArgs.boot_splash); 241 fix_address(gKernelArgs.arch_args.apic); 242 fix_address(gKernelArgs.arch_args.hpet); 243 244 convert_preloaded_image(static_cast<preloaded_elf64_image*>( 245 gKernelArgs.kernel_image.Pointer())); 246 fix_address(gKernelArgs.kernel_image); 247 248 // Iterate over the preloaded images. Must save the next address before 249 // converting, as the next pointer will be converted. 250 preloaded_image* image = gKernelArgs.preloaded_images; 251 fix_address(gKernelArgs.preloaded_images); 252 while (image != NULL) { 253 preloaded_image* next = image->next; 254 convert_preloaded_image(static_cast<preloaded_elf64_image*>(image)); 255 image = next; 256 } 257 258 // Set correct kernel args range addresses. 259 dprintf("kernel args ranges:\n"); 260 for (uint32 i = 0; i < gKernelArgs.num_kernel_args_ranges; i++) { 261 gKernelArgs.kernel_args_range[i].start = fix_address( 262 gKernelArgs.kernel_args_range[i].start); 263 dprintf(" base %#018" B_PRIx64 ", length %#018" B_PRIx64 "\n", 264 gKernelArgs.kernel_args_range[i].start, 265 gKernelArgs.kernel_args_range[i].size); 266 } 267 268 // Fix driver settings files. 269 driver_settings_file* file = gKernelArgs.driver_settings; 270 fix_address(gKernelArgs.driver_settings); 271 while (file != NULL) { 272 driver_settings_file* next = file->next; 273 fix_address(file->next); 274 fix_address(file->buffer); 275 file = next; 276 } 277 } 278 279 280 static void 281 long_smp_start_kernel(void) 282 { 283 uint32 cpu = smp_get_current_cpu(); 284 285 // Important. Make sure supervisor threads can fault on read only pages... 286 asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1)); 287 asm("cld"); 288 asm("fninit"); 289 290 // Fix our kernel stack address. 291 gKernelArgs.cpu_kstack[cpu].start 292 = fix_address(gKernelArgs.cpu_kstack[cpu].start); 293 294 long_enter_kernel(cpu, gKernelArgs.cpu_kstack[cpu].start 295 + gKernelArgs.cpu_kstack[cpu].size); 296 297 panic("Shouldn't get here"); 298 } 299 300 301 void 302 long_start_kernel() 303 { 304 // Check whether long mode is supported. 305 cpuid_info info; 306 get_current_cpuid(&info, 0x80000001, 0); 307 if ((info.regs.edx & (1 << 29)) == 0) 308 panic("64-bit kernel requires a 64-bit CPU"); 309 310 preloaded_elf64_image *image = static_cast<preloaded_elf64_image *>( 311 gKernelArgs.kernel_image.Pointer()); 312 313 smp_init_other_cpus(); 314 315 long_gdt_init(); 316 long_mmu_init(); 317 debug_cleanup(); 318 convert_kernel_args(); 319 320 // Save the kernel entry point address. 321 gLongKernelEntry = image->elf_header.e_entry; 322 dprintf("kernel entry at %#llx\n", gLongKernelEntry); 323 324 // Fix our kernel stack address. 325 gKernelArgs.cpu_kstack[0].start 326 = fix_address(gKernelArgs.cpu_kstack[0].start); 327 328 // We're about to enter the kernel -- disable console output. 329 stdout = NULL; 330 331 smp_boot_other_cpus(long_smp_start_kernel); 332 333 // Enter the kernel! 334 long_enter_kernel(0, gKernelArgs.cpu_kstack[0].start 335 + gKernelArgs.cpu_kstack[0].size); 336 337 panic("Shouldn't get here"); 338 } 339