Bootloader 32 bit kernel, A20? Pmode?
-
- Posts: 2
- Joined: Wed Nov 15, 2006 12:01 am
Bootloader 32 bit kernel, A20? Pmode?
I've recently takin up teaching my self OS development, So far I have created a basic 16 bit boot loader and 16 bit kernel all works all dandy. Now i've created a kernel that uses the extern function which aparently requires you to have an ASM launcher, I have type [BITS 32] as it will not compile other wise. Unfortunatly the bootloader does not load the 32 bit kernel that was compiled. I've heard I need to set Protected Mode, A20, and I've tried copying and pasting some examples to see if they work or any thing but for some reason I can't get them to work, can some one give me a basic example of a bootloader that will load a 32 bit kernel?
- kataklinger
- Member
- Posts: 381
- Joined: Fri Nov 04, 2005 12:00 am
- Location: Serbia
There are two ways to do that, first you can stay in rmode and use BIOS to load kernel image from FDD/HDD/CD in memory under 1MB mark, then enter the pmode (and enable A20 line), copy kernel image to higher memory and jump to kernel, or you can enter pmode right away and write your own pmode FDD/ATA/ATAPI driver, so then you can load kernel right away at any memory location. I think the second one is better but it's harder! And there is a third solution you can use some existing bootloader like GRUB.
-
- Posts: 2
- Joined: Wed Nov 15, 2006 12:01 am
Hrm Hrm Hrm
I sorta was trying to pry an example out of someone
Well, I have a 2 sector boot loader, the first part is specific to the file system/boot device, while the second (.inc file) is not specific at all, just relies on calls to the first sector. My second 'stage' if you will is the part that actually does the loading into pmode, sets up my virtual memory stuff, and determines physical ram, etc. Here is a copy of my second sector, which could easily be changed to do what you'd like. It memory maps the lower region so it doesn't crash on change to pmode, and also loads 4 entries (defined in my first sector), these are specific drivers that are required for this boot device (so i can load my OS from just about any boot device by simply changing the first sector of my boot loader, and supplying drivers for the specific device and file system). Some things not included in this file are in the first section, this is compiled with NASM. Kernel is located at 0xF0002000, so if it's in ASM, you will need to ORG 0xF0002000, if it's in C/C++ you will need to link at this location. Let me know if you have questions or need help makign something more specific to your needs. My kernel uses virtual memory, so a lot of this might be overkill for you .
[/code]
Code: Select all
;Second Stage, depend's on a few calls to first stage, but this is independant of file system/disk!
[bits 16]
;Our 16-bit functions
A20Loop:
mov cx, 0x2000 ;8k tries!
A20Looper:
in al, 0x64
test al, 2
loopne A20Looper
ret
;Lets setup our new text mode before going to far... (80x50)
SetTextMode:
mov ax, 0x1112
xor bx, bx
int 0x10
mov word [0x60], 0x07 ;cursor to blank!
ret
EnableA20:
;Enable the A20 line
call A20Loop
jnz .EnableA20Done
mov al, 0xd1
out 0x64, al
call A20Loop
jnz .EnableA20Done
mov al, 0xdf
out 0x60, al
call A20Loop
.EnableA20Done
ret
;Print char in al
PrintChar:
push ax
push bx
mov ah, 0x0e
mov bx, 0x07
int 0x10
pop bx
pop ax
ret
PrintHex:
db 0x66
pusha
mov ecx, 8 ;8 values!
push word 13
push word 10
.ValueToStack
mov eax, edx
and eax, 15
shr edx, 4
cmp ax, 10
jl .Number
add al, 'A'-10-'0'
.Number
add al, '0'
push ax
loop .ValueToStack
push word 'x'
push word '0'
mov ecx, 12 ;8 values + CrLf + 0x
.PrintHexNext
pop ax
call PrintChar
loop .PrintHexNext
;This runs once ecx hits 0
db 0x66
popa
ret
;Create a memory mapping of the system!
FindMemory:
mov ax, 0xe801 ;Read system ram :)
xor ecx, ecx
xor edx, edx
int 0x15
shl ecx, 10 ;Multiply by 1024 to get MB's
;Returns 64kb blocks above 16mb into bx
shl edx, 16 ;Multiply by 16 to get MB's
add ecx, edx
cmp ecx, 0 ;Check if we have 0 bytes!
jne .MemGood
;Fallback?
mov ecx, 3*1024*1024 ;Assume 3mb + 1mb below = 4mb!
.MemGood
add ecx, 1024*1024 ;Tack on one extra meg since it only shows 15mb under 16mb!
mov [SystemMemory], ecx
ret
SecondStage:
call EnableA20 ;Enable our A20 line
mov ecx, 4
mov ebx, 0x9000
mov edx, LoadEntries
mov eax, [DataStart] ;Start sector of our kernel
.EntryLoop
push cx
mov cx, [edx] ;Sector count
cmp cx, 0
je .NothingThere
call ReadSector
.NothingThere
push edx
mov edx, eax ;LBA
call PrintHex
mov edx, ecx ;Sector Count
call PrintHex
pop edx
add eax, ecx ;Increment LBA...
shl cx, 9 ;Multiply by 512 to get byte count!
add bx, cx ;Move to next memory address
add edx, 2 ;Next entry
pop cx
loop .EntryLoop
;All 4 sections loaded...
;1 - Kernel
;2 - Memory Manager
;3 - Disk Driver
;4 - File System Driver
call SetTextMode ;Set our new text mode
call FindMemory ;Find the amount of memory we have in the system
;Lets get into 32-bit mode now
;Next thing is get into 32-bit mode
lgdt [gdt_desc]
cli ;Clear interrupts before we switch to 32-bit mode
mov eax, cr0
inc eax
mov cr0, eax
jmp 0x8:Go32 ;Jump to 32-bit code
[bits 32]
Go32:
mov eax, 0x10
mov ds, eax
mov es, eax
mov gs, eax
mov fs, eax
mov ss, eax
mov esp, 0x7000 ;Put stack right before some stuff :)
;Now lets enable paging...
;We're currently at 0x9000, we want to first map the bottom 1mb of memory...
;Mark each of these as completely available, but not loaded yet...
mov edi, Kern_PDE ;Kernel base :)
call SetAllAvailable
mov edi, Kern_PTE ;Kernel space :)
call SetAllAvailable
xor eax, eax ;Virtual Address
mov ebx, eax ;Physical Address
mov ecx, 256 ;Map only first 1mb
mov edx, Tmp_PTE ;Used to map lower 1mb
call MemoryMap ;Map this area :)
mov eax, 0xF0000000 ;Virtual address
mov ebx, 0x7000 ;Kernel address - 4k for functions + 4k for IDT
mov ecx, 64 ;First 256kb memory mapped
mov edx, Kern_PTE ;PTE to map kernel space
call MemoryMap
;Now lets map ourself
mov dword [Kern_PDE+0xDFC], Kern_PDE+3 ;Set it to itself!
mov eax, Kern_PDE
mov cr3, eax
mov eax, cr0
or eax, 0x80000000 ;Enable paging
mov cr0, eax
mov dl, [BootDisk]
mov dh, [BootPartition]
mov eax, [SystemMemory]
jmp 0xF0002000 ;Jump to kernel code at 0xF0002000
;edi = PDE/PTE to set!
SetAllAvailable:
mov eax, 0x200 ;Available, but not loaded
mov ecx, 1024 ;1024*4 = 4k
rep stosd
ret
;Memory map a 4mb region (not present)
;eax - virtual location, must be 4mb aligned
;ebx - physical memory to map, must be 4kb aligned
;ecx - number currently present
;edx - location of PTE
MemoryMap:
pusha
shr eax, 20 ;Divide by 1mb (divide by 4mb and mult index by 4)
add eax, Kern_PDE ;Add base address of PDE
mov [eax], edx ;Set the PDE entry to point to PTE
or byte [eax], 3 ;Set up for supervisor r/w
or ebx, 3 ;Set it up for supervisor : read/write present
.Loop
mov [edx], ebx ;Store the address here
add ebx, 4096 ;Next physical address
add edx, 4 ;Next entry
loop .Loop
popa
ret
Kern_PDE equ 0xC000 ;Location of first PDE
Kern_PTE equ 0xD000 ;First 4mb of kernel
Tmp_PTE equ 0xE000 ;PTE to map bottom 4mb
KernelPages dd 0 ;# of pages used for kernel/base drivers
gdt: ; Address for the GDT
gdt_null: ; Null Segment
dw 0
dw 0
db 0
db 0
db 0
db 0
gdt_code: ; Code segment, read/execute, nonconforming
dw 0xFFFF
dw 0
db 0
db 10011010b
db 11001111b
db 0
gdt_data: ; Data segment, read/write, expand down
dw 0xFFFF
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end: ; Used to calculate the size of the GDT
gdt_desc: ; The GDT descriptor
dw gdt_end - gdt - 1 ; Limit (size)
dd gdt ; Address of the GDT
times 1024-($-$$) db 0