198 lines
5.4 KiB
NASM
198 lines
5.4 KiB
NASM
;boot.asm
|
|
;Author: Josh Holtrop
|
|
;Date: 07/08/04
|
|
;Modified: 07/10/04
|
|
|
|
|
|
%define MULTIBOOT_MAGIC 0x1BADB002
|
|
%define MULTIBOOT_FLAGS 0x00010003
|
|
|
|
%define VIRT_OFFSET 0xC0000000 ;3gb virtual address
|
|
%define PHYS_START 0x00100000 ;1mb physical address
|
|
%define VIRT_STACK_TOP 0xCFFFFFFC ;3gb+256mb virtual address
|
|
%define GDT_P PHYS_START ;1mb physical - Global Descriptor Table space
|
|
%define GDT_V GDT_P+VIRT_OFFSET
|
|
%define IDT_P PHYS_START+0x2000 ;1mb+8kb - Interrupt Descriptor Table space
|
|
%define IDT_V IDT_P+VIRT_OFFSET
|
|
%define PDBR_P PHYS_START+0x4000 ;1mb+16kb - Page Directory Base Register (first PD)
|
|
%define PDBR_V PDBR_P+VIRT_OFFSET
|
|
%define LOPT_P PHYS_START+0x5000 ;1mb+20kb - LOw Page Table for mapping first 4mb
|
|
%define LOPT_V LOPT_P+VIRT_OFFSET
|
|
%define PT_STACK_P PHYS_START+0x6000 ;1mb+24kb - page table for initial kernel stack pages (under 0xD0000000)
|
|
%define PT_STACK_V PT_STACK_P+VIRT_OFFSET
|
|
%define STACK_P PHYS_START+0x7000 ;1mb+28kb - initial 4kb kernel stack page
|
|
%define STACK_V STACK_P+VIRT_OFFSET
|
|
%define KERNEL_P PHYS_START+0x8000 ;1mb+32kb - the kernel's physical address
|
|
%define KERNEL_V KERNEL_P+VIRT_OFFSET ;3gb+1mb+32kb, the virtual address of the kernel
|
|
|
|
extern _k_init, _isr, _k_mbsave, _end
|
|
|
|
[bits 32]
|
|
|
|
[global _start]
|
|
_start:
|
|
|
|
multiboot_header:
|
|
dd MULTIBOOT_MAGIC ;magic
|
|
dd MULTIBOOT_FLAGS ;flags
|
|
dd -(MULTIBOOT_MAGIC + MULTIBOOT_FLAGS) ;checksum
|
|
|
|
dd multiboot_header-VIRT_OFFSET ;header_addr
|
|
dd _start-VIRT_OFFSET ;load_addr
|
|
dd 0 ;load_end_addr
|
|
dd _end-VIRT_OFFSET ;bss_end_addr
|
|
dd multiboot_entry-VIRT_OFFSET ;entry_addr
|
|
|
|
; dd 1 ;mode_type
|
|
; dd 80 ;width
|
|
; dd 25 ;height
|
|
; dd 0 ;depth
|
|
|
|
[global multiboot_entry]
|
|
multiboot_entry:
|
|
;This is where the kernel begins execution from the bootloader.
|
|
;At this point, a temporary gdt is set up to "map" 0xC000_0000 to 0x0.
|
|
cli ;should already be off...
|
|
lgdt [gdtrbs32-VIRT_OFFSET]
|
|
jmp KERNEL_CODE_BS32:segmented_start
|
|
segmented_start:
|
|
mov cx, KERNEL_DATA_BS32
|
|
mov ss, cx
|
|
mov ds, cx
|
|
mov es, cx
|
|
mov gs, cx
|
|
mov fs, cx
|
|
mov esp, STACK_V+0x1000 ;ok, now we can access our data
|
|
|
|
;aloop:
|
|
; inc dword [0xC00B8000]
|
|
; jmp aloop
|
|
|
|
|
|
;Then the multiboot info structures are saved to local data variables.
|
|
add ebx, VIRT_OFFSET
|
|
push eax
|
|
push ebx ;pointer to multiboot info structure
|
|
call _k_mbsave ;save multiboot info structures
|
|
add esp, 8
|
|
|
|
cmp eax, 0
|
|
jz pm_return
|
|
|
|
;go back to real mode to initialize video mode
|
|
mov ebx, pm_return
|
|
|
|
|
|
|
|
;Next we enable paging with the first 4mb mapped 1:1 virtual:physical
|
|
; and with the 4mb starting at 0xC000_0000 mapped to the first 4mb physical.
|
|
pm_return:
|
|
xor eax, eax
|
|
mov edi, PDBR_V
|
|
mov ecx, 1024 ;clear the PDBR
|
|
rep stosd
|
|
mov edi, PT_STACK_V
|
|
mov ecx, 1024 ;clear the PT_STACK
|
|
rep stosd
|
|
mov [PDBR_V], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
|
|
mov [PDBR_V+0xC00], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
|
|
mov [PDBR_V+0xCFC], dword PT_STACK_P|0x03 ;store the physical address of the initial stack page page table | (read/write, present)
|
|
mov [PDBR_V+0xFFC], dword PDBR_P|0x03 ;store the physical address of the page directory (identity map) | (read/write, present)
|
|
mov [PT_STACK_V+0xFFC], dword STACK_P|0x03 ;store the physical address of the initial stack page | (read/write, present)
|
|
|
|
mov edi, LOPT_V
|
|
mov ecx, 1024
|
|
mov eax, 0x03 ;starting physical address = 0x0 | (read/write, present flags)
|
|
fill_lopt_loop: ;fill the page table
|
|
stosd
|
|
add eax, 4096 ;increment next phsyical address by 4kb
|
|
loop fill_lopt_loop
|
|
|
|
mov eax, PDBR_P
|
|
mov cr3, eax ;store the Page Directory Base Address
|
|
mov eax, cr0
|
|
or eax, 0x80000000 ;set Page Enable bit
|
|
mov cr0, eax ;now paging is active!
|
|
|
|
|
|
mov edi, GDT_V
|
|
mov esi, gdt
|
|
mov ecx, gdt_end-gdt
|
|
rep movsb
|
|
|
|
mov edi, IDT_V ;destination
|
|
mov esi, isr_0 ;address of isr0
|
|
mov edx, isr_1-isr_0 ;distance between isr labels
|
|
mov ecx, 50 ;number of isrlabels
|
|
fill_idt:
|
|
mov ebx, esi
|
|
mov ax, si
|
|
stosw ;0 offset 15:0
|
|
mov ax, KERNEL_CODE
|
|
stosw ;2 selector 15:0
|
|
mov ax, 0x8E00
|
|
stosw ;4 [P][DPL][0][TYPE][0][0][0][0][0][0][0][0]
|
|
shr esi, 16
|
|
mov ax, si
|
|
stosw ;6 offset 31:16
|
|
mov esi, ebx
|
|
add esi, edx
|
|
loop fill_idt
|
|
mov word [IDT_V+0x30*8+4], 0xEE00 ;interrupt 0x30 has user priviledges
|
|
|
|
;Then we can start using our "real" gdt, then unmap the lower 4mb.
|
|
lgdt [gdtr] ;load gdt
|
|
jmp KERNEL_CODE:newgdtcontinue
|
|
newgdtcontinue:
|
|
mov ax, KERNEL_DATA
|
|
mov es, ax
|
|
mov ds, ax
|
|
mov gs, ax
|
|
mov fs, ax
|
|
mov ss, ax
|
|
mov esp, VIRT_STACK_TOP ;stack just under 3gb+256mb, moves downward
|
|
lidt [idtr] ;load idt
|
|
mov [PDBR_V], dword 0 ;unmap 0x0, we are running completely paged at 0xC000_0000
|
|
|
|
call _k_init ;C kernel initialization
|
|
|
|
idle_loop:
|
|
; sti
|
|
hlt
|
|
jmp idle_loop
|
|
|
|
;-------------------------------------------------------
|
|
gdtrbs32:
|
|
dw gdt_endbs32-gdtbs32-1
|
|
dd gdtbs32-VIRT_OFFSET
|
|
gdtbs32: ;null descriptor
|
|
dd 0
|
|
dd 0
|
|
|
|
;a base of 0x4000_0000, when added to 0xC000_0000 will produce 0x0000_0000 physical before paging in effect
|
|
KERNEL_CODE_BS32 equ $-gdtbs32
|
|
db 0xff ;limit 7:0
|
|
db 0xff ;limit 15:8
|
|
db 0x00 ;base 7:0
|
|
db 0x00 ;base 15:8
|
|
db 0x00 ;base 23:16
|
|
db 0x9a ;access
|
|
db 0xcf ;flags / limit 19:16
|
|
db 0x40 ;base 31:24
|
|
|
|
KERNEL_DATA_BS32 equ $-gdtbs32
|
|
db 0xff ;limit 7:0
|
|
db 0xff ;limit 15:8
|
|
db 0x00 ;base 7:0
|
|
db 0x00 ;base 15:8
|
|
db 0x00 ;base 23:16
|
|
db 0x92 ;access
|
|
db 0xcf ;flags / limit 19:16
|
|
db 0x40 ;base 31:24
|
|
|
|
gdt_endbs32:
|
|
|
|
%include "gdt.inc"
|
|
%include "idt.inc"
|
|
|