Testing 2 Stage Bootloader on VirtualBox

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
NirajJha
Posts: 5
Joined: Thu Jul 20, 2017 11:36 pm
Libera.chat IRC: Niraj

Testing 2 Stage Bootloader on VirtualBox

Post by NirajJha »

Hello Everybody

I am trying to develop 16 bit sample 2 stage boot loader using visualstudio 1.5 and MASM 1.5 and want to test on the virtual box.

My sample code is

Code: Select all

.MODEL SMALL
.486p

	_TEXT	SEGMENT	WORD USE16 'CODE'
		ASSUME	CS:_TEXT, DS:_TEXT, ES:_TEXT

	ORG 	100H	
	ORG		0500H 	
	
	StartFromSecondSector:
		jmp		near ptr SecondSector
		nop
		ORG	0500H
		
		
	SecondSector:
			; Boot Code
		
	ORG 	7C00H
	ASSUME	CS:_TEXT, DS:_TEXT, ES:_TEXT	
	
	main:
		
			xor	ax, ax			
			mov	ds, ax
			mov	es, ax
			cli					
			mov	ss, ax			
			mov	sp, 4F00H	
			sti
			
			mov		dl, 80h
			mov		ah, 41h
			mov		bx, 55aah
			int		13h
			setnc	      is_ext
			
			mov		si, offset vol0
			mov		bx, 0400H
			
			test	       is_ext, 0ffh
			jz		short ErrorMSGPrompt
			
			mov		ah, 42h
			mov           dl, 80h
			int		13h
			jmp		StartFromSecondSector
			
			ORG		7C00H+1BEH	
			DB		64 DUP (0FFH)	

			DB		055H		
			DB		0AAH		

			ErrorMSGPrompt:
				; Error mesage int10

			_TEXT		ends
			
	end		main
After Assembling and making and 16 bit executable , i remove the EXE signature and placed the binary in 2 file . 1 stage0.DAT which contains the 512 bytes of code started from 7c00 and another file is stage1.DAT which contains the next 512 bytes of started from 500 offset.

In virtualbox vdi HDD of fixed size , i copied the 512 byte of stage0.dat from 0200000 and i copied the 512 bytes of stage1.DAT from 0200500

The stage0 works fine but the jump to the stage 2 is failing. is i am missing some thing ?

Thanks in Advance

Niraj
madanra
Member
Member
Posts: 149
Joined: Mon Sep 07, 2009 12:01 pm

Re: Testing 2 Stage Bootloader on VirtualBox

Post by madanra »

I would recommend using bochs debugger to step through instruction by instruction, to work out exactly where it is failing.

(Also: why are you stripping an EXE header rather than assembling to flat binary in the first place?)
LtG
Member
Member
Posts: 384
Joined: Thu Aug 13, 2015 4:57 pm

Re: Testing 2 Stage Bootloader on VirtualBox

Post by LtG »

Or doing a thousand ORG's, or extraneous cli/sti....
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Testing 2 Stage Bootloader on VirtualBox

Post by bzt »

LtG is right. You need exactly one ORG (maybe 2 with relocation), and use cli/sti instructions carefully. What's more, there's a reason why all boot loaders start with cli. Even more, your stack will very likely overwrite your code or data.

Suggestions:
1. read spec carefully, don't start writing a boot loader until you are 100% sure how memory layout looks like (the ORGs suggest you don't have a clue)
2. relocate your code if you want to support chainloading. 0:600h would be an appropriate place for that.
3. set up segment registers properly. You've forgotten to set up the most important segment register. Only original IBM BIOS used 0:7C00h, there are BIOSes that use 7C0h:0 (homework: learn about real mode addressing scheme and figure out why 0:7C00h == 7C0h:0).
4. place your stack out of the way, and calculate it's maximum size properly. Make sure it won't overwrite your code or data
5. as madanra suggested, boot loaders are raw flat binaries. There's a good chance that your assembler messes up segments when using EXE layout, and stripping header won't magically fix that.
6. learn about x86 instructions and BIOS interrupts. Code size is an essence. Use int/jc as it compiles to less bytes.
7. Don't assume you are booting from the first disk. Don't touch dl.
8. Your description on modifying the VDI is uninterpretable in this context. At what sector do you want to store 2nd stage? It must be sector aligned, at least. And if your stage1.DAT contains any code, you have seriously messed up something. Your code (from main label to the end) is less than 512 bytes...
9. If you've thought that your first jump will work (with wrong addresses and unloaded 2nd stage), then I'd suggest to study a lot before you start to write a boot loader. Right now, you definitely don't have the required knowledge.
NirajJha
Posts: 5
Joined: Thu Jul 20, 2017 11:36 pm
Libera.chat IRC: Niraj

Re: Testing 2 Stage Bootloader on VirtualBox

Post by NirajJha »

Thanks to All for this valuable input. I am new to this bootloader stuff and you are right i need to learn more.
I will go with single assembly for all.

Can i get any sample for this 2 stage bootloader for x86 machine so that i can go through that and learn .

Thanks
Niraj
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Testing 2 Stage Bootloader on VirtualBox

Post by bzt »

NirajJha wrote:Thanks to All for this valuable input. I am new to this bootloader stuff and you are right i need to learn more.
I will go with single assembly for all.

Can i get any sample for this 2 stage bootloader for x86 machine so that i can go through that and learn .

Thanks
Niraj
Welcome! Yes, there are a lot of examples in this forum and there's a very good description on the wiki as well. Also you can take a look at my code.

stage1 code that loads my stage2 and transfers control to it. I do not support floppies, only hard drives (and I don't support CHS, I use LBA addresses to load sectors from disk to memory. Suitable for USB sticks). I assume that the stage2 can be anywhere on the disk, it's continuous (if it's on a filesystem then the fs is defragmented) and it's first LBA is recorded in stage1 at 0x1B0. I have created an mkfs tool that will guarantee that. It's called mbr.asm, but don't let that confuse you, it works as a VBR too.

stage2 code is special as it complies with BIOS boot specification therefore it can be loaded not only by stage1, but from ROM as well. It's also compatible with GRUB's Multiboot. My goal was to achieve multiple ways to load stage2 in a single binary image, so it's a bit more complex than other examples you can find.

You can use my stage1 code (binary included) and write your own stage2 with VS if you like. Your stage2 must start with a 6 bytes header, but other than that you are free to do whatever you want (32 bytes header only required if you want to load your stage2 from ROM too, and 64 bytes if you also want it to be Multiboot compliant as well). I suppose (as you are using VS) you're not building on ELF but PE kernel? But if so, you can use both stages if you are okay with an ELF64 mapped at the last page directory in the memory, -2M. Both sources are public domain. You can find more documentation and precompiled binaries here.
NirajJha
Posts: 5
Joined: Thu Jul 20, 2017 11:36 pm
Libera.chat IRC: Niraj

Re: Testing 2 Stage Bootloader on VirtualBox

Post by NirajJha »

Thanks :D :D . I will Go through this .

Can i test this on virtual box vdi image. DO i need to copy of the 1st stage code 0200000 to 2001F0 and second stage from 0200600 to 0200B12 or from 0200200 .
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Testing 2 Stage Bootloader on VirtualBox

Post by bzt »

NirajJha wrote:Can i test this on virtual box vdi image. DO i need to copy of the 1st stage code 0200000 to 2001F0 and second stage from 0200600 to 0200B12 or from 0200200 .
Stage1 must be 200h bytes long, and stage2 must be multiple of 200h bytes. I suggest to create raw image, and copy the stage1 in the first sector of the disk at offset 0 (if you want to use it as an MBR) or in the first sector of a partition (if you intend to use it as VBR), and save the stage2's first lba address at dword 0x1B0 (which will be 2 if you add the stage2 right after the MBR and before the first partition).
I cannot tell you exactly where my stage2 is located, as I copy it as a simple file on the first partition. Depending on configuration, that first partition is either a FATx (in which case I use BOOTBOOT\LOADER) or a partition with my own fs, FS/Z (in that case I use /sys/loader). Regardless my disk creation utility (mkfs disk) locates the stage2 part and records it's starting sector in the MBR (and also stores stage1 code there). So when my image (bin/disk.dd) is finished, everything is at place to boot. If you want to test it with Virtualbox, you can use VBoxManage utility to create vdi from the raw image (part of Virtualbox, see my makefile for make vdi).

Other than that if you meant memory addresses, you cannot access memory above 0FFFFh in real mode (assuming your segment is 0). The stage1 is loaded at 7C00h (or 7C0h:0) by the BIOS, and then it relocates itself to 0:600h. The stage2 (which is loaded by stage1, GRUB or already accessible in ROM above C8000h) relocates itself after that, at 0:800h if necessary (the memory map is described in the beginning of the source in detail).

If you use BOOTBOOT stage1 and roll your own stage2, you should use ORG 800h, zero out segment registers and the stack pointer.

Code: Select all

    ORG 800H
SecondSector:
    DB 55H, 0AAH, 0, 0E9H  ; magic bytes, don't care, don't change
    DW main                ; label to execute on start
main:
    xor ax, ax
    mov sp, ax             ; see below
    mov ds, ax
    mov es, ax
    ...etc.
You shouldn't bother with size, checksum and relocation at all (as you don't want to store your stage2 in ROM) therefore the first 6 bytes won't change. Now I've also used a little trick here with the stack. When you push your first item on the stack, it will decrease the sp pointer from 0 which will wrap around to 0FFFEh and will store the item there. That's the highest address you can use in small model in real mode, therefore it provides the biggest space for your program and the stack. You can of course use "mov sp, 07C00h" if you like.

You can place your stage2 code anywhere on the disk (as long as it's sector aligned, that is), just don't forget to save the starting LBA address in stage1's sector (that can be detected with a hexeditor the same way my mkfs utility does: look for the magic bytes, then use offset/512+1). If you're not creating a raw image and convert it to vdi afterwards as suggested, then you should subtract the size of the vdi header (in other words the offset of MBR) from the offset first. So for example if vdi header is 200000h bytes long, mbr.bin should be copied to 200000h-2001FFh. If you choose to save your stage2 right after it, then store that to 200200h-207DFFh (or less if it's smaller), and set 2 at 2001B0h. If you choose to create a partition with your stage2 as a file on it, then locate the magic bytes in the vdi. Let's say they are at 201600h, then 2001B0h should be 0Ch ('cos (201600h-200000h)/200h+1=0Ch).
NirajJha
Posts: 5
Joined: Thu Jul 20, 2017 11:36 pm
Libera.chat IRC: Niraj

Re: Testing 2 Stage Bootloader on VirtualBox

Post by NirajJha »

Thanks a lot .. :) :) :)
NirajJha
Posts: 5
Joined: Thu Jul 20, 2017 11:36 pm
Libera.chat IRC: Niraj

Re: Testing 2 Stage Bootloader on VirtualBox

Post by NirajJha »

Hi ,

I have followed the given suggestion and perform the following
1. As I am using windows as mt dev machine , so Written Disk Filter Driver to read and write Disk sectors
2. Create a Format tool by which I am creating an file and copied my 2nd stage bootloader file , defreg it and got its physical address using FSCTL_GET_RETRIEVAL_POINTER and place its base physical address in MBR . In one of my test example this was like Start Sector(0x567D8) => EndSector(0x56FD7 ) . In MBR i copied this address at 0x11 . I used my Driver to update this MBR .

3. A New MBR loaded 0n 0x7c00 and this address is in data segment 0x7c10 .


Now I am trying to perform 2 things from here

1. Try to read the Extended by calling int 13h with service 42 . What should i include in my format tool so that i can read my 2nd stage code using 42h of 13h interrupt . Currently when i perform this service the windows original BootSector code is getting loaded on given stack

2. How do i load this sector using 13h 2 service . Below is the code i am using for this purpose which seems to be incorrect somewhere as on 13h interrupt the value of AH is 1 but the wrong data is copied on stack .

I am using BOCHS emulator and debuggers to debug this code ;

mov ah , 0x08 ;
int 13h
and cx , 03fh ;
mov byte ptr [SectorPerTrack] , cl ; (0x7a09 ==> 3fh)
movzx ax , dh
inc ax
mul cx
mov word ptr [ SectorPerCyl] , ax ; (0x7a00 => 3ec1h)
mov word ptr [SectorPerCyl +2] , dx ; (0x7a02=> 0 )
mov si , 0x7c10 ; ( actual address offset of bootloader file)
mov bx, 0x600

mov edx , dword ptr ds:[si+4]
mov eax , dword ptr ds:[si]
div eax , dword ptr ds:0x7a00
cmp eax, 1024 // File Size in KB
; jne error ;

push ax
mov ax , dx
div al, byte ptr ds:0x7a09
mov dh , al
mov cl, ah
inc cx
pop ax
mov ch , al
shl ah , 0x06
or cl , ah
mov ax , 0x001
mov ah, 0x02
mov dl , 80h
int 13h
Post Reply