Strange 1st stage boot loader issue

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
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Strange 1st stage boot loader issue

Post by johnsa »

Hey all,

I've re-started working on a hobby os project recently, and just brushed the dust off my old 1 and 2 stage boot loader code.
In the 1st stage loader I'm just using int 13h/func=02 to load the sectors (8 of them starting at sector 2) for the 2nd stage loader.
The BIOS call returns with no carry or errors, but the memory that it's written to es:bx is all 0's... any ideas?
It works under Bochs/VPC but this is booting it for real from my USB stick. The BIOS picks up the USB for boot perfectly and gets right thru all the 1st stage loader code.. (sees it as drive 80h).

I'm wondering if because it's seing it as a HDD I need to use 13h extensions? or perhaps i didn't reset the disk params table correctly.. is this necessary for HDD? (thought it was only for floppy).

Thanks!
John
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: Strange 1st stage boot loader issue

Post by johnsa »

Hey all,

Just to update.. the idea with this boot-loader (stage1) is for it to be able to work from a floppy/hdd/cdrom or usb in a single unified way. From what I understand the BIOS emulates a HD when booting from usb or cdrom? the 2nd stage loader will always be under 16 sectors (8kb?) I'm assuming at boot time all devices would present 512 byte sectors (usb/hd/cd) via bios 13h 02h? - in which case i can avoid lba2chs or anything else in the stage1 loader.

I'm not worried about supporting partitions/mbr really for what i'm doing and i don't want to use a ready-made loader like grub etc seing as it's for fun and one might as well write it all to learn.
Here is the full code with regards to the previous post, perhaps someone can see a major flaw .. I've tried to combine what i've read and seen from various loaders to support FD/HD/USB ..
Any thoughts as to why this thing loads sectors for the 2nd stage with out any errors but the data is all just 0.

Code: Select all


.386p

code segment para public use16 'code'
	assume cs:code, ds:code

	;--------------------------------------------------------------------------------
	; Ensure the assembler generates 0 relative offsets for our later CS correction.
	; -> Some BIOSes will load the boot sector code to 0000:7c00 while others
	; -> will load it to 07c0:0000. We move it to this in either event for
	; -> simplicity and to ensure we can re-locate the code to a different segment
	; -> without affecting the offsets.
	;--------------------------------------------------------------------------------
	org 0h

start:
	jmp short begin									; This 2 byte jump will always be the first part of our MBR.
    ;-----------------------------------------------------------------------------------
    ; MDB (Master Disk Block) = 32bytes.
    ;-----------------------------------------------------------------------------------
    m_filesystem db "VXFS"                   		; File System Type in Use on Logical Disk.
    m_volume     db "UNTITLED"				 		; Drive Volume Name.
    m_heads      dw 2                        		; Heads per Disk (Physical).
    m_cylinders  dw 80                       		; Cylinders Per Head (Physical).
    m_sectors    dd 18                       		; Sectors Per Track (Physical).
    m_sectorsize dw 512                     		; Size in bytes of a sector (Physical).
    m_driveNo    db 00h                     		; 0 = fdd0 / 80h = hdd0.
    m_mode       dw 0                       		; 1 = CHS / 0 = LBA.
	m_first_sec  dd 0		 			    		; First Sector Of File System.
    padding		 db 0
    
;###############################################################################################################
; BOOT LOADER CODE BEGINS HERE.
;###############################################################################################################
begin:	
	db 0eah											; Hard-coded long jump to seg:ofs as specified.
	dw offset cs_correction, 07c0h

cs_correction:
	cli												; Disable any interrupts.
	xor ax,ax
	mov es,ax
	dec ax
	mov sp,ax
	mov ax,9000h
	mov ss,ax										; Setup stack at 9000:ffff (common place).

	mov ax,07c0h
	mov ds,ax										; Ensure DS = CS (07c0:0000).
	mov m_driveNo,dl								; Store the Boot Drive Number (BIOS will start us with this in DL).

    xor si,si                               		; DS:SI = begin of original bootloader.
    mov di,600h                             		; ES:DI = begin of new bootloader.
    mov cx,100h                             		; Copy 256 words (512 bytes).
    rep movsw                               		; Copy bootloader.

    db 0eah                                 		; Hardcode force far jmp.
    dw offset bootloader_exc0,0060h         		; new code addr = (0060:bootloader_exc0).

;=============================================================================================================
; Bootloader will commence from here at new address.
; -> All offsets need to be adjusted manually from here on due 
; -> to self-modified execution address 600h.
; -> eg (offset Print_Msg-7c00h)+600h
; -> short IP relative jmps are fine.
; -> THIS IS NOW FIXED BY USING ORG 0h and seg:0000...!!!!
; -> Just out of interest 0600h happens to be the address DOS 1.x loaded to..
;=============================================================================================================
bootloader_exc0:
    mov ax,060h                             		; Reset Seg Registers.
    mov ds,ax                               		; CS and DS = 0060h.

	;--------------------------------------------------------------------------------
	; If we get this far, we can display the startup message and
	; start doing some useful setup.
	; -> Traditionally we'd want to check for a 386+ machine, but these days?
	;--------------------------------------------------------------------------------
	mov ax,03h										; Reset 80x25 text mode.
	int 10h
	
	mov si,offset msg0								; Display Start Message.
	call printstr

	mov si,offset msg1								; Display Boot Drive Number.
	call printstr
	mov al,m_driveNo
	call printbyte

	; The Interrupt Vector Table (IVT) occupies the first 1024 bytes of low memory and
	; contains 256 4-byte entries.  Each entry is an address to an Interrupt routine.
	; The INT 1E vector (Diskette Configuration pointer) is at 0000:0078 and contains
	; the address to the Diskette Parameter Table (DPT).  (78h/4 = 1Eh)
    ;-----------------------------------------------------------------------------------
    ; -> Reset FDC Param Tables (apparently some BIOS have too low max sector
    ;    count (7).. we need 36 for max 2.88 disks, this messes up multi-sector
    ;    reads greater than the BIOS value. Too high is safe, too low not...
    ;-----------------------------------------------------------------------------------
    push ds
    mov bx,078h                    					; ES:BX = FDC BIOS Param Table Ptr.        
    lds si,es:[bx]                 					; DS:SI points to Param Table.
    mov byte ptr ds:[si+4],36      					; Kludge Sector Per Track Count (36 = 2.88 disk). We try 63?
    mov byte ptr ds:[si+9],0fh     					; Reset Head Bounce Time.
    pop ds                         					; Updates INT 1E table.

    mov dl,m_driveNo
    xor ax,ax
    int 13h                         				; Reset Controller for booted drive.
		
	;--------------------------------------------------------------------------------
	; Did we get booted from a floppy, harddisk, usb or cdrom?
	; -> USB will emulate a HDD boot (80h).
	;--------------------------------------------------------------------------------
   	cmp m_driveNo,80h
    jae skip_not_floppy

;====================================================================================
; FLOPPY DISK BOOT SOURCE.
;====================================================================================
    mov m_heads,2                           		; All floppies have 2 heads(?)
    mov m_sectorsize,512                    		; All floppies have 512 byte sectors.
    mov m_cylinders,80                      		; All floppies have 80 cylinders.
    mov m_mode,1                            		; All floppies have CHS addressing.

    ;-----------------------------------------------------------------------------------
    ; Probe Disk Drive Sectors per Track.
    ; -> Try 36, then 18 and so on to see what works as BIOS has no definite way
    ; -> of knowing using INT13H, SERVICE 08h... more arcane rubbish.
    ;-----------------------------------------------------------------------------------
    mov ax,07c0h
    mov es,ax
    mov si,offset disksizes
probe_loop:
    xor eax,eax
    xor cx,cx
    mov al,ds:[si]
    inc si
    cbw                                     		; Extend AL to AX.
    mov m_sectors,eax
    cmp si,(offset disksizes)+4
    jae short got_sect_size
    mov cl,al
    xor dx,dx
    mov dl,m_driveNo
    xor bx,bx                              			; Use future load address to overwrite (no danger).
    mov ax,0201h
    int 13h
    jc short probe_loop                     		; If failed try next sector size down.
got_sect_size:
	
	mov di,4										; Retry load a few times.
readatt0:	
    xor ax,ax
    mov dl,m_driveNo
    int 13h											; Ensure FDC Boot Source is Reset Again.

    mov ax,07c0h									; ES:[BX] = 07C0:0000
    mov es,ax								
    xor bx,bx
    mov ax,0208h									; Load 8 sectors.
    mov dl,m_driveNo								; Drive to Load From (Boot Drive).
    mov cx,02h										; Starting Sector
    xor dh,dh
    int 13h
	jnc short doneloadingok
	dec di
	jnz short readatt0

	mov si,offset errmsg1							; Fail if we can't load stage2 loader.
	call bootfail

doneloadingok:
   	mov dx,03f2h
	xor al,al
	out dx,al										; Ensure we turn off the floppy mode to enter 2nd stage loader in known state.
	jmp doneloading
	    
;====================================================================================
; HARD-DISK BOOT SOURCE.
;====================================================================================
skip_not_floppy:

	mov ah,08h
	mov dl,m_driveNo
	int 13h
	xor ax,ax
	mov al,ch
	mov ah,cl
	and ah,11000000b
	shr ah,6
	mov m_cylinders,ax
	xor eax,eax
	mov al,cl
	and al,00111111b
	mov m_sectors,eax
	
	mov ax,07c0h
	mov es,ax
	mov al,byte ptr es:[0]
	call printbyte
	
	mov di,4
attempthdload:    
    xor ax,ax
	mov es,ax
    mov dl,m_driveNo
    int 13h
    mov bx,07c00h
    mov ax,0208h									; Load 8 sectors.
    mov dl,m_driveNo								; Drive to Load From (Boot Drive).
    mov cx,02h										; Starting Sector
    xor dh,dh
    int 13h
    jnc short doneloading
	dec di
	jnz short attempthdload
	
	mov si,offset errmsg1							; Failed to load 2nd stage from HDD source.
	call bootfail    	

;====================================================================================
; Switch to 2nd Stage Loader Now.
;====================================================================================
doneloading:

	mov al,byte ptr es:[7c00h]
	call printbyte

	jmp short $
	
	db 0eah
	dw 0000h, 07c0h									; Hard coded Far Jump to 07c0:0000h.

;######################################################################################################
; !!!All first stage boot loader procedures and data go here!!!
;######################################################################################################

;Value	Color  	Value	Color
;00h	Black 	08h		Dark gray
;01h	Blue 	09h		Bright blue
;02h	Green 	0Ah		Bright green
;03h	Cyan 	0Bh		Bright cyan
;04h	Red 	0Ch		Pink
;05h	Magenta 0Dh		Bright magenta
;06h	Brown 	0Eh		Yellow
;07h	Gray 	0Fh		White

;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; Print an ASCII string.
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
printstr:
	mov ah,0Eh
	mov bh,00h
	mov bl,07h
	lodsb
	or al,al
	jz short strDone
	int 10h
	jmp short printstr
strDone:
	ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; Print a byte value in hex.
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
printbyte:
	pusha
	xor ah,ah
	mov cl,al
	mov bh,00h
	mov bl,07h
	and al,11110000b
	and cl,00001111b
	shr al,4
	mov si,offset hexLUT
	add si,ax
	mov al,ds:[si]
	mov ah,0Eh
	int 10h
	xor ax,ax
	mov al,cl
	mov si,offset hexLUT
	add si,ax
	mov al,ds:[si]
	mov ah,0Eh
	int 10h
	popa
	ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; Boot Failure and Reboot.
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bootfail:
	call printstr											; Display whichever error msg was passed in.
	;mov si,offset errmsg0
	;call printstr											; Display the "any key to reboot" message.
	xor ax,ax
	int 16h													; Wait for key press.
	int 19h													; Force POST reboot by calling int 19h.
	; ALTERNATIVE REBOOT.
	; store magic value at 0040:0072h
	;  - 0000h - cold boot.
	;  - 1234h - warm boot.
	;mov ax,40h
	;mov es,ax
	;mov word ptr es:[0072h],0000h
	;db 0eah												; Jump to ffff:0000 (Alternative Reboot Scheme). 
	;dw 0000h
	;dw 0ffffh

;=====================================================================================================
; BootLoader Data Area.
;=====================================================================================================		
	;errmsg0      db '<Press any key to reboot>',13,10,0
	errmsg1      db 'error',13,10,0
	msg0		 db 'VXOS v1.0',13,10,0
	msg1         db 'drive:',0
	disksizes    db 36, 18, 15, 9              				; SPT options for FDD. (Sectors per Track).
	hexLUT       db '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'

	db 510-($-start) DUP (0)								; Add padding to ensure boot loader code is exactly 512bytes long.
	db 055h,0aah											; Boot loader signature which must be present at end of 512byte 1st sector.
															; BIOS will check this magic number to ensure that it is a bootable sector.
code ends													; End of Code Segment.
end start													; End of Block Marker.
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Re: Strange 1st stage boot loader issue

Post by egos »

johnsa wrote:From what I understand the BIOS emulates a HD when booting from usb or cdrom?
USB flash has the same structure as a hard disk therefore it does not need emulation in this aspect. Booting from CD-ROM can occur without emulation (with 2K sector size). In both cases boot loader must use EDD service.
If you have seen bad English in my words, tell me what's wrong, please.
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: Strange 1st stage boot loader issue

Post by johnsa »

Ok, so basically in the boot code I check to see if the drive no. is >= 80h... if not i assume floppy, do the manual spt probe and use int 15h 02 to load sectors.

If it's a HDD (this would indicate a real HDD, or USB in HDD emulation or possibly a CDROM? I've seen CDROM boot with driveno=0 as well?? large floppy emulation??)
In this case I'd use int 13h ah=42h to perform the sector reads with the relevant spt/heads info etc obtained from the 13h extension info?

Thanks!
quok
Member
Member
Posts: 490
Joined: Wed Oct 18, 2006 10:43 pm
Location: Kansas City, KS, USA

Re: Strange 1st stage boot loader issue

Post by quok »

johnsa wrote: Just to update.. the idea with this boot-loader (stage1) is for it to be able to work from a floppy/hdd/cdrom or usb in a single unified way. From what I understand the BIOS emulates a HD when booting from usb or cdrom? the 2nd stage loader will always be under 16 sectors (8kb?) I'm assuming at boot time all devices would present 512 byte sectors (usb/hd/cd) via bios 13h 02h? - in which case i can avoid lba2chs or anything else in the stage1 loader.
Your understanding is slightly off. A bootable CDROM follows the El Torito standard. It allows for floppy emulation, hard disk emulation, or no emulation at all. For both floppy and hard disk emulation, the BIOS will translate sector sizes and fake drive geometry for your use. With no emulation, the BIOS will read 2048 byte sectors off the CD.

Booting from USB also has a bunch of standards to follow. There is USB-FDD, USB-HDD, and USB-ZIP. USB-FDD is a lot like a regular floppy. USB-HDD requires a partition table on the USB device. The device may have multiple partitions, and one of the partitions must be marked active. USB-ZIP requires a special geometry, as well as a partition table. However, it uses only one partition, and it must be the 4th entry in the partition table. Generally, these standards are incompatible, but it is possible (and quite tricky) to create a single bootloader that simultaneously complies with these three standards. I believe that USB-HDD is the most widely supported, however.
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: Strange 1st stage boot loader issue

Post by johnsa »

Ok, I'm with you.

So in terms of CD booting would it be safe to assume that most systems will implement a faked FDD/HDD boot thus resulting in the boot drive number being either 00h or 80h? If no emulation then what would the drive number be? Following then it would be imperative to obtain the bytes per sector info from either int 13/08 or 13/48h(assuming extensions are available) to load the stage2 loader from the CD and correctly handle 2kb sectors.

I think I could ignore USB-ZIP for now and just work from FDD/HDD again. I know that on my machine it emulates it as HDD (80h drive number on boot). Oddly though I don't have any partition table etc and the boot still works fine. Are you sure the Partition table is necessary? or is that more to fall in line with other standards like FAT etc?

Ignoring USB-ZIP should make it fairly trivial to get this working as a unified stage1 as the two emulations options will report drive number 0 or 80h and thus the two cases are handled seperately for
A) real floppy/usb-fdd/cd-rom as FDD
B) real hdd/usb-hdd/cd-rom as HDD

Following on I implemented the int13h extension read (42h) to see if that solved the problem i'm having off USB.. for all intense purposes the boot loader works and the usb stick boots, gets through 90% of the code and then only when loading the sectors up for the stage2 does it do this funny of not reporting an error bust just loading 0's... (it works in bochs/vmware).. but then again we all know how quirky "real" environments can be.
Needless to say it did not solve the problem, I even used the get disk info function to report back the geometry and obtained the following for:
Cyl: 1965
Heads: 1
SPT: 63
Sector-Size: 512
which to my mind = a 64Mb drive, and in truth the usb-stick is 1Gig.
I'm going to quickly burn this as iso onto a cd and see what happens when it boots that way.
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: Strange 1st stage boot loader issue

Post by johnsa »

Ok, I've tested it on FDD and CD-ROM under Bochs/VirtualBox/VMWare and on my real machine and all work. It's now only the USB thing that still seems strange.

I've include an attachment here with 3 things, the img file to write to a memory stick, an iso to burn to CD and a small utility I wrote a while ago to write/read sectors to devices called diskimage.

Usage:
To write 4,608 bytes to a USB drive (F:) use the following:
diskimage a.img 0 1200 \\.\F: 0
source and destination specify an offset and length.
If it's a physical device (a drive eg) then the offset is in sectors and length too.. if it's a file then it's in bytes.. both sets of values in hex.

If someone could test this for me using a USB stick they know boots that would be fantastic!
The correct output should be : EBFA ... which i get in all configs except USB where it's EB00 ... first byte is original value, 2nd is the first byte after the load.. FA is correct .. 00 not.

John
PS Feel free to use the little diskimage tool.
Attachments
OStest.rar
(6.95 KiB) Downloaded 75 times
Post Reply