Setting up second stage loader

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
GenHornet18
Posts: 22
Joined: Sat Mar 06, 2010 2:17 pm

Setting up second stage loader

Post by GenHornet18 »

Hey, this has likely been asked before (although I couldn't find a response) but I've started building my OS by assembling a two stage bootloader (learned from bits and pieces here and there). Now the first stage works fine (gets control, loads second stage, transfers control), but the second stage not so much. I've created a message processor to output messages corresponding to the progress of the loader, but they don't seem to appear (it's just a black screen the whole time). The code just executes and control eventually gets transferred to the kernel. Now I'm new at OSdev and I'm unsure exactly how to set up the second stage of the loader when control gets transferred there so I was wondering if anyone could offer me insight into how to set things up (memory addressing, a stack?) The second stage loader is incomplete as I'm just trying to get it set up accordingly...

boot sector/first stage

Code: Select all

[ORG 0]
[BITS 16]

jmp 07C0h:StartBoot


StartBoot:
   mov AX, CS
   mov DS, AX
   mov ES, AX

.reset:                      
   mov AX, 00h           
   mov DL, 00h         
   int 13h             
   jc .reset           

.read:
   mov AX, 7E00h     
   mov ES, AX        
   mov BX, 00h          

   mov AH, 02h           
   mov AL, 04h          
   mov CH, 00h         
   mov CL, 02h          
   mov DH, 00h           
   mov DL, 00h          
   int 13h             
   jc .read             
jmp 7E00h:0000h      ;To second stage bootloader


times 510-($-$$) db 0
dw 0AA55h
second stage loader

Code: Select all

[ORG 0]
[BITS 16]

Setup:
   mov AX, 7E00h   ;set new location, and set screen mode
   mov DS, AX
   mov ES, AX
   mov DL, 00h

   mov AH, 00h
   mov AL, 03h
   int 10h

   mov SI, [TITLE]
   call PrintS
jmp Main

Main:
.reset:             ;load kernel to physical address 10000h 
   mov AX, 00h           
   mov DL, 00h         
   int 13h             
   jc .reset           
.read:
   mov AX, 1000h    
   mov ES, AX        
   mov BX, 00h          

   mov AH, 02h       ;start locations for reading    
   mov AL, 40h          
   mov CH, 00h         
   mov CL, 06h          
   mov DH, 00h           
   mov DL, 00h          
   int 13h             
   jc .read 

   mov SI, [KLOAD]
   call PrintS
.pMode:
   cli
   
   mov AX, 2401h     ;enable the A20 line
   int 15h
   jc Error

       
jmp Done

PrintS:
   mov AH, 0Eh
.loop:
   mov AL, [SI]
   cmp AL, 00h
   je .done
   int 10h
   inc SI
   jmp .loop
.done:
   ret

Error:
   cmp AH, 86h
   je .nSupport
   
.unknwon:
   mov SI, [UNERROR]
   call PrintS
   hlt
.nSupport:
   mov SI, [NOSUPPORT]
   call PrintS
   hlt

;****************
; Strings
;****************
TITLE:
   db "-> BootSector found, second stage bootloader started", 0Ah, 0Dh, 00h
KLOAD:
   db "-> Kernel succefully loaded, setting up protected mode", 0Ah, 0Dh, 00h 
NOSUPPORT:
   db "ERROR!! - A20 line function not supported, booting halted", 0Ah, 0Dh, 00h
UNERROR:
   db "ERROR!! - An unknown error has occured, booting halted", 0Ah, 0Dh, 00h

Done:
   jmp 1000h:0000h

times 2048-($-$$) db 0
Thanks in advance for any help you can give
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Setting up second stage loader

Post by Brendan »

Hi,

An instruction like "mov SI, [TITLE]" moves the value at the address "TITLE" into the SI register. You want to do "mov SI, TITLE" which moves the address itself into SI.


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.
GenHornet18
Posts: 22
Joined: Sat Mar 06, 2010 2:17 pm

Re: Setting up second stage loader

Post by GenHornet18 »

Thank you Sir,

Unbelievable how I missed that mistake, (what i actually should have put there and after that was lea SI, [TITLE]), you just saved me countless hours of frustration. I need to take a break, and actually examine what I type.


thanks,
Hornet
User avatar
SOLeonOS
Posts: 4
Joined: Sat Mar 06, 2010 3:47 am
Location: Enschede, NL

Re: Setting up second stage loader

Post by SOLeonOS »

Hey,

furthermore, in your first stage you load the kernel to segment 0x7E00.
If my assumption is right that you want the kernel being loaded directly after the bootsector you need to put it into segment 0x07E0.

:arrow: good luck!
currently working on: Keyboard driver/interrupt, creating a filesystem, floppy disk driver

done: Video driver, timer interrupt, debugger interrupt , debugger memory (sending memory to the screen)
GenHornet18
Posts: 22
Joined: Sat Mar 06, 2010 2:17 pm

Re: Setting up second stage loader

Post by GenHornet18 »

No actually in the first stage loader I load the second stage loader which then goes to load the kernel, enter protected mode and jump to the kernel. It would do this anyways but as I said it is incomplete. Just a simple question though, when I jump to the second stage loader do I have to update the registers (so the memory location will be set accordingly)?
GenHornet18
Posts: 22
Joined: Sat Mar 06, 2010 2:17 pm

Re: Setting up second stage loader

Post by GenHornet18 »

Well on the upside my original error is somewhat resolved. I can get text to be outputted correctly if I move my GDT table and PrintS function around. I'm not exactly sure why but does the GDT need to be somewhere specifically in my coding? The code listed below doesn't work and I'm not exactly sure why, the error bochs spams we with is segment limit violation, which seems to occur somewhere at the start. Any insight you can offer as to how/where this is badly structured/poorly coded would be greatly appreciated.


updated second stage loader (first stage loader still remains the same, and functional)

Code: Select all

[ORG 0]
[BITS 16]

Setup:
   mov AX, 7E00h
   mov DS, AX
   mov ES, AX
   mov DL, 00h

   mov AH, 00h
   mov AL, 03h
   int 10h

   lea SI, [TITLE]
   call PrintS
jmp Main

Main:
.stack:             ;setup stack
   cli
   xor AX, AX
   mov DS, AX
   mov ES, AX
   mov AX, 9000h
   mov SS, AX
   mov SP, 0FFFFh
   sti

.reset:             ;load kernel to physical address 10000h 
   mov AX, 00h           
   mov DL, 00h         
   int 13h             
   jc .reset           
.read:
   mov AX, 1000h    
   mov ES, AX        
   mov BX, 00h          

   mov AH, 02h       ;start locations for reading    
   mov AL, 40h          
   mov CH, 00h         
   mov CL, 06h          
   mov DH, 00h           
   mov DL, 00h          
   int 13h             
   jc .read 

   lea SI, [KLOAD]
   call PrintS
.pMode:
   cli
   
   mov AX, 2401h     ;enable the A20 line
   int 15h
   jc Error

   pusha
   lgdt [GDTTable]   ;load a GDT
   popa

   mov EAX, CR0
   or EAX, 01h
   mov CR0, EAX
   hlt
   jmp 08h:clear_pipe

[BITS 32]
clear_pipe:
   mov AX, 10h         
   mov DS, AX              
   mov SS, AX              
   mov ESP, 90000h         
jmp Done


PrintS:
   mov AH, 0Eh
   mov BH, 00h
.loop:
   mov AL, [SI]
   cmp AL, 00h
   je .done
   int 10h
   inc SI
   jmp .loop
.done:
   ret

Error:
   cmp AH, 86h
   je .nSupport
   
.unknwon:
   lea SI, [UNERROR]
   call PrintS
   hlt
.nSupport:
   lea SI, [NOSUPPORT]
   call PrintS
   hlt

GDT:
null:      
   dd 00h
   dd 00h

code:               
   dw 0FFFFh
   dw 00h
   db 00h
   db 10011010b
   db 11001111b
   db 00h

data:               
   dw 0FFFFh
   dw 00h
   db 00h
   db 10010010b
   db 11001111b
   db 00h
GDTEnd:                

GDTTable:                      
   dw GDTEnd - GDT - 1    
   dd GDT

;****************
; Strings
;****************
TITLE:
   db "-> BootSector found, second stage bootloader started", 0Ah, 0Dh, 00h
KLOAD:
   db "-> Kernel succefully loaded, setting up protected mode", 0Ah, 0Dh, 00h 
NOSUPPORT:
   db "ERROR!! - A20 line function not supported, booting halted", 0Ah, 0Dh, 00h
UNERROR:
   db "ERROR!! - An unknown error has occured, booting halted", 0Ah, 0Dh, 00h

Done:
   jmp 08h:1000h


times 2048-($-$$) db 0
madeofstaples
Member
Member
Posts: 204
Joined: Thu Apr 12, 2007 8:15 am
Location: Michigan

Re: Setting up second stage loader

Post by madeofstaples »

The second stage is using an origin of 0 and the first stage jumps to this code while setting the CS to 0x7E00. Consequently, the calculated address of the GDT related labels will be 0x7E000 too small. The fact that your code seems to work when changing around the location of the GDT is probably only a lucky coincidence, because really, your code causes part of the interrupt vector table (probably, I haven't actually assembled the code to see what the address ends up being to be sure) to be used as if it were the GDT.

Try changing

Code: Select all

GDTTable:                      
   dw GDTEnd - GDT - 1    
   dd GDT
to

Code: Select all

GDTTable:                      
   dw GDTEnd - GDT - 1    
   dd GDT + 0x7E000
Although not required, the GDT should be aligned to an 8-byte boundary for best performance. You probably want to place "align 8" before the "GDT" label.

Edit: whoops, forgot the implicit multiplier. Originally I just added 0x7E00 but I've fixed the above post to add 0x7E000.
Some people are offended by the verifiable truth; such people tend to remain blissfully unencumbered by fact.
If you are one of these people, my posts may cause considerable discomfort. Read at your own risk.
GenHornet18
Posts: 22
Joined: Sat Mar 06, 2010 2:17 pm

Re: Setting up second stage loader

Post by GenHornet18 »

Thanks for the advice, the problem actually resided in the way I was reading in the kernel. The GDT has also been corrected, I think there was a problem there. Loads the kernel now though, so I just have to finish writing it.

Thanks for the help,
-Hornet
Post Reply