blob: 2844b8c503b98f76fa50840bd7803f63eb67cda6 [file] [log] [blame] [edit]
/*
* Copyright (c) 2009 Corey Tabaka
* Copyright (c) 2015 Intel Corporation
* Copyright (c) 2016 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <asm.h>
#include <arch/x86/descriptor.h>
#include <arch/x86/mmu.h>
/* The magic number for the Multiboot header. */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
/* The flags for the Multiboot header. */
#if defined(__ELF__) && 0
#define MULTIBOOT_HEADER_FLAGS 0x00000002
#else
#define MULTIBOOT_HEADER_FLAGS 0x00010002
#endif
/* The magic number passed by a Multiboot-compliant boot loader. */
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
#define PHYS_LOAD_ADDRESS (MEMBASE + KERNEL_LOAD_OFFSET)
#define PHYS_ADDR_DELTA (KERNEL_BASE + KERNEL_LOAD_OFFSET - PHYS_LOAD_ADDRESS)
#define PHYS(x) ((x) - PHYS_ADDR_DELTA)
.section ".text.boot"
.global _start
_start:
jmp real_start
.align 4
.type multiboot_header,STT_OBJECT
multiboot_header:
/* magic */
.int MULTIBOOT_HEADER_MAGIC
/* flags */
.int MULTIBOOT_HEADER_FLAGS
/* checksum */
.int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
#if !defined(__ELF__) || 1
/* header_addr */
.int PHYS(multiboot_header)
/* load_addr */
.int PHYS(_start)
/* load_end_addr */
.int PHYS(__data_end)
/* bss_end_addr */
.int PHYS(__bss_end)
/* entry_addr */
.int PHYS(real_start)
#endif
real_start:
cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
jne 0f
movl %ebx, PHYS(_multiboot_info)
0:
/* load our new gdt by physical pointer */
lgdt PHYS(_gdtr_phys)
movw $DATA_SELECTOR, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %ss
movw %ax, %gs
movw %ax, %ss
/* load initial stack pointer */
movl $PHYS(_kstack + 4096), %esp
/*We jumped here in protected mode in a code segment that migh not longer
be valid , do a long jump to our code segment, we use retf instead of
ljmp to be able to use relative labels */
pushl $CODE_SELECTOR /*Pushing our code segment */
pushl $PHYS(.Lfarjump) /*and jump address */
retf /*This instruction will jump to codesel:farjump */
.Lfarjump:
/* zero the bss section */
bss_setup:
movl $PHYS(__bss_start), %edi /* starting address of the bss */
movl $PHYS(__bss_end), %ecx /* find the length of the bss in bytes */
subl %edi, %ecx
shrl $2, %ecx /* convert to 32 bit words, since the bss is aligned anyway */
2:
movl $0, (%edi)
addl $4, %edi
loop 2b
paging_setup:
#ifdef PAE_MODE_ENABLED
#error broken for now
/* Preparing PAE paging, we will use 2MB pages covering 1GB
for initial bootstrap, this page table will be 1 to 1 */
/* Setting the First PDPTE with a PD table reference*/
movl $pdp, %eax
orl $0x01, %eax
movl %eax, (pdpt)
movl $pdp, %esi
movl $0x1ff, %ecx
fill_pdp:
movl $0x1ff, %eax
subl %ecx, %eax
shll $21,%eax
orl $0x83, %eax
movl %eax, (%esi)
addl $8,%esi
loop fill_pdp
/* Set PDPT in CR3 */
movl $pdpt, %eax
mov %eax, %cr3
/* Enabling PAE*/
mov %cr4, %eax
btsl $(5), %eax
mov %eax, %cr4
/* Enabling Paging and from this point we are in
32 bit compatibility mode */
mov %cr0, %eax
btsl $(31), %eax
mov %eax, %cr0
#else
/* map the first 1GB 1:1 */
movl $PHYS(pd), %esi
movl $0x100, %ecx
xor %eax, %eax
.Lfill_pd:
mov %eax, %edx
orl $X86_KERNEL_PD_LP_FLAGS, %edx
movl %edx, (%esi)
addl $4, %esi
addl $0x00400000, %eax
loop .Lfill_pd
/* map the first 1GB to KERNEL_ASPACE_BASE */
movl $(PHYS(pd) + 0x800), %esi
movl $0x100, %ecx
xor %eax, %eax
.Lfill_pd2:
mov %eax, %edx
orl $X86_KERNEL_PD_LP_FLAGS, %edx
movl %edx, (%esi)
addl $4, %esi
addl $0x00400000, %eax
loop .Lfill_pd2
/* Set PD in CR3 */
movl $PHYS(pd), %eax
mov %eax, %cr3
/* Enabling Paging and from this point we are in */
mov %cr4, %eax
orl $0x10, %eax
mov %eax, %cr4
mov %cr0, %eax
btsl $(31), %eax
mov %eax, %cr0
#endif
/* load the high kernel stack */
movl $(_kstack + 4096), %esp
/* reload the high gdtr */
lgdt PHYS(_gdtr)
/* branch to the high address */
movl $main_lk, %eax
jmp *%eax
main_lk:
/* set up the idt */
call setup_idt
/* call the main module */
call lk_main
0: /* just sit around waiting for interrupts */
hlt /* interrupts will unhalt the processor */
pause
jmp 0b /* so jump back to halt to conserve power */