Darwin weird or my fault?

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.
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Darwin weird or my fault?

Post by Firestryke31 »

Hello, everyone. It's me again.

I was just wondering if there was anything weird about the way Darwin boots partitions. I'm booting with Darwin because it'll boot both Vista and Leopard with minimal fuss. It also brings up an entry with my OS's test partition, but whenever I boot from it my bootloader locks up and dies. I know it at least partially works, because the exact same bootloader will run off of a USB flash stick (which includes a basic partition table with a default MBR) and I wasn't sure whether Darwin does something different that Vista's boot sector can handle but mine can't, or if Darwin's completely normal and I screwed up somewhere. Due to the fact that Darwin (and Leopard) technically shouldn't be on this computer, I'm tending towards Darwin being weird, but it wouldn't surprise me in any way if it was my fault...

Here's a dump of my latest boot sector code, since it's changed a bit since my other thread...

Code: Select all

;; Stage 1 bootloader for Firebird O.S
;;  FAT32 Partition version
;;  Version 2.2
org 0x7C00
bits 16

BS_jmpBoot:
	jmp start
	nop

;; FAT fields, labeled here for convenience
BS_OEMName:
	dd 16843009
	dd 16843009
BPB_BytsPerSec:
	dw 257
BPB_SecPerClus:
	db 1
BPB_ResvdSecCnt:
	dw 257
BPB_NumFATs:
	db 1
BPB_RootEntCnt:
	dw 257
BPB_TotSec16:
	dw 257
BPB_Media:
	db 1
BPB_FATSz16:
	dw 257
BPB_SecPerTrk:
	dw 257
BPB_NumHeads:
	dw 257
BPB_HiddSec:
	dd 16843009
BPB_TotSec32:
	dd 16843009
BPB_FATSz32:
	dd 16843009
BPB_ExtFlags:
	;; Bits 0-3 = Active FAT, 7 = !FAT mirroring
	dw 257
BPB_FSVer:
	dw 257
BPB_RootClus:
	dd 16843009
BPB_FSInfo:
	dw 257
BPB_BkBootSec:
	dw 257
BPB_Reserved:
	dd 16843009
	dd 16843009
	dd 16843009
BS_DrvNum:
	db 1
BS_Reseved1:
	db 1
BS_BootSig:
	db 1
BS_VolID:
	dd 16843009
BS_VolLab:
	dd 16843009
	dd 16843009
	dw 257
	db 1
BS_FilSysType:
	dd 16843009
	dd 16843009

start:
	;; save DS so we can get the value at ds:si later
	push ds
	pop fs
	;; Set CS, DS, ES, & SS to a known value
	;; I used eax because I want to have the upper word cleared later
	xor eax, eax
	mov ds, ax
	mov es, ax
	jmp 0:loadCS
loadCS:
	
	;; set up the stack ( a temporary 512-byte stack )
	mov ss, ax
	mov sp, 0x8000
	mov bp, sp
	
	;; LBA packet
	mov [LBAindex+4], eax
	mov al, 16
	mov [LBApacket], ax

	;; Save the boot drive
	;; BootDrive = dl
	push dx
	
	;; check if we're on a partition
	push si
	xor al, al
	call readDiskToBP
	;; Now to compare.
	;; If the sector we just loaded == this code,
	;; we're on a flat disk. Else, let's assume a partition
	mov si, 0x7C00
	mov di, bp
	mov cx, 512
	repe cmpsb
	pop si
	;; get the partition start from the MBR
	mov ecx, [fs:si+8]
	jne .partitioned
	;; if we're here, it's not actually partitioned,
	;; so clear the 'offset'
	xor ecx, ecx
.partitioned:
	
	;; calculate the first data sector
	;; FirstDataSector = BPB_NumFATs * BPB_FATSz32 + BPB_ResvdSecCnt + partitionStart
	mov al, [BPB_NumFATs]
	mul dword [BPB_FATSz32]
	movzx ebx, word [BPB_ResvdSecCnt]
	add eax, ebx
	add eax, ecx
	push eax
	
	;; now let's get the location of the first FAT
	;; FATsector = BPB_ResvdSecCnt + partitionStart
	movzx eax, word [BPB_ResvdSecCnt]
	add eax, ecx
	push eax
	
	;; BytsPerCluster = BPB_BytsPerSec * BPB_SecPerClus
	mov ax, [BPB_BytsPerSec]
	mul word [BPB_SecPerClus]
	push eax
	
	;; FATClusterMask = 0x0FFFFFFF
	mov eax, 0x0FFFFFFF
	push eax
	
	;; FATEoFMask = 2nd 'cluster' value & (bitwise) FATClusterMask
	;; load the FAT
	mov eax, [FATsector]
	call readDiskToBP
	;; Get the second cluster's value
	mov eax, [bp+4]
	and eax, [FATClusterMask]
	push eax
	
	;; CurrentCluster = BPB_RootClus
	mov eax, [BPB_RootClus]
	push eax
	
	;; Fortunately, clusters are relative to FirstDataSector
	
	;; Reserve the LBA packet,
	;; (even though we've already been using it)
	sub sp, byte 16
	
	mov di, bp
	;; Stack is now as follows:
BootDrive 			equ BP- 2
FirstDataSector		equ BP- 6
FATsector			equ BP-10
BytsPerCluster		equ BP-14
FATClusterMask		equ BP-18
FATEoFMask			equ BP-22
CurrentCluster		equ BP-26
LBAindex			equ BP-36
LBAseg				equ BP-38
LBAaddr				equ BP-40
LBAcount			equ BP-42
LBApacket			equ BP-44
LBApacketAddr		equ 0x8000-44
	
	;; Load the first root directory cluster
	call readCluster
	
	;; parse first cluster to see if it has what we want
nextDirCluster:
	;; Set bx to the end of the cluster
	mov bx, [BytsPerCluster]
	add bx, bp
	;; ax = 0x8000 - sizeof(FAT_DIR_entry)
	;; this simplifies the upcoming loop a bit
	lea ax, [bp-32]

findloop:
	;; move to next entry
	add ax, 32
	;; check if we're at the end of the cluster
	cmp ax, bx
	;; if so, handle it
	jz notFound
	;; I got 99 problems, bein' found is one.
	;; If you're havin' directory problems,
	;; I feel bad for you, son.
	
	;; (Too much?)
	
	;; else let's check the entry
	mov si, ax
	mov di, fileName
	mov cx, 11
	;; compare names
	repe cmpsb
	;; if not the same, try next entry
	jnz findloop
	
	;; file found!
	;; +9 and +15 because SI is already 11 bytes into the entry
	mov ax, [si+9]
	sal eax, 16
	mov ax, [si+15]
	;; eax = cluster of file
	mov [CurrentCluster], eax
	mov di, bp
loadFileLoop:
	;; if we're already at the EoF, this won't read anything
	call readCluster
	;; it will, however, set the carry flag to indicate that we're at the EoF
	;; so if( !cf )
	;;  keep loading clusters
	jnc loadFileLoop
	;; else
	;;  jump to the second stage
	jmp bp

notFound:
	;; try reading the next cluster
	call readCluster
	jnc nextDirCluster
	;; if this was the last one
	;; show an error
	mov si, noFile
	jmp putStr
	
;; A few useful routines
readDiskToBP:
	mov cx, sp
	mov sp, LBApacketAddr
	push cx
	mov bx, bp
	mov cl, 1
	call readDiskLBA
	pop sp
	ret

;;  readCluster :: ES:DI = dest
readCluster:
	;; Check if we're already at the EoF
	mov eax, [CurrentCluster]
	and eax, [FATClusterMask]
	cmp eax, [FATEoFMask]
	;; if so, bail
	jz eofLoad
	
	;; Get the first sector of the cluster
	;; Sector = (cluster - 2) * BPB_SecPerClus + FirstDataSector
	sub eax, 2
	movzx ebx, byte [BPB_SecPerClus]
	mul ebx
	add eax, [FirstDataSector]
	;; eax = first sector of cluster
	;; fetch the cluster and put it where the user wanted
	mov bx, di
	mov cl, [BPB_SecPerClus]
	call readDiskLBA

	;; increment the destination pointer
	add di, [BytsPerCluster]
	
	;; we've trashed eax, so let's get it back
	;; so we can store the next cluster
	mov eax, [CurrentCluster]
	
	;; now, let's get the number of
	;; cluster pointers in a sector
	movzx ebx, word [BPB_BytsPerSec]
	shr bx, 2
	;; now that we have that, let's figure
	;; out the offset, in sectors, of the
	;; current cluster pointer
	xor edx, edx
	div eax, ebx
	;; now that we have those, let's save the clusterpointer index
	push dx
	;; add in the location of the first FAT sector
	;; to get the location on disk
	add eax, [FATsector]
	;; figure out where to put it
	mov bx, 0x7C00
	sub bx, [BPB_BytsPerSec]

	mov si, bx
	mov cl, 1
	call readDiskLBA
	
	pop dx
	;; dx = index of desired clusterpointer
	
	;; let's figure out the memory offset
	;; for the cluster pointer
	sal dx, 2
	add si, dx
	;; load the next cluster
	mov eax, [si]
	;; and set it to the new current cluster
	mov [CurrentCluster], eax
	
	;; clear the EoF flag and return
	clc
	ret
	
eofLoad:
	;; set the EoF flag and return
	stc
	ret

readDiskLBA:
	push si
	;; Set the LBA packet parameters
	mov [LBAindex], eax
	mov [LBAcount], cl
	mov [LBAseg], es
	mov [LBAaddr], bx
	;; set the error count to 0
	xor al, al
	push ax
.tryLoop:
	mov si, LBApacketAddr
	mov ah, 0x42
	mov dl, [BootDrive]
	int 13h
	jc .readError
	pop ax
	pop si
	ret


.readError:
	;; whoops! there was an error reading the drive!
	;; Let's check and see if we've already tried too many times
	
	;; grab the value
	pop ax
	inc al
	push ax
	
	;; It just so happens that the number of times we want to loop
	;; also can be used as the bit mask for comparing. How useful!
	and al, 0x04
	jz .tryLoop
	
freeze:
	;; Too many failures, display an error and freeze
	mov si, readFail
putStr:
	;; ah = useTeletype
	mov ah, 0x0E
	;; bh = use page 0, bl = useless in Bochs
	xor bx, bx
.loopPut:
	;; lodsb == mov al, si \ inc si
	;; too bad it doesn't do "or al, al" also
	lodsb
	;; check if al == 0
	or al, al
	;; if so, we're done
.here
	jz .here
	;; otherwise, let's put it
	int 10h
	;; and go again for the next character
	jmp .loopPut
	
;; Some basic data

readFail:
	db "Drive read failed!", 0
noFile:
	db "No FBOOT.SYS!", 0

fileName:
	db "FBOOT   SYS"

	;; this is here in case I make changes
	times 510-($-$$) db 0
	
	;; Standard end of boot sector
	db 0x55, 0xAA
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Darwin weird or my fault?

Post by Firestryke31 »

Actually, it'll boot just fine via the standard MS MBR (installed by Vista, I flagged the HFS+ partition as the boot one) on my computer. Though, I do use Chameleon for EFI emulation, so that may change some things.

Maybe I should write a quick boot sector that just prints the important registers when it turns over control...
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Darwin weird or my fault?

Post by Firestryke31 »

Okay, I wrote a simple diagnostic boot sector and that gives me the following results on RHW with Darwin:

Code: Select all

SS: 0x0000  GS: 0x2000
FS: 0x2000  ES: 0x0000
DS: 0x0000  CS: 0x0000
DI: 0x0000  SI: 0x0000
BP: 0x0000  SP: 0xFFF0
BX: 0x0000  DX: 0x0080
CX: 0x0000  AX: 0x0000
So it seems that Darwin doesn't quite follow the standard of passing the partition pointer in DS:SI...

I've attached the ASM file in case you want to inspect my boot sector...
Attachments
DiagBoot.asm
Diagnostic boot sector source
(2.84 KiB) Downloaded 96 times
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Darwin weird or my fault?

Post by Firestryke31 »

Sorry to triple post, but I just wanted to update: I modified the above boot sector to do a stack dump from SP to BP and got... 0s. 16 bytes of 0s.

I've tried a glance through the Darwin source repository, but there's just so much stuff, and the 3 or 4 things I thought would have the code I'm looking for didn't. I'd rather not download half of OSX just to find out why Vista can boot from the Darwin menu. What does Vista do to find itself that I don't?
Attachments
DiagBoot.asm
Update of DiagBoot
(3.04 KiB) Downloaded 165 times
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: Darwin weird or my fault?

Post by JAAman »

So it seems that Darwin doesn't quite follow the standard of passing the partition pointer in DS:SI...
if you rely on this behavior, then that would explain why (since MS bootloaders do not rely on this behavior, and it is not guaranteed to be true from all MBRs/boot managers)
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Darwin weird or my fault?

Post by Firestryke31 »

So how do they find themselves? It seems kind of hard to do in 512 bytes without using some cheap hack.
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: Darwin weird or my fault?

Post by JAAman »

what they do is:
first load the MBR (they do not even rely on the old MBR mapping it to a known position)
then they parse the partition table looking for an 'active' partition

its not hard to do, and only uses a few bytes to do it (at least thats how the FAT32 bootloader does it...)
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Darwin weird or my fault?

Post by Firestryke31 »

I guess I could do something like that, but I can't rely on it being the active partition. I have two other OSs on my computer (which is why I'm using the Darwin loader).
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Darwin weird or my fault?

Post by neon »

Keep in mind bootstrap programs do not *need* to be 512 bytes. If you need more bytes, simply have your 1st sector load the rest of the boot strap program into memory. No more 512 byte limitation ;)
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Darwin weird or my fault?

Post by Firestryke31 »

But that would need hax, and I don't want to have to do any special formatting of that partition to get it to work. Keep in mind that this particular partition already exists on a physical drive. Plus it's fun packing 800 features into 512 bytes.
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Darwin weird or my fault?

Post by Firestryke31 »

But what if there are 2 NTFS partitions? And if for some inexplicable reason the user installed on the second partition?

I think that what I'll do is this:
-Load first sector, and compare 512 bytes to 0x7C00
-If same, not on partitioned drive: load normally
-else
--while(not same partition and still have more to check)
---load first sector of partition
---Compare to bootloader
---If same, add partition start offset to FirstDataSector and FATsector, and break loop
---else loop again
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Darwin weird or my fault?

Post by Firestryke31 »

Whee, double posting again.

I couldn't fit the above loop into my boot sector (pushed it up to 532 bytes, with space optimizations) so I created a separate version for partitioned drives. I put it on my FAT32 drive and got a "No FBOOT.SYS", which is both good and bad. It's good because at least now it's trying to read the root directory. It's bad because there is, in fact, an FBOOT.SYS file there, but it's not being found.

I've looked over my code, but you know how it gets to be when you stare at the same code for hours on end. I've attached it in case any of you want to have a go at it.

Edit:
Image

I just realized, there's some code that depends on eax being zeroed, after my partition finding code completely screws eax up, and I never cleared it before said dependent code. I feel stupid, but at least I found it.
Attachments
BootSectorPartition.asm
(7.74 KiB) Downloaded 98 times
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: Darwin weird or my fault?

Post by JAAman »

iirc, a boot manager is required to change the boot partition to be active before booting it...

that way the bootloader can rely on the fact that only the 'active' partition will ever be booted (iirc windows never looks at the partition type byte... thats strictly for disk tools to use)

windows doesnt rely on either the MBR being located at a specific location, or the partition being pointed to by any particular registers, and loads the MBR off the disk, and looks for the active partition to know which one it booted from (and, iirc, it looks in that partition for the boot script telling it which disk/partition contains the actual OS)
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Darwin weird or my fault?

Post by Firestryke31 »

Except that I've got my Leopard HFS+ partition marked as active, so that the MBR will load the Darwin boot sector, which then chains into the Vista boot sector, and the Vista boot sector has no problems finding the rest of the NTFS partition even though an HFS+ partition is marked active.

But it doesn't matter to me, because it works, and if for some reason it breaks I know how to make it work again.
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: Darwin weird or my fault?

Post by JAAman »

what a boot manager is supposed to do, is first change the partition table to point the other partition to be active... (though usually boot managers are not in the partition at all, but are loaded by the MBR instead -- and not generally part of any partition... so im not entirely sure how that works this way)

then again, perhaps the NTLDR works differently... idk, i know that is how it was done under FAT...


strictly speaking, there is another way it could determine the boot partition... the boot sector (for FAT anyway... not sure if its part of NTFS) contains the offset from start of physical disk for the bootsector (that is HiddenSectorsEx)
Post Reply