I'm new to OS development. So I figured I would start out by writing a boot loader from scratch. I am attempting to write a Stage 2 boot loader. All Stage 1 does is read Stage 2 from disk and jump to it. I am using interrupts for output.
Stage 1 works fine. It outputs the string "Bootloader Initialised...", loads the second sector of the floppy disk and jumps to it.
Stage 2 does not work the way I expect it to work. For some reason I am unable to output a string the same way I output a string in stage 1. Any ideas why? Below is my code.
Here is my code for Stage 1:
--------------------------------------------------------------------------------------------------------------------------------
; bootloader
[BITS 16]
[ORG 0x7C00]
MOV si, BootLoaderWelcomeString
CALL PrintBootLoaderWelcome
ResetFloppyDrive:
MOV dl, 0 ;Drive = 0 (A drive)
MOV ah, 0
INT 0x13
JC ResetFloppyDrive
ReadFloppyDisk:
MOV ax, 0x1000
MOV es, ax ;es - extra segment. Pointer to extra data. es = 0x1000
MOV bx, 0 ;bx - Base register. Used as a pointer to data. bx = 0
MOV al, 1 ;Load just 1 disk sector
MOV ch, 0 ;Cylander = 0
MOV cl, 2 ;Sector = 2
MOV dh, 0 ;Head = 0
MOV dl, 0 ;Drive = 0 (A drive)
MOV ah, 2
INT 0x13
JC ReadFloppyDisk
JMP 0x1000:0000
PrintBootLoaderWelcome:
MOV al, [si]
OR al, al
JZ ReturnStage1
MOV ah, 0x0E
INT 0x10
INC si
JMP PrintBootLoaderWelcome
GetString:
MOV ah, 0
INT 0x16
MOV ah, 0x0E
INT 0x10
JMP GetString
ReturnStage1:
RET
BootLoaderWelcomeString DB "Bootloader Initialised...", 0x0D, 0x0A, 0
TIMES 510 - ($ - $$) DB 0 ;Fill the rest of sector with 0
DW 0xAA55 ;Add boot signature at the end of bootloader
-------------------------------------------------------------------------------------------------------------------------------------------------
Here is my code for stage 2:
-------------------------------------------------------------------------------------------------------------------------------------------------
MOV si, Stage2WelcomeString
CALL PrintStage2Welcome
JMP $
PrintStage2Welcome:
MOV al, [si]
OR al, al
JZ returnStage2
MOV ah, 0x0E
INT 0x10
INC si
JMP PrintStage2Welcome
returnStage2:
RET
Stage2WelcomeString db "Initialising Stage 2...", 0x0D, 0x0A, 0
Stage 2 bootloader Question
Re: Stage 2 bootloader Question
you need to set up a stack first off.
call and ret use the stack iirc.
also, edx needs to be zero'd (as it's not on boot). I'm not 100% that it will be an issue, but if dh is != 0, you're interrupt calls may produce unpredictable results.
call and ret use the stack iirc.
also, edx needs to be zero'd (as it's not on boot). I'm not 100% that it will be an issue, but if dh is != 0, you're interrupt calls may produce unpredictable results.
Website: https://joscor.com
Re: Stage 2 bootloader Question
There are no problems with the interrupts. I tried the following code...
MOV al, 65
MOV ah, 0x0E
INT 0x10
...and it does print 'A'
If I just do...
MOV si, Stage2WelcomeString
MOV al, [si]
MOV ah, 0x0E
INT 0x10
Stage2WelcomeString db "Initialising Stage 2...",13,10, 0
...all I get is an empty space on the screen ' '
I guess I don't have a complete understanding on how the above code works. Does the above code require a stack? If so, how does the above code interact with the stack? I was able to produce output on a screen without creating a stack in Stage 1. What is the difference now that I am in Stage 2?
Thanks!
MOV al, 65
MOV ah, 0x0E
INT 0x10
...and it does print 'A'
If I just do...
MOV si, Stage2WelcomeString
MOV al, [si]
MOV ah, 0x0E
INT 0x10
Stage2WelcomeString db "Initialising Stage 2...",13,10, 0
...all I get is an empty space on the screen ' '
I guess I don't have a complete understanding on how the above code works. Does the above code require a stack? If so, how does the above code interact with the stack? I was able to produce output on a screen without creating a stack in Stage 1. What is the difference now that I am in Stage 2?
Thanks!
Re: Stage 2 bootloader Question
you don't set BX during the INT 0x10 (which selects the page, and if you're on page 0, which you probably are, and BH != 0, then you will write to another video page).
also, if you're getting a blank space, most likely BL is == 0 (the foreground == BLACK (0)).
try this:
check out: http://www.ctyme.com/intr/rb-0106.htm
also, if you're getting a blank space, most likely BL is == 0 (the foreground == BLACK (0)).
try this:
Code: Select all
MOV si, Stage2WelcomeString
MOV al, byte [si]
MOV ah, 0x0E
MOV bl, 0x0A
MOV bh, 0x00
INT 0x10
Stage2WelcomeString db "Initialising Stage 2...",13,10, 0
Website: https://joscor.com
Re: Stage 2 bootloader Question
Hi,
AFAIK "DS segment base" equals "whatever trash the BIOS left in DS", which may not be 0x07C0 in the first stage (you were lucky) and won't suddenly changed to 0x1000 for the second stage...
Cheers,
Brendan
The "MOV al,[si]" instruction means "copy the value at the address "DS segment base + SI" into AL". The value in SI should be right, so, what is "DS segment base" equal to?Stavros wrote:If I just do...
MOV si, Stage2WelcomeString
MOV al, [si]
MOV ah, 0x0E
INT 0x10
AFAIK "DS segment base" equals "whatever trash the BIOS left in DS", which may not be 0x07C0 in the first stage (you were lucky) and won't suddenly changed to 0x1000 for the second stage...
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: Stage 2 bootloader Question
SS/DS/ES/FS/GS selector = 0, base = 0, limit = 0xFFFF
according to Intel Volume 3A table 8-1 in section 8.1 Initialization Overview.
[edit]also, wouldn't SI be a non-relative offset, so DS == 0 would be correct? 0x0000:phys_string_location.
or better, just put a breakpoint and check out your segment values and GP regs yourself before that INT.
according to Intel Volume 3A table 8-1 in section 8.1 Initialization Overview.
[edit]also, wouldn't SI be a non-relative offset, so DS == 0 would be correct? 0x0000:phys_string_location.
or better, just put a breakpoint and check out your segment values and GP regs yourself before that INT.
Website: https://joscor.com
Re: Stage 2 bootloader Question
Hi,
The only things you can really assume are that the BIOS left the device number for the boot device in DL, that interrupts are enabled, that you're in real mode (or unreal mode for some dodgy BIOSs apparently), and that the IDTR points to 0x00000000. There's no guarantees for the contents of other general registers, all segment registers (including CS), FPU/MMX/SSE state, the GDTR and LDTR, the A20 gate, the stack location or anything else; so if your code relies on any of these things then it needs to set them to a known value/state first.
Cheers,
Brendan
That's *before* the BIOS has done heaps of stuff (and then started an OS). After the BIOS has done heaps of stuff you can't assume the CPU is in the same state (e.g. same general register contents, same segment register contents, etc) as it was in on reset/power on.01000101 wrote:SS/DS/ES/FS/GS selector = 0, base = 0, limit = 0xFFFF
according to Intel Volume 3A table 8-1 in section 8.1 Initialization Overview.
The only things you can really assume are that the BIOS left the device number for the boot device in DL, that interrupts are enabled, that you're in real mode (or unreal mode for some dodgy BIOSs apparently), and that the IDTR points to 0x00000000. There's no guarantees for the contents of other general registers, all segment registers (including CS), FPU/MMX/SSE state, the GDTR and LDTR, the A20 gate, the stack location or anything else; so if your code relies on any of these things then it needs to set them to a known value/state first.
Doh - my mistake. With "org 0x7C00" you'd want DS to be zero in the first stage. For the second stage (loaded at 0x00010000) you'd need DS to be 0x1000, partly because there is no "org" and the assembler assumes "org 0", and partly because with DS still set to zero you can only use it to access RAM from 0x00000000 to 0x0000FFFF due to the 64 KiB segment limit (which means it wouldn't be able to access anything in the second stage).01000101 wrote:[edit]also, wouldn't SI be a non-relative offset, so DS == 0 would be correct? 0x0000:phys_string_location.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: Stage 2 bootloader Question
I got it to work now. In case anyone was wondering this is what I did...
The problem was not in the code itself, the problem was the way I was trying to implement the two stage boot loader. Basically what I was doing was using nasm to create a single binary file from a single file of assembly code. Nasm did not allow me to use ORG more than once in the same assembly file. Since I was unable to use ORG for stage 2, Nasm basically just loaded my code into random memory (I'm assuming). This is what messed up the code in Stage 2. What I did to correct this was to create two separate binary files from two separate assembly source code files (this time loaded in the correct addresses using ORG for each stage), then I used cat to join the binary files. Now the code works.
Thanks for all the help.
The problem was not in the code itself, the problem was the way I was trying to implement the two stage boot loader. Basically what I was doing was using nasm to create a single binary file from a single file of assembly code. Nasm did not allow me to use ORG more than once in the same assembly file. Since I was unable to use ORG for stage 2, Nasm basically just loaded my code into random memory (I'm assuming). This is what messed up the code in Stage 2. What I did to correct this was to create two separate binary files from two separate assembly source code files (this time loaded in the correct addresses using ORG for each stage), then I used cat to join the binary files. Now the code works.
Thanks for all the help.