1/* 2 * Copyright (c) 2009 Corey Tabaka 3 * Copyright (c) 2015 Intel Corporation 4 * Copyright (c) 2016 Travis Geiselbrecht 5 * 6 * Use of this source code is governed by a MIT-style 7 * license that can be found in the LICENSE file or at 8 * https://opensource.org/licenses/MIT 9 */ 10#include <lk/asm.h> 11#include <arch/x86/descriptor.h> 12#include <arch/x86/mmu.h> 13 14/* The magic number for the Multiboot header. */ 15#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 16 17/* The flags for the Multiboot header. */ 18#if defined(__ELF__) && 0 19#define MULTIBOOT_HEADER_FLAGS 0x00000002 20#else 21#define MULTIBOOT_HEADER_FLAGS 0x00010002 22#endif 23 24/* The magic number passed by a Multiboot-compliant boot loader. */ 25#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 26 27#define PHYS_LOAD_ADDRESS (MEMBASE + KERNEL_LOAD_OFFSET) 28#define PHYS_ADDR_DELTA (KERNEL_BASE + KERNEL_LOAD_OFFSET - PHYS_LOAD_ADDRESS) 29#define PHYS(x) ((x) - PHYS_ADDR_DELTA) 30 31.section ".text.boot" 32.global _start 33_start: 34 jmp real_start 35 36.align 4 37 38.type multiboot_header,STT_OBJECT 39multiboot_header: 40 /* magic */ 41 .int MULTIBOOT_HEADER_MAGIC 42 /* flags */ 43 .int MULTIBOOT_HEADER_FLAGS 44 /* checksum */ 45 .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) 46 47#if !defined(__ELF__) || 1 48 /* header_addr */ 49 .int PHYS(multiboot_header) 50 /* load_addr */ 51 .int PHYS(_start) 52 /* load_end_addr */ 53 .int PHYS(__data_end) 54 /* bss_end_addr */ 55 .int PHYS(__bss_end) 56 /* entry_addr */ 57 .int PHYS(real_start) 58#endif 59 60real_start: 61 cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax 62 jne 0f 63 movl %ebx, PHYS(_multiboot_info) 64 650: 66 /* load our new gdt by physical pointer */ 67 lgdt PHYS(_gdtr_phys) 68 69 movw $DATA_SELECTOR, %ax 70 movw %ax, %ds 71 movw %ax, %es 72 movw %ax, %fs 73 movw %ax, %ss 74 movw %ax, %gs 75 movw %ax, %ss 76 77 /* load initial stack pointer */ 78 movl $PHYS(_kstack + 4096), %esp 79 80 /*We jumped here in protected mode in a code segment that migh not longer 81 be valid , do a long jump to our code segment, we use retf instead of 82 ljmp to be able to use relative labels */ 83 pushl $CODE_SELECTOR /*Pushing our code segment */ 84 pushl $PHYS(.Lfarjump) /*and jump address */ 85 retf /*This instruction will jump to codesel:farjump */ 86 87.Lfarjump: 88 89 /* zero the bss section */ 90bss_setup: 91 movl $PHYS(__bss_start), %edi /* starting address of the bss */ 92 movl $PHYS(__bss_end), %ecx /* find the length of the bss in bytes */ 93 subl %edi, %ecx 94 shrl $2, %ecx /* convert to 32 bit words, since the bss is aligned anyway */ 952: 96 movl $0, (%edi) 97 addl $4, %edi 98 loop 2b 99 100paging_setup: 101#ifdef PAE_MODE_ENABLED 102#error broken for now 103 /* Preparing PAE paging, we will use 2MB pages covering 1GB 104 for initial bootstrap, this page table will be 1 to 1 */ 105 106 /* Setting the First PDPTE with a PD table reference*/ 107 movl $pdp, %eax 108 orl $0x01, %eax 109 movl %eax, (pdpt) 110 111 movl $pdp, %esi 112 movl $0x1ff, %ecx 113 114fill_pdp: 115 movl $0x1ff, %eax 116 subl %ecx, %eax 117 shll $21,%eax 118 orl $0x83, %eax 119 movl %eax, (%esi) 120 addl $8,%esi 121 loop fill_pdp 122 123 /* Set PDPT in CR3 */ 124 movl $pdpt, %eax 125 mov %eax, %cr3 126 127 /* Enabling PAE*/ 128 mov %cr4, %eax 129 btsl $(5), %eax 130 mov %eax, %cr4 131 132 /* Enabling Paging and from this point we are in 133 32 bit compatibility mode */ 134 mov %cr0, %eax 135 btsl $(31), %eax 136 mov %eax, %cr0 137 138#elif X86_LEGACY 139 /* map the first 16MB 1:1 with 4KB pages and again at 0x8000.0000 */ 140 141 /* set up 4 page tables worth of entries */ 142 movl $PHYS(kernel_pt), %edi 143 movl $1024*4,%ecx 144 movl $X86_KERNEL_PT_FLAGS, %eax 145 146.Lfill_pt: 147 movl %eax, (%edi) 148 addl $4, %edi 149 addl $4096, %eax 150 loop .Lfill_pt 151 152 /* set up the page dir with 4 entries at 0 and 0x8000.0000 pointing 153 * to 4 page tables that will map physical address 0 - 16MB 154 */ 155 movl $PHYS(kernel_pd), %esi 156 movl $PHYS(kernel_pd) + 512*4, %edi 157 movl $PHYS(kernel_pt) + X86_KERNEL_PT_FLAGS, %eax 158 movl %eax, (%esi) 159 movl %eax, (%edi) 160 addl $4096, %eax 161 movl %eax, 4(%esi) 162 movl %eax, 4(%edi) 163 addl $4096, %eax 164 movl %eax, 8(%esi) 165 movl %eax, 8(%edi) 166 addl $4096, %eax 167 movl %eax, 12(%esi) 168 movl %eax, 12(%edi) 169 170 /* Set PD in CR3 */ 171 movl $PHYS(kernel_pd), %eax 172 mov %eax, %cr3 173 174 /* Enabling Paging and from this point we are in */ 175 mov %cr0, %eax 176 btsl $(31), %eax 177 mov %eax, %cr0 178#else 179 /* map the first 1GB 1:1 using 4MB pages */ 180 movl $PHYS(kernel_pd), %esi 181 movl $0x100, %ecx 182 xor %eax, %eax 183 184.Lfill_pd: 185 mov %eax, %edx 186 orl $X86_KERNEL_PD_LP_FLAGS, %edx 187 movl %edx, (%esi) 188 addl $4, %esi 189 addl $0x00400000, %eax 190 loop .Lfill_pd 191 192 /* map the first 1GB to KERNEL_ASPACE_BASE */ 193 movl $(PHYS(kernel_pd) + 0x800), %esi 194 movl $0x100, %ecx 195 xor %eax, %eax 196 197.Lfill_pd2: 198 mov %eax, %edx 199 orl $X86_KERNEL_PD_LP_FLAGS, %edx 200 movl %edx, (%esi) 201 addl $4, %esi 202 addl $0x00400000, %eax 203 loop .Lfill_pd2 204 205 /* Set PD in CR3 */ 206 movl $PHYS(kernel_pd), %eax 207 mov %eax, %cr3 208 209 /* Enabling Paging and from this point we are in */ 210 mov %cr4, %eax 211 orl $0x10, %eax 212 mov %eax, %cr4 213 214 mov %cr0, %eax 215 btsl $(31), %eax 216 mov %eax, %cr0 217#endif 218 219 /* load the high kernel stack */ 220 movl $(_kstack + 4096), %esp 221 222 /* reload the high gdtr */ 223 lgdt PHYS(_gdtr) 224 225 /* branch to the high address */ 226 movl $main_lk, %eax 227 jmp *%eax 228 229main_lk: 230 /* set up the idt */ 231 call setup_idt 232 233 /* call the main module */ 234 call lk_main 2350: /* just sit around waiting for interrupts */ 236 hlt /* interrupts will unhalt the processor */ 237 pause 238 jmp 0b /* so jump back to halt to conserve power */ 239