Bootloader 32 bit kernel, A20? Pmode?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
treehunter
Posts: 2
Joined: Wed Nov 15, 2006 12:01 am

Bootloader 32 bit kernel, A20? Pmode?

Post by treehunter »

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?
User avatar
kataklinger
Member
Member
Posts: 381
Joined: Fri Nov 04, 2005 12:00 am
Location: Serbia

Post by kataklinger »

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.
RedEagle
Member
Member
Posts: 31
Joined: Sat Nov 04, 2006 5:38 am
Location: Earth
Contact:

Post by RedEagle »

I use int 0x15 (ah = 0x87) to use the higher memory in 16Bit-mode.
so i can load the whole floppydisk to higher memory in RM-mode.
mfg.: RedEagle
treehunter
Posts: 2
Joined: Wed Nov 15, 2006 12:01 am

Hrm Hrm Hrm

Post by treehunter »

I sorta was trying to pry an example out of someone ;-)
Ready4Dis
Member
Member
Posts: 571
Joined: Sat Nov 18, 2006 9:11 am

Post by Ready4Dis »

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: 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
[/code]
Post Reply