Page 1 of 1

ELF Bootloader

Posted: Thu Nov 15, 2012 5:04 pm
by teodori
Hello everyone,
I have written a two stage bootloader, 1st stage loads sectors to memory then jumps to it, 2nd stage enables A20 and PMode. They are working very well, but both are in "binary" format and I want now to load an "elf32-i386" and jump to it. I imagine that a far jump won't be enough? Can anyone point me to the right direction? Thank you :)

Re: ELF Bootloader

Posted: Thu Nov 15, 2012 5:17 pm
by SparrowOS
When faced with the problem of boot loaders for FAT32, EXT2, EXT3, EXT4, NTFS, Reiser, I had a brilliant idea! I'll write one bootloader that uses a fixed-block address and when I install my operating system, I'll patch the block address and make sure it is contiguous.

I also do a minimum in my bootloaders, pushing work forward to a place without a size limit. Why do work in a boot-loader that has a 512 byte limit?

I wrote my own compiler and made my own binary file format. It sucks the UEFI uses elf. You should see the crap they put into UEFI. Unbelievable.

Re: ELF Bootloader

Posted: Thu Nov 15, 2012 6:09 pm
by teodori
Yep,
here is my boot loader which successfully loads a 32 bit executable in binary format :) ,
but now I want to load an elf32-i386 from the second sector and I don't know how to make the entry.

Code: Select all

.section .rodata

bootmsg:
	.asciz "loading..."
bootmsgend:

bootmsglen:
	.word (bootmsgend - bootmsg)

errmsg:
	.asciz "disk error!"
errmsgend:

errmsglen:
	.word (errmsgend - errmsg)

gdt:
	# Null Descriptor at 0x0
	.word 0x0000
	.word 0x0000
	.byte 0x00
	.byte 0x00
	.byte 0x00
	.byte 0x00
	# Code Descriptor at 0x8
	.word 0xffff
	.word 0x0500
	.byte 0x00
	.byte 0x9a
	.byte 0xcf
	.byte 0x00
	# Data Descriptor at 0x10
	.word 0xffff
	.word 0x0500
	.byte 0x00
	.byte 0x92
	.byte 0xcf
	.byte 0x00
gdt_end:

gdtptr:
	.word (gdt_end - gdt - 1)
	.long gdt

.section .text

.globl Start

Start:
	.code16

SaveDriveNumber:
	movb %dl, 0x7bff			# Copy DL to memory 0x7bff

SetVideoMode:
	clrb %ah							# Set Video Mode
	movb $0x03, %al				# 3rd Mode -> 80x25
	int $0x10							# Video Interrupt

ClearScreen:
	movb $0x06, %ah				# Clear Screen
	clrb %al							# Lines to scroll (0 = clear -> CX & DX)
	movb $0x0f, %bh				# Color Black White
	clrw %cx							# Upper Left Corner
	movb $25, %dh					# 25 Lines
	movb $80, %dl					# 80 Columns
	int $0x10							# Video Interrupt

PrintBootMsg:
	clrw %ax							# Set AX to 0x0
	movw %ax, %es					# Set Extra Segment to 0x0
	movw $bootmsg, %bp		# Set base pointer to msg location

	movb $0x13, %ah				# Print String
	movb $0x01, %al				# Char only - Cursor moved
	clrb %bh							# Page Number
	movb $0x09, %bl				# Color Black Blue
	movw bootmsglen, %cx	# Message Length
	movb $1, %dh					# Row 1 
	movb $1, %dl					# Column 1
	int $0x10							# Video Interrupt

SetA20:
	cli										# Disable Interrupts
	inb $0x92, %al				# Enable A20 Gate
	testb	$0x2, %al				# to access to more than
	outb %al, $0x92				# 1 Mega Byte of memory
	sti										# Enable Interrupts

ResetDisk:
	clrb %ah							# Reset Disk
	movb 0x7bff, %dl			# Drive (from Memory Loacation)
	int $0x13							# Disk Interrupt

	jc PrintErrorMsg			# If CF set jump to PrintErrorMsg

LoadFromDisk:
	movw $0x0050, %ax			# Set AX to 0x0050
	movw %ax, %es					# Set Extra Segment to 0x0050

	movb $0x02, %ah				# Read Disk Sectors
	movb $0x01, %al				# Read one sector only (512 bytes per sector)
	clrw %bx							# Offset 0 - Start of Segment
	clrb %ch							# Track 0
	movb $0x02, %cl				# Sector 2
	clrb %dh							#	Head 0
	movb 0x7bff, %dl			# Drive (from Memory Loacation)
	int $0x13							# Disk Interrupt

	jc PrintErrorMsg			# If CF set jump to PrintErrorMsg

	cli										# Disable Interrupts

LoadGDT:
	lgdt gdtptr						# Load Global Descriptor Table

EnterProtectedMode:
	movl %cr0, %eax				# Read from Control Register CR0
	orl $1, %eax					# Set Protected Mode Bit
	movl %eax, %cr0				# Write to Control Register CR

SetupSelectors:
	movw $0x0010, %ax			# Selector 0x0010
	movw %ax, %ds					# Set Data Segment
	movw %ax, %es					# Set Extra Segment
	movw %ax, %fs					# Set Data2 Segment
	movw %ax, %gs					# Set Data3 Segment
	movw %ax, %ss					# Set Stack Segment

	ljmp $0x8, $0x0				# Far Jump

PrintErrorMsg:
	clrw %ax							# Set AX to 0x0
	movw %ax, %es					# Set Extra Segment to 0x0
	movw $errmsg, %bp			# Set base pointer to msg location

	movb $0x13, %ah				# Print String
	movb $0x01, %al				# Char only - Cursor moved
	clrb %bh							# Page Number
	movb $0x04, %bl				# Color Black Red
	movw errmsglen, %cx		# Message Length
	movb $3, %dh					# Row 3
	movb $1, %dl					# Column 1
	int $0x10							# Print Message

	cli										# Disable Interrupts

Hang:
	hlt										# Halt CPU
	jmp Hang							# Infinit loop if Halt does not work

Re: ELF Bootloader

Posted: Fri Nov 16, 2012 1:49 am
by bluemoon
The minimum code to transfer control to a static linked elf-i386 file is getting the program entry field from the program header, this is an 32-bit number that located on fixed file offset.
That number will be in the form of virtual address, as specified by the linker script.
You can use that entry offset to translate to the actual memory location with a bit of calculations by:

Code: Select all

foreach "phdr struct" within ELF {
  if ( "entry point" within the region specified on this phdr ) {
    address = entry(VMA) - phdr(VMA) + phdr(offset) + file offset
  }
}
You may also need to adjust the address depends on where you actually load the elf file.

Grab a copy of the ELF_Format.pdf for detail.


ps. note that this method skipped a lot of things, it does not clear BSS, it assume the memory layout is the same as file layout, it assume BSS is on the end of file, etc - but it usually work as a simple loader, so you can go ahead working on the kernel and come back for a full loader later.

Re: ELF Bootloader

Posted: Fri Nov 16, 2012 4:38 am
by Griwes
SparrowOS wrote:When faced with the problem of boot loaders for FAT32, EXT2, EXT3, EXT4, NTFS, Reiser, I had a brilliant idea! I'll write one bootloader that uses a fixed-block address and when I install my operating system, I'll patch the block address and make sure it is contiguous.

I also do a minimum in my bootloaders, pushing work forward to a place without a size limit. Why do work in a boot-loader that has a 512 byte limit?

I wrote my own compiler and made my own binary file format. It sucks the UEFI uses elf. You should see the crap they put into UEFI. Unbelievable.
Yeah, it's unbelievable, especially since UEFI uses PE+...

Re: ELF Bootloader

Posted: Sun Nov 18, 2012 5:25 am
by Yoda
SparrowOS wrote:When faced with the problem of boot loaders for FAT32, EXT2, EXT3, EXT4, NTFS, Reiser, I had a brilliant idea! I'll write one bootloader that uses a fixed-block address and when I install my operating system, I'll patch the block address and make sure it is contiguous.
This will work until first disk defragmentation with making free space contiguous or until moving/copying/overwriting the file with bootloader.
SparrowOS wrote:I also do a minimum in my bootloaders, pushing work forward to a place without a size limit. Why do work in a boot-loader that has a 512 byte limit?
Till now the space in boot areas of at least FAT12/16/32/NTFS/Ext2/3 file systems is quite enough in case of PC architecture to boot file placed in root directory and located anywhere in the disk, even beyond 2TB limit.