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#include <hw/multiboot.h> 14 15#define PHYS_LOAD_ADDRESS (MEMBASE + KERNEL_LOAD_OFFSET) 16#define PHYS_ADDR_DELTA (KERNEL_BASE + KERNEL_LOAD_OFFSET - PHYS_LOAD_ADDRESS) 17#define PHYS(x) ((x) - PHYS_ADDR_DELTA) 18 19.section ".text.boot" 20.global _start 21_start: 22 jmp real_start 23 24.align 4 25 26/* flags for multiboot header */ 27#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE) 28 29.type multiboot_header,STT_OBJECT 30multiboot_header: 31 /* magic */ 32 .int MULTIBOOT_HEADER_MAGIC 33 /* flags */ 34 .int MULTIBOOT_HEADER_FLAGS 35 /* checksum */ 36 .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) 37 38 /* header_addr */ 39 .int PHYS(multiboot_header) 40 /* load_addr */ 41 .int PHYS(_start) 42 /* load_end_addr */ 43 .int PHYS(__data_end) 44 /* bss_end_addr */ 45 .int PHYS(__bss_end) 46 /* entry_addr */ 47 .int PHYS(real_start) 48 49real_start: 50 cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax 51 jne 0f 52 movl %ebx, PHYS(_multiboot_info) 53 540: 55 /* load our new gdt by physical pointer */ 56 lgdt PHYS(_gdtr_phys) 57 58 movw $DATA_SELECTOR, %ax 59 movw %ax, %ds 60 movw %ax, %es 61 movw %ax, %fs 62 movw %ax, %ss 63 movw %ax, %gs 64 movw %ax, %ss 65 66 /* load initial stack pointer */ 67 movl $PHYS(_kstack + 4096), %esp 68 69 /*We jumped here in protected mode in a code segment that migh not longer 70 be valid , do a long jump to our code segment, we use retf instead of 71 ljmp to be able to use relative labels */ 72 pushl $CODE_SELECTOR /*Pushing our code segment */ 73 pushl $PHYS(.Lfarjump) /*and jump address */ 74 retf /*This instruction will jump to codesel:farjump */ 75 76.Lfarjump: 77 78 /* zero the bss section */ 79bss_setup: 80 movl $PHYS(__bss_start), %edi /* starting address of the bss */ 81 movl $PHYS(__bss_end), %ecx /* find the length of the bss in bytes */ 82 subl %edi, %ecx 83 shrl $2, %ecx /* convert to 32 bit words, since the bss is aligned anyway */ 842: 85 movl $0, (%edi) 86 addl $4, %edi 87 loop 2b 88 89paging_setup: 90#if X86_LEGACY 91 /* map the first 16MB 1:1 with 4KB pages and again at 0x8000.0000 */ 92 93 /* set up 4 page tables worth of entries */ 94 movl $PHYS(kernel_pt), %edi 95 movl $1024*4,%ecx 96 movl $X86_KERNEL_PT_FLAGS, %eax 97 98.Lfill_pt: 99 movl %eax, (%edi) 100 addl $4, %edi 101 addl $4096, %eax 102 loop .Lfill_pt 103 104 /* set up the page dir with 4 entries at 0 and 0x8000.0000 pointing 105 * to 4 page tables that will map physical address 0 - 16MB 106 */ 107 movl $PHYS(kernel_pd), %esi 108 movl $PHYS(kernel_pd) + 512*4, %edi 109 movl $PHYS(kernel_pt) + X86_KERNEL_PT_FLAGS, %eax 110 movl %eax, (%esi) 111 movl %eax, (%edi) 112 addl $4096, %eax 113 movl %eax, 4(%esi) 114 movl %eax, 4(%edi) 115 addl $4096, %eax 116 movl %eax, 8(%esi) 117 movl %eax, 8(%edi) 118 addl $4096, %eax 119 movl %eax, 12(%esi) 120 movl %eax, 12(%edi) 121#else 122 /* map the first 1GB 1:1 using 4MB pages */ 123 movl $PHYS(kernel_pd), %esi 124 movl $0x100, %ecx 125 xor %eax, %eax 126 127.Lfill_pd: 128 mov %eax, %edx 129 orl $X86_KERNEL_PD_LP_FLAGS, %edx 130 movl %edx, (%esi) 131 addl $4, %esi 132 addl $0x00400000, %eax 133 loop .Lfill_pd 134 135 /* map the first 1GB to KERNEL_ASPACE_BASE */ 136 movl $(PHYS(kernel_pd) + 0x800), %esi 137 movl $0x100, %ecx 138 xor %eax, %eax 139 140.Lfill_pd2: 141 mov %eax, %edx 142 orl $X86_KERNEL_PD_LP_FLAGS, %edx 143 movl %edx, (%esi) 144 addl $4, %esi 145 addl $0x00400000, %eax 146 loop .Lfill_pd2 147 148 /* enable PSE (4MB pages) */ 149 mov %cr4, %eax 150 orl $(1<<4), %eax 151 mov %eax, %cr4 152#endif 153 154 /* Set PD in CR3 */ 155 movl $PHYS(kernel_pd), %eax 156 mov %eax, %cr3 157 158 /* save a copy of the address of the kernel page directory */ 159 movl %eax, PHYS(kernel_pd_phys) 160 161 /* Enabling Paging and from this point we are in */ 162 mov %cr0, %eax 163 btsl $(31), %eax 164 mov %eax, %cr0 165 166 /* load the high kernel stack */ 167 movl $(_kstack + 4096), %esp 168 169 /* reload the high gdtr */ 170 lgdt PHYS(_gdtr) 171 172 /* branch to the high address */ 173 movl $main_lk, %eax 174 jmp *%eax 175 176main_lk: 177 /* set up the idt */ 178 call setup_idt 179 180 /* set up the percpu data structure pointer for the boot cpu */ 181 pushl $0 182 pushl $0 183 call x86_configure_percpu_early 184 185 /* call the main module */ 186 call lk_main 1870: /* just sit around waiting for interrupts */ 188 hlt /* interrupts will unhalt the processor */ 189 pause 190 jmp 0b /* so jump back to halt to conserve power */ 191