Page 1 of 2

Who Uses GRUB?

Posted: Fri Feb 02, 2007 6:27 pm
by pcmattman
I just thought this would be interesting to find out how many use GRUB and how many use their own custom bootloader.

If you do write your own, post it's code for others to peruse.

Re: Who Uses GRUB?

Posted: Fri Feb 02, 2007 10:29 pm
by SpooK
pcmattman wrote:I just thought this would be interesting to find out how many use GRUB and how many use their own custom bootloader.

If you do write your own, post it's code for others to peruse.
Now, who will be the first "courageous" person to offer the spoon-full of source code :P

Posted: Fri Feb 02, 2007 10:58 pm
by Android Mouse
I've only used grub. I might take on the challenge of writing one later on though.

Posted: Sat Feb 03, 2007 3:24 am
by JoeKayzA
I did both, but ATM I'm using GRUB only. Maybe I'll write my own later on, especially on other platforms.

Posted: Sat Feb 03, 2007 3:35 am
by AJ
I've gone for the 'use often' - I used to use my own boot loader as a learning excercise. Now I have done that, I've realised that GRUB is likely to be much more versatile than my own loader will ever be.

I am currently working on a second stage boot loader for my OS (does more with VESA, provides more information to the kernel, sets up paging, GDT and stack in the location I want etc...) which I hope to make fairly versatile - like with PDCLib where you just have to alter one header file to make it compatible with your own kernel. Oh - it also does COM debugging.

When I have a basic 'working unit' I'm happy with, I'll release the source and images as version 0.1 and see where it goes :)

Cheers,
Adam

Posted: Sat Feb 03, 2007 6:54 am
by Brendan
Hi,

I went for the "always write my own" option, although this isn't strictly correct...

My OS is designed for any number of different boot loaders, and for the last version of my OS I wrote a GRUB boot loader that ignores all the info GRUB supplied, switches back to real mode and restores the computer to the state my second stage expects. Eventually I'll probably port this to the new version of my OS.

IMHO this doesn't entirely count as "using" GRUB as most of the code is there to undo things GRUB did, and it's not intended as a "native" part of the OS - it's more like a compatability layer for situations where GRUB can't be easily removed (e.g. dual boot machines where someone elses OS uses GRUB).


Cheers

Brendan

Posted: Sat Feb 03, 2007 11:09 am
by Combuster
I think grub is a good program, and my kernel supports it. however, i have a custom bootloader which is much smaller which I use for floppy booting.

The reason for this is that i want to dual-boot with my own os, and grub would be the obvious way to do so.

So with the future in mind, I chose "often"

Re: Who Uses GRUB?

Posted: Sat Feb 03, 2007 5:33 pm
by pcmattman
SpooK wrote:Now, who will be the first "courageous" person to offer the spoon-full of source code :P
I get your point. This is my bootloader:

Code: Select all

; Mattise Boot Sector
; Assemble with NASM

            bits 16
            org 0x7C00

start:      jmp short begin
            nop
bsOEM       db "Mattise1"               ; OEM String
bsSectSize  dw 512                      ; Bytes per sector
bsClustSize db 1                        ; Sectors per cluster
bsRessect   dw 1                        ; # of reserved sectors
bsFatCnt    db 2                        ; # of fat copies
bsRootSize  dw 224                      ; size of root directory
bsTotalSect dw 2880                     ; total # of sectors if < 32 meg
bsMedia     db 0xF0                     ; Media Descriptor
bsFatSize   dw 9                        ; Size of each FAT
bsTrackSect dw 18                       ; Sectors per track
bsHeadCnt   dw 2                        ; number of read-write heads
bsHidenSect dd 0                        ; number of hidden sectors
bsHugeSect  dd 0                        ; if bsTotalSect is 0 this value is
                                        ; the number of sectors
bsBootDrv   db 0                        ; holds drive that the bs came from
bsReserv    db 0                        ; not used for anything
bsBootSign  db 29h                      ; boot signature 29h
bsVolID     dd 0                        ; Disk volume ID also used for temp
                                        ; sector # / # sectors to load
bsVoLabel   db "MATTISEOS  "            ; Volume Label
bsFSType    db "FAT12   "               ; File System type

begin:      cli                         ; disable interrupts
            mov [bsBootDrv],dl          ; save drive number
            mov ax,0x9000               ; put stack at 0x98000
            mov ss,ax
            mov sp,0x8000

            mov cx,[bsTrackSect]        ; update int 1E FDC param table
            mov bx,0x0078
            lds si,[ds:bx]
            mov byte [si+4], cl
            mov byte [si+9], 0x0F

            sti                         ; enable interrupts
            push ds
            mov dl,[bsBootDrv]          ; reset controller
            xor ax,ax
            int 0x13
            pop ds
            jc bootfail2                ; display error message
            jmp _l1
bootfail2:  jmp bootfail
_l1:
            mov ax,0x0000
            mov es,ax
            mov ds,ax

            mov si,MsgLoad              ; display load message
            call putstr

            ; find the root directory

            xor ax,ax
            mov al,[bsFatCnt]
            mov bx,[bsFatSize]
            mul bx
            add ax,word [bsHidenSect]
            adc ax,word [bsHidenSect+2]
            add ax,word [bsRessect]     ; ax holds root directory location
            mov word [BootSig],ax

            call checkroot

	    mov bx,word [bsVolID]
	    mov word [filesect],bx

            xor ax,ax
            add ax,word [start]
            add ax,word [bsVolID]       ; sector number
            add ax,word [BootSig]
            sub ax,2                    ; correction for a mis-calc
            mov cx,word [bsVolID+2]     ; number of sectors

            mov bx,0x8000
            mov es,bx


nextsector: push ax                     ; save registers
            push cx
            push dx
            push es

            xor bx,bx                   ; set zero offset
            call readsect               ; read a sector

            mov si,MsgDot               ; display a dot
            call putstr

            pop es                      ; restore registers
            pop dx
            pop cx
            pop ax
            mov bx,es
            add bx,20h                  ; increment address 512 bytes
            mov es,bx
            inc ax                      ; read next sector
            loopnz nextsector

            mov si,MsgComp               ; display a dot
            call putstr

            mov ax,0x8000               ; set segment registers and jump
            mov es,ax
            mov ds,ax
            push ax
            mov ax,0
            push ax
            retf

checkroot:
            push ax                     ; save registers
            push bx
            push cx
            push dx
            push si
            push di
            
            mov ax,0x8000               ; put root directory at 0x80000
            mov es,ax
            mov ax,32                   ; AX = ((32*RootSize)/512) + 2
            mul word [bsRootSize]
            div word [bsSectSize]
            mov cx,ax                   ; cx holds # of sectors in root
            mov word [start],ax
            mov ax,word [BootSig]       ; get prev. saved loc. for root dir

r1:         xor bx,bx
            push cx                     ; save count
            push ax                     ; save sector number
            push es
            push dx
            call readsect
            xor bx,bx
l_1:        mov di,bx                   ; set address to check from
            mov cx,11                   ; check 11 bytes
            mov si,FileName             ; address of string to check with
            repz cmpsb
            je foundit
            add bx,32                   ; check next entry
            cmp bx,[bsSectSize]         ; end of sector?
            je l_2
            jmp l_1
l_2:        pop dx                      ; restore registers
            pop es
            pop ax
            pop cx
            inc ax                      ; read next sector
            loopnz r1
            jmp bootfail
foundit:    pop dx                      ; get these off the stack
            pop es
            pop ax
            pop cx

            mov di,0x1A                 ; get clustor #
            add di,bx
            push bx                     ; save bx for finding # of sectors
            mov ax,[es:di]
            xor bx,bx                   ; calculate sector #
            mov bl,[bsClustSize]
            mul bx                      ; ax holds sector #
            mov word [bsVolID],ax

            pop bx                      ; get location of directory entry
            mov di,0x1C
            add di,bx
            mov ax,[es:di]              ; put number of bytes in ax
            xor dx,dx
            mov bx,[bsClustSize]        ; # of bytes / 512
            div bx
            inc ax
            mov word [bsVolID+2],ax     ; save number of sectors to load

            pop di                      ; restore registers
            pop si
            pop dx
            pop cx
            pop bx
            pop ax
            
            ret                         ; return to caller
            
putstr:     ; SI = address of string to display
            lodsb
            or al,al
            jz short putstrd
            mov ah,0x0E
            mov bx,0x0007
            int 0x10
            jmp putstr
putstrd:    retn                        ; return to caller

bootfail:   ; display failure message
            mov si,MsgBad               ; display error message
            call putstr
            xor ax,ax                   ; wait for keypress
            int 0x16
            int 0x19                    ; reboot

readsect:   ; ES:BX = Location ; AX = Sector
            mov si,[bsTrackSect]
            div si                      ; divide logical sect by track size
            inc dl                      ; sector # begins at 1
            mov [bsReserv],dl           ; sector to read
            xor dx,dx                   ; logical track left in ax
            div word [bsHeadCnt]        ; leaves head in dl, cyl in ax
            mov dh, [bsBootDrv]         ;
            xchg dl,dh                  ; head to dh, drive to dl
            mov cx,ax                   ; cyl to cx
            xchg cl,ch                  ; low 8 bits of cyl to ch, hi 2 bits
            shl cl,6                    ; shifted to bits 6 and 7
            or cl, byte [bsReserv]      ; or with sector number
            mov al,1                    ; number of sectors
            mov ah,2                    ; use read function of int 0x13
            int 0x13                    ; read sector
            jc bootfail                 ; display error message
            ret                         ; return to caller

FileName    db "MATTISE COM"
MsgBad      db "Couldn't boot!",13,10,0
MsgDot      db ".",0
Newline	    db 13,10,0
MsgLoad     db "Mattise Loading...",0
MsgComp	    db " Complete!",13,10,0
filesect    dw 0
times	    510-($-$$) db 0
BootSig     db 0x55, 0xAA
Although I have found myself using BootProg more often. I would use GRUB but I can't get it to install on my Windows box... a disk image with GRUB already on it would mean I could use it.

Posted: Sat Feb 03, 2007 5:45 pm
by Ready4Dis
Firstly, here is my multi-boot MBR so I can boot from more than a single partition, i actually use this on this machine, and it works great:

Code: Select all

[bits	16]
[org	0]

jmp	short	Start

Choice
	db	'0'							;Default partition, set by fdisk type program!

Start:
;Setup our stack
	xor		eax,	eax				;This is where we got loaded
	mov		ds,		ax
	mov		es,		ax
	mov		ax,		0x7c0			;Right before boot sector!
	mov		sp,		ax

;Lets copy ourself to another free location
	mov		si,		0x7c00			;Were we are now
	mov		di,	Location			;Move to our new location
	mov		ecx,	512/4			;Total bytes to move
	rep		movsd

	jmp		0:Reloaded+Location

Reloaded:
	mov		[BootDisk+Location],	dl		;Store boot disk

	mov		si,	BootMessage+Location
	call	PrintText

.AskAgain
	xor		edx,	edx							;Partition zero
	mov		eax,	Location+PartEntry+8		;Start of partitions + LBA

	mov		[Location+PartEntry],	dl
	mov		[Location+PartEntry+16],	dl
	mov		[Location+PartEntry+32],	dl
	mov		[Location+PartEntry+48],	dl

.Again
	mov		ebx,	[eax]					;LBA
	cmp		ebx,	0
	je		.NoPartition
	call	PrintNum
	mov		si,	BootPart+Location
	call	PrintText
	pusha
	mov		edx,	ebx
	call	PrintNum
	mov		si,		PartSep+Location
	call	PrintText
	mov		edx,	[eax+4]					;Size in sectors
	shr		edx,	11						;Divide by 2048 (*1024*1024/512, mb)
	call	PrintNum
	mov		si,	PartEnd+Location
	call	PrintText
	popa
.NoPartition
	add		eax,	16						;Next...
	inc		dx
	cmp		dx,		4
	jne		.Again

	mov		bx,		182						;10 seconds
;	mov		bx,		91						;5 seconds
;	mov		bx,		9						;1/2 second, just enough to see boot menu ;)
;	mov		bx,		46						;2.5 seconds, just enough to see boot menu ;)
	add		bx,		[0x46c]					;Bios clock!

.KeyWait
	mov		ah,		1
	int		0x16
	jnz		.GetKey
	cmp		bx,		[0x46c]
	jge		.KeyWait						;Still waiting...
	mov		al,		[Choice+Location]		;Default partition
	jmp		.Default						;Default

.GetKey
	xor		ax,		ax
	int		0x16
	call	PrintChar
.Default

;Lets boot the partition now!
	xor		ecx,	ecx
	mov		cl,		al						;Get our choice
	mov		eax,	Location+PartEntry
	sub		cl,		'0'						;Now go from character to drive!

	shl		ecx,	4						;Multiply by 16
	add		eax,	ecx						;Move to the correct table
	add		eax,	8						;Go to LBA of partition

	mov		ebx,	[eax]
	cmp		ebx,	0
	je		.AskAgain

;Update our _lba to start of partition
	mov		[_lba+Location],	ebx			;Put LBA of boot sector into _lba

;Write our MBR back out before reading the new one :)
	sub		eax,	8
	mov		dl,		[BootDisk+Location]
	mov		[eax],	dl								;Store our boot disk back into this
	mov		dh,		0								;Head
	mov		cx,		1								;Sector 1/Cylinder 0
	mov		ax,		0x0301							;Write, 1 sector
	mov		bx,		Location
	int		0x13

;Reset drive
;	mov		ah,		0
;	int		0x13
.ReadBootSector
;Lets use LBA
	mov		dl,		[BootDisk+Location]
	mov		ah,		0x42					;LBA read
	mov		si,		_boot_lba+Location		;information block!
	int		0x13
	jc		.ReadBootSector

	mov		dl,		[BootDisk+Location]			;Let the bootsector know our boot drive
 
	jmp		0:0x7c00							;Jump to the boot sector where it thinks the bios loaded it ;)

;Inputs
;	edx = value
PrintNum:
	pusha
	mov		eax,	edx
	mov		ebx,	10
	xor		ecx,	ecx

.ValueToStack
	xor		edx,		edx			;Zero out dx
	div		ebx
	add		dx,	'0' 
	push	dx
	inc		ecx						;Add to counter
	cmp		eax,	0
	jne		.ValueToStack

.PrintDecNext
	pop		ax
	call	PrintChar
	loop	.PrintDecNext
	popa
	ret

;Print char in al
PrintChar:
	push	ax
	push	bx
	mov		ah,		0x0e
	mov		bx,		0x07
	int		0x10
	pop		bx
	pop		ax
	ret

;si = message
PrintText:
	push	ax
.PrintNext
	lodsb			;Load es:si into al
	test	al,		al
	jz		.Done
	call	PrintChar
	jmp		.PrintNext	;Repeat
.Done
	pop		ax
	ret

_boot_lba
	db	0x10
	db	0
_length
	dw	1		;1 sector
_location
	dw		0x7c00
_segment
	dw	0
_lba
	dd	0	;Sector to read, 4 bytes!
	dd	0	;Upper part of lba (8 bytes total!)

BootMessage
	db	'PhatOS Multi Booter',13,10,0

BootPart
	db	'.) LBA ',0

PartSep
	db	' Size : ',0
PartEnd
	db	'mb',13,10,0

BootDisk			;Disk we booted from
	db		0

Location		equ		0x8000			;Some random place out of the way
tick			equ		0x46c			;Location of bios tick count!
PartEntry		equ		446				;Start of partition entries

times 446-($-$$) db 0				;Up to boot sector info
times 510-($-$$) db 0				;Up to boot signature
dw	0xaa55
Ok, so now my boot loader has more than one part... the first part I replace depending on the file system/boot device,the second part doesn't change. First my Fat32 standard HD boot sector.

Code: Select all

[bits	16]
[org	0x7c00]

jmp		short	Start							;0-2
nop

;Lets make our BPB
OEMName				db		'PhatOS  '
BytesPerSector		dw		512					;512 bytes is normal ;)
SectorsPerClustor	db		1					;Sector == cluster
ReservedSectors		dw		1					;Reserve the boot sector
FatCount			db		1					;1 copy of the fat (some things require this)
RootEntries			dw		224					;# of root entries
TotalSectors16		dw		0					;# of sectors on the disk
MediaType			db		0xF8				;Ignored for most things
FatSize16			dw		0					;Size of a single fat in sectors
SectorsPerTrack		dw		0					;Sectors Per Track
Heads				dw		0					;Head count
HiddenSectors		dd		0					;# of hidden sectors
TotalSectors32		dd		0					;# of sectors, 32-bit!

;Fat32 section
FatSize32			dd		0					;Size of a single Fat in sectors
ExtFlags			dw		0					;Used for mirroring, leave this alone
FSVersion			dw		0					;Our version is 0.0 :)
RootCluster			dd		2					;Cluster # of root, normally 2
FSInfo				dw		0					;Sector # of FS Info Block
BkBootSector		dw		0					;Backup boot sector... unused for us ;)
Reserved1			times	12	db	0			;Reserved
DriveNum			db		0					;We don't care for this
Reserved2			db		0					;Reserved
BootSig				db		0x29				;0x29 - next 3 things exist
VolumeID			dd		0					;Volume's ID, we don't care for it ;)
VolumeLabel			db		'PhatOS     '		;11 bytes
FileSystem			db		'FAT32   '			;File system

Start:
	cld
	mov		[BootDisk],			dl			;Store boot disk

	;Set up our stack at	0x07c0:0x0000 (goes downwards!)
	xor		ax,		ax
	mov		ss,		ax
	mov		es,		ax
	mov		ax,		0x07c0
	mov		sp,		ax

;Read our MBR to see what partition we booted from
	mov		eax,	0								;MBR
	mov		bx,		0x1000							;Random free address
	mov		cx,		1								;One sector
	call	ReadSector
	xor		ecx,	ecx
	mov		eax,	0x1000+446

;Lets determine boot partition + LBA
.CheckNext
	cmp		byte [eax],	0			;Would be 0x80
	jne		.FoundBootPartition
	inc		cx
	cmp		cx,		4
	je		.DidntFindMBR
	add		eax,	16
	jmp		.CheckNext

.FoundBootPartition
	mov		[BootPartition],	cl			;Store boot partition here...
	mov		ebx,	[eax+8]					;Store into ebx
	mov		[PartitionLBA],	ebx				;Store this here...
.DidntFindMBR

;Lets determine our Data Start now... based on params above :)
	xor		edx,	edx
	mov		ebx,	edx
	mov		eax,	[FatSize32]
	mov		dl,		[FatCount]
	mov		bx,		[ReservedSectors]
	or		ax,		[FatSize16]
	mul		dx
	add		eax,	ebx
	inc		eax
	mov		[DataStart],	eax				;This is our start sector of our kernel :)

;Lets load our second stage :)
	mov		eax,	1						;Start of 2nd stage
	mov		bx,		0x7c00+512				;Right after boot sector!
	mov		cx,		3						;3 sectors
	call	ReadSector
	jmp		SecondStage						;Go to our second stage loader

BootDisk				;Disk we booted from
	db		0
BootPartition			;Partition on disk we booted from (0xFF = no partitions!)
	db		0xFF
PartitionLBA			;LBA of the boot partition
	dd		0
SystemMemory			;Memory in bytes,4gb max
	dd		0

;Read a sector from the boot disk/partition
;eax - sector to read
;bx - dest
;cx - length
ReadSector:
	db	0x66
	pusha
	mov		dl,		[BootDisk]					;Use boot disk
	add		eax,	[PartitionLBA]				;Start of partition
	mov		[_lba],			eax					;Store linear block address
	mov		[_location],	bx					;Store location
	mov		[_length],		cx					;Length in sectors
	mov		ah,		0x42						;Read function
	mov		si,		_boot_lba					;Location of LBA block
	int		0x13
	db	0x66
	popa
	ret

_boot_lba
	db	0x10			;Size of lba block structure :)
	db	0
_length
	dw	0				;Filled in from above!
_location
	dw	0				;4k page bounary
_segment
	dw	0
_lba
	dd	0	;Sector to read, 8 bytes total!
	dd	0

DataStart			dd	0

times 502-($-$$)	db	0	;Last, enough for 4 entries :)
LoadEntries:			;Stores size of each file in sectors
times 510-($-$$)	db	0
dw	0xaa55

%include '2ndStage.inc'
And, here is one for fat12/fat16 floppy disk or hard drive :)

Code: Select all

[bits	16]
[org	0x7c00]

jmp		short	Start							;0-2
nop

;Lets make our BPB
OEMName				db		'PhatOS  '
BytesPerSector		dw		512					;512 bytes is normal ;)
SectorsPerClustor	db		1					;Sector == cluster
ReservedSectors		dw		1					;Reserve the boot sector
FatCount			db		1					;1 copy of the fat (some things require this)
RootEntries			dw		224					;# of root entries
TotalSectors16		dw		0					;# of sectors on the disk
MediaType			db		0xF8				;Ignored for most things
FatSize16			dw		0					;Size of a single fat in sectors
SectorsPerTrack		dw		0					;Sectors Per Track
Heads				dw		0					;Head count
HiddenSectors		dd		0					;# of hidden sectors
TotalSectors32		dd		0					;# of sectors, 32-bit!

;Start of our Fat12/16 info
DriveNum			db		0					;Drive number (0x0x - floppy, 0x8x - hd
Reserved			db		0					;Reserved, set to 0
BootSig				db		0x29				;Set to 0x29 if next 3 values are present
VolumeID			dd		0					;Volume's ID, we don't care for it ;)
VolumeLabel			db		'PhatOS     '		;11 bytes
FileSystem			db		'FAT     '			;File system

Start:
	cld
	mov		[BootDisk],			dl		;Store boot disk

	;Set up our stack at	0x07c0:0x0000 (goes downwards!)
	xor		ax,		ax
	mov		ss,		ax
	mov		es,		ax
	mov		ax,		0x07c0
	mov		sp,		ax

;Determine which read function to use...
	test	dl,		0x80							;Hard Disk Bit?
	jnz		.KernelHD								;Lets use LBA if bit set
	mov		dword [ReadSectorFunc],	ReadSectorFD
	jmp		DidntFindMBR
.KernelHD
	mov		dword [ReadSectorFunc],	ReadSectorHD	;Use HD function

;Read our MBR to see what partition we booted from
	mov		eax,	0								;MBR
	mov		bx,		0x1000							;Random free address
	mov		cx,		1								;One sector
	call	ReadSector
	xor		ecx,	ecx
	mov		eax,	0x1000+446

;Lets determine boot partition + LBA
.CheckNext
	cmp		byte [eax],	0			;Would be 0x80
	jne		.FoundBootPartition
	inc		cx
	cmp		cx,		4
	je		DidntFindMBR
	add		eax,	16
	jmp		.CheckNext

.FoundBootPartition
	mov		[BootPartition],	cl			;Store boot partition here...
	mov		ebx,	[eax+8]					;Store into ebx
	mov		[PartitionLBA],	ebx				;Store this here...
DidntFindMBR:

;Lets determine our Data Start now... based on params above :)
	xor		edx,	edx
	mov		ebx,	edx
	mov		eax,	edx
	mov		ecx,	edx
	mov		cx,		[RootEntries]
	shr		cx,		4						;Divide by 16 to get # of sectors
	mov		dl,		[FatCount]
	mov		bx,		[ReservedSectors]
	mov		ax,		[FatSize16]
	mul		dx
	add		eax,	ebx
	add		eax,	ecx
	mov		[DataStart],	eax				;This is our start sector of our kernel :)

;Lets load our second stage :)
	mov		eax,	1						;Start of 2nd stage
	mov		bx,		0x7c00+512				;Right after boot sector!
	mov		cx,		1						;1 sector

	call	ReadSector
	jmp		SecondStage						;Go to our second stage loader


BootDisk				;Disk we booted from
	db		0
BootPartition			;Partition on disk we booted from (0xFF = no partitions!)
	db		0xFF
PartitionLBA			;LBA of boot partition
	dd		0
SystemMemory			;Memory in bytes,4gb max
	dd		0
ReadSectorFunc
	dd		0			;Which read function to use

ResetDrive:
	pusha
.Retry
	mov		ax,		0
	mov		dl,		[BootDisk]					;Drive [BootDisk]
	int		0x13
	jc		.Retry							;Didn't reset, lets try again
	popa
	ret
	
;Convert LBA -> CHS
;Inputs:
;	eax - sector
;	cx - length
;	bx - destination
;Outputs: Standard CHS format
GetCHS:
	xor		edx,	edx					;Zero out edx
	div		word [SectorsPerTrack]
	mov		cl,		dl					;Sector # ?
	inc		cl
	xor		edx,	edx
	div		word [Heads]
	mov		dh,		dl					;Mov dl into dh (dh=head)
	mov		ch,		al					;Mov cylinder into ch

;//??
	shl		ah,		6
	or		cl,		ah
	ret

;eax - sector to read
;bx - dest
ReadSingleSectorFD:
	db	0x66
	pusha
	call	GetCHS				;Grab our CHS
.Retry
	call	ResetDrive			;Get drive ready..
	mov		dl,	[BootDisk]		;Grab our boot disk
	mov		ax,	0x0201			;Read function, one sector
	int		0x13
	jc		.Retry
	db	0x66
	popa
	ret

;Floppy disk code
;eax - sector to read
;bx - dest
;cx - length
ReadSectorFD:
	db	0x66
	pusha

.ReadNext
	call	ReadSingleSectorFD
	dec		cx
	jz		.Done
	add		bx,		512				;Next location..
	inc		eax						;Next LBA
	jmp		.ReadNext				;Keep reading
.Done
	db	0x66
	popa
	ret

;Hard disk code
;eax - sector to read
;bx - dest
;cx - length
ReadSectorHD:
	db	0x66
	pusha
	mov		dl,		[BootDisk]					;Use boot disk
	add		eax,	[PartitionLBA]				;Start of partition
	mov		[_lba],			eax					;Store linear block address
	mov		[_location],	bx					;Store location
	mov		[_length],		cx					;Length in sectors
	mov		ah,		0x42						;Read function
	mov		si,		_boot_lba					;Location of LBA block
	int		0x13
	db	0x66
	popa
	ret

ReadSector:
	jmp		[ReadSectorFunc]					;Jump to the correct function

_boot_lba
	db	0x10
	db	0
_length
	dw	0				;Filled in from above!
_location
	dw	0x8000			;4k page bounary
_segment
	dw	0
_lba
	dd	0	;Sector to read, 8 bytes total!
	dd	0

DataStart			dd	0

times 502-($-$$) db	0	;Last, enough for 4 entries :)
LoadEntries:
times 510-($-$$) db 0
dw	0xaa55

%include '2ndStage.inc'
And lastly is the include file that these both include (2ndStage.inc)

Code: Select all

;Second Stage, completely I/O independant besides a few calls to first stage

[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 0xF0000000

;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
So, that's it, mbr is 512 bytes, boot loader is 1k no matter what boot medium (well, so far). It's still a work in progress, but works fine right now for what I'm doing. I need to do more work on the memory detection stuff, but other than that it is pretty much done.

Posted: Sun Feb 04, 2007 11:46 am
by xyjamepa
GRUB have been helping me in alot of things specially when i need to get the memory size ,and also it's so easy to use. :wink:

Posted: Sun Feb 04, 2007 9:16 pm
by beyondsociety
When I first started my operating system I went for writing my own custom bootloader as a learning process. In later versions, I decided to use grub as the bootloader simply because I had problems with my bootloader not working right with the kernel and wanted to move onto other things. For my current re-write of my os Im not sure if I will use grub or not, it depends on what design and architectures I decide to support. So I voted for using grub once or twice in my os.

Posted: Mon Feb 05, 2007 2:18 am
by prajwal
I use GRUB which is modified to support mosfs (MOS File System)...

Posted: Mon Feb 05, 2007 6:32 am
by TheQuux
For Xenon, I'm just using grub. For plan10 (a remake of plan9 on the SPARC64), I'm rolling my own due to a lack of a choice. Fortunately, I have 7.5K to play with, and the openprom actually is useful, which makes it easier.

Posted: Mon Feb 05, 2007 9:09 am
by JAAman
i prefer to write my own boot system

i wont post my current code, since im in the midst of a complete rewrite, but basically, my boot-sector parses the FAT file system to find the 2nd stage, and my 2nd stage uses the routines from the bootsector (my 2nd stage never needs to know what filesystem is in use, or what disk is being booted)

currently i only boot FAT12/16/32, but this system should allow easy booting on a number of different filesystems without modifying the 2nd stage

Posted: Mon Feb 05, 2007 3:43 pm
by frank
I would use GRUB, but I'm picky. I have to know everything that is going on all the time. I don't want some magic bootloader loading my kernel.

This might change however if I ever implement any other filesystems.