Loading BIN From Floppy

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
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Loading BIN From Floppy

Post by Omega »

Hi. Found some example code that loads a COM or EXE from the root of a floppy and I converted it to nasm and had it working fine, but I tried to have it load a C compiled (DJGPP) and linked to 0x1000 and rendered as a BIN, but it will not find my file. The fat12 code is like so:

Code: Select all

[BITS 16]

?                       equ     0
ImageLoadSeg            equ     60h

[SECTION .text]
[ORG 0]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Boot sector starts here ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        jmp     short   start
        nop
bsOemName               DB      "EIGHTCHR"      ; 0x03

;;;;;;;;;;;;;;;;;;;;;
;; BPB starts here ;;
;;;;;;;;;;;;;;;;;;;;;

bpbBytesPerSector       DW      ?               ; 0x0B
bpbSectorsPerCluster    DB      ?               ; 0x0D
bpbReservedSectors      DW      ?               ; 0x0E
bpbNumberOfFATs         DB      ?               ; 0x10
bpbRootEntries          DW      ?               ; 0x11
bpbTotalSectors         DW      ?               ; 0x13
bpbMedia                DB      ?               ; 0x15
bpbSectorsPerFAT        DW      ?               ; 0x16
bpbSectorsPerTrack      DW      ?               ; 0x18
bpbHeadsPerCylinder     DW      ?               ; 0x1A
bpbHiddenSectors        DD      ?               ; 0x1C
bpbTotalSectorsBig      DD      ?               ; 0x20

;;;;;;;;;;;;;;;;;;;
;; BPB ends here ;;
;;;;;;;;;;;;;;;;;;;

bsDriveNumber           DB      ?               ; 0x24
bsUnused                DB      ?               ; 0x25
bsExtBootSignature      DB      ?               ; 0x26
bsSerialNumber          DD      ?               ; 0x27
bsVolumeLabel           DB      "NO NAME    "   ; 0x2B
bsFileSystem            DB      "FAT12   "      ; 0x36

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Boot sector code starts here ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

start:
        cld

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; How much RAM is there? ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        int     12h             ; get conventional memory size (in KBs)
        shl     ax, 6           ; and convert it to paragraphs

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for the boot sector and the stack ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        sub     ax, 512 / 16    ; reserve 512 bytes for the boot sector code
        mov     es, ax          ; es:0 -> top - 512

        sub     ax, 2048 / 16   ; reserve 2048 bytes for the stack
        mov     ss, ax          ; ss:0 -> top - 512 - 2048
        mov     sp, 2048        ; 2048 bytes for the stack

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Copy ourself to top of memory ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     cx, 256
        mov     si, 7C00h
        xor     di, di
        mov     ds, di
        rep     movsw

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Jump to relocated code ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        push    es
        push    word main
        retf

main:
        push    cs
        pop     ds

        mov     [bsDriveNumber], dl     ; store boot drive number

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for a FAT12 image (6KB max) and load it whole ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     ax, [bpbBytesPerSector]
        shr     ax, 4                   ; ax = sector size in paragraphs
        mov     cx, [bpbSectorsPerFAT]  ; cx = FAT size in sectors
        mul     cx                      ; ax = FAT size in paragraphs

        mov     di, ss
        sub     di, ax
        mov     es, di
        xor     bx, bx                  ; es:bx -> buffer for the FAT

        mov     ax, [bpbHiddenSectors]
        mov     dx, [bpbHiddenSectors+2]
        add     ax, [bpbReservedSectors]
        adc     dx, bx                  ; dx:ax = LBA

        call    ReadSector

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for a root directory and load it whole ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     bx, ax
        mov     di, dx                  ; save LBA to di:bx

        mov     ax, 32
        mov     si, [bpbRootEntries]
        mul     si
        div     word [bpbBytesPerSector]
        mov     cx, ax                  ; cx = root directory size in sectors

        mov     al, [bpbNumberOfFATs]
        cbw
        mul     word [bpbSectorsPerFAT]
        add     ax, bx
        adc     dx, di                  ; dx:ax = LBA

        push    es                      ; push FAT segment (2nd parameter)

        push    word ImageLoadSeg
        pop     es
        xor     bx, bx                  ; es:bx -> buffer for root directory

        call    ReadSector

        add     ax, cx
        adc     dx, bx                  ; adjust LBA for cluster data

        push    dx
        push    ax                      ; push LBA for data (1st parameter)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Look for a COM/EXE program to be load and run ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     di, bx                  ; es:di -> root entries array
        mov     dx, si                  ; dx = number of root entries
        mov     si, ProgramName         ; ds:si -> program name

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Looks for a file with particular name ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input:  DS:SI -> file name (11 chars) ;;
;;         ES:DI -> root directory array ;;
;;         DX = number of root entries   ;;
;; Output: SI = cluster number           ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FindName:
        mov     cx, 11
FindNameCycle:
		mov si,dots ; Store our String
        lodsb
		mov     ah, 0Eh
        mov     bx, 7
		int 10h
        cmp     byte [es:di], ch
        je      FindNameFailed          ; end of root directory
        pusha
        repe    cmpsb
        popa
        je      FindNameFound
        add     di, 32
        dec     dx
        jnz     FindNameCycle           ; next root entry
FindNameFailed:
        jmp     ErrFind
FindNameFound:
        jmp     Found
        mov     si, [es:di+1Ah]         ; si = cluster no.

;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Load entire a program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadNextCluster:
        call    ReadCluster
        cmp     si, 0FF8h
        jc      ReadNextCluster         ; if not End Of File

;;;;;;;;;;;;;;;;;;;
;; Type checking ;;
;;;;;;;;;;;;;;;;;;;

        ;cli                             ; for stack adjustments

        ;mov     ax, ImageLoadSeg
        ;mov     es, ax

        ;cmp     word [es:0], 5A4Dh      ; "MZ" signature?
        ;je      RelocateEXE             ; yes, it's an EXE program

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Setup and Run COM program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     ax, es
        sub     ax, 10h                 ; "org 100h" stuff :)
        mov     es, ax
        mov     ds, ax
        mov     ss, ax
        xor     sp, sp
        push    es
        push    word 1000h
        jmp     Run

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Relocate, setup and run EXE program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RelocateEXE:
        mov     ds, ax

        add     ax, [ds:08h]            ; ax = image base
        mov     cx, [ds:06h]            ; cx = reloc items
        mov     bx, [ds:18h]            ; bx = reloc table pointer

        jcxz    RelocationDone

ReloCycle:
        mov     di, [ds:bx]             ; di = item ofs
        mov     dx, [ds:bx+2]           ; dx = item seg (rel)
        add     dx, ax                  ; dx = item seg (abs)

        push    ds
        mov     ds, dx                  ; ds = dx
        add     [ds:di], ax             ; fixup
        pop     ds

        add     bx, 4                   ; point to next entry
        loop    ReloCycle

RelocationDone:

        mov     bx, ax
        add     bx, [ds:0Eh]
        mov     ss, bx                  ; ss for EXE
        mov     sp, [ds:10h]            ; sp for EXE

        add     ax, [ds:16h]            ; cs
        push    ax
        push    word [ds:14h]           ; ip
Run:
        mov     dl, [cs:bsDriveNumber]  ; let program know boot drive
        sti
        retf

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a FAT12 cluster      ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Inout:  ES:BX -> buffer    ;;
;;         SI = cluster no    ;;
;; Output: SI = next cluster  ;;
;;         ES:BX -> next addr ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadCluster:
        mov     bp, sp

        lea     ax, [si-2]
        xor     ch, ch
        mov     cl, [bpbSectorsPerCluster]
                ; cx = sector count
        mul     cx

        add     ax, [ss:bp+1*2]
        adc     dx, [ss:bp+2*2]
                ; dx:ax = LBA

        call    ReadSector

        mov     ax, [bpbBytesPerSector]
        shr     ax, 4                   ; ax = paragraphs per sector
        mul     cx                      ; ax = paragraphs read

        mov     cx, es
        add     cx, ax
        mov     es, cx                  ; es:bx updated

        mov     ax, 3
        mul     si
        shr     ax, 1
        xchg    ax, si                  ; si = cluster * 3 / 2

        push    ds
        mov     ds, [ss:bp+3*2]         ; ds = FAT segment
        mov     si, [ds:si]             ; si = next cluster
        pop     ds

        jnc     ReadClusterEven

        shr     si, 4

ReadClusterEven:
        and     si, 0FFFh               ; mask cluster value
ReadClusterDone:
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a sector using BIOS Int 13h fn 2 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input:  DX:AX = LBA                    ;;
;;         CX    = sector count           ;;
;;         ES:BX -> buffer address        ;;
;; Output: CF = 1 if error                ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadSector:
        pusha

ReadSectorNext:
        mov     di, 5                   ; attempts to read

ReadSectorRetry:
        pusha

        div     word [bpbSectorsPerTrack]
                ; ax = LBA / SPT
                ; dx = LBA % SPT         = sector - 1

        mov     cx, dx
        inc     cx
                ; cx = sector no.

        xor     dx, dx
        div     word [bpbHeadsPerCylinder]
                ; ax = (LBA / SPT) / HPC = cylinder
                ; dx = (LBA / SPT) % HPC = head

        mov     ch, al
                ; ch = LSB 0...7 of cylinder no.
        shl     ah, 6
        or      cl, ah
                ; cl = MSB 8...9 of cylinder no. + sector no.

        mov     dh, dl
                ; dh = head no.

        mov     dl, [bsDriveNumber]
                ; dl = drive no.

        mov     ax, 201h
                                        ; al = sector count
                                        ; ah = 2 = read function no.

        int     13h                     ; read sectors
        jnc     ReadSectorDone          ; CF = 0 if no error

        xor     ah, ah                  ; ah = 0 = reset function
        int     13h                     ; reset drive

        popa
        dec     di
        jnz     ReadSectorRetry         ; extra attempt
        jmp     short ErrRead

ReadSectorDone:
        popa
        dec     cx
        jz      ReadSectorDone2         ; last sector

        add     bx, [bpbBytesPerSector] ; adjust offset for next sector
        add     ax, 1
        adc     dx, 0                   ; adjust LBA for next sector
        jmp     short ReadSectorNext

ReadSectorDone2:
        popa
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Error Messaging Code ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;
ErrRead:
        mov     si, MsgErrRead
        jmp     Print
ErrFind:
        mov     si, MsgErrFind
		jmp     Print
Found:
		mov     si, MsgFound
Print:
        mov     ah, 0Eh
        mov     bx, 7

        lodsb
        int     10h                     

        jmp     $                 ; hang

;;;;;;;;;;;;;;;;;;;;;;
;; String constants ;;
;;;;;;;;;;;;;;;;;;;;;;
dots			db		".",0
MsgErrRead      db      "X",13,10,0
MsgErrFind      db      "N",13,10,0
MsgFound		db		"Y",13,10,0	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Fill free space with zeroes ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

times 510-($-$$) db 0           ; Fill up the file with zeros

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Name of a program to be load and run ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ProgramName     db      "KERNEL  BIN"   ; name and extension must be padded
                                        ; with spaces (11 bytes total)

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; End of the sector ID ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

                dw      0AA55h

The output is:
...N
I changed it only a bit and verified that it still finds the com (ASM) BIN but it still does not find mine (C) BIN. Perhaps it is with my linking, here is my code:

Code: Select all

c:\djgpp\bin\gcc -ffreestanding -c main.c -o main.o

c:\djgpp\bin\gcc -c video.c -o video.o
c:\djgpp\bin\gcc -c ports.c -o ports.o
c:\djgpp\bin\gcc -c gdt.c -o gdt.o
c:\djgpp\bin\gcc -c idt.c -o idt.o
c:\djgpp\bin\gcc -c irq.c -o irq.o
c:\djgpp\bin\gcc -c isrs.c -o isrs.o
c:\djgpp\bin\gcc -c timer.c -o timer.o
c:\djgpp\bin\gcc -c kb.c -o kb.o

c:\djgpp\bin\ld -e _main -Ttext 0x1000 -o kernel.o main.o hal.o video.o ports.o gdt.o idt.o irq.o isrs.o timer.o kb.o
c:\djgpp\bin\ld -i -e _main -Ttext 0x1000 -o kernel.o main.o hal.o video.o ports.o gdt.o idt.o irq.o isrs.o timer.o kb.o

c:\djgpp\bin\objcopy -R .note -R .comment -S -O binary kernel.o kernel.bin
c:\djgpp\bin\makeboot a.img x86boot.bin kernel.bin
Thanks
Free energy is indeed evil for it absorbs the light.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Loading BIN From Floppy

Post by Combuster »

Have you looked at what's exactly in the root table? If your file name got converted to a LFN entry the bootloader won't find it anymore (i.e. it will be something like KERNEL~1.BIN -> kernel.bin)

You can open up your (broken) floppy image in an hex editor and look for the string "KERNEL" and see what you can find.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Loading BIN From Floppy

Post by Omega »

@Combuster: Tried what you said, but I didn't see anywhere in hex the name of the file at all. So, I navigated to it in cmd and it didn't change the name to an LFN, it is <= 8 chars, so I don't know why it would convert it to LFN. I am using NASM as you can see above, so could that be why. The example I was using actually assembled using TASM; TASM makes .obj files and NASM .o and from what little I know about the two there lies differences, perhaps why mine wont work? thanks
Free energy is indeed evil for it absorbs the light.
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Loading BIN From Floppy

Post by Omega »

Well, after a bit of research it appears that DJGPP does not create PE headers. You can see that I used objcopy for that but no matter what I do it does not find my kernel. Someone?
Free energy is indeed evil for it absorbs the light.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Loading BIN From Floppy

Post by Combuster »

Now you say two contradicting things - The file *is not* on your disk because there's no reference on it in the corresponding disk image. You also say that the file *is* on your disk because you can list the directory and see it.

For this nice box of cookies, is the correct answer A or B ?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Loading BIN From Floppy

Post by Omega »

Keep the cookies, do you have beer (Heineken preferably) instead?

I thought you meant look in the kernel.bin, so let me now check the image. OK, it looks like:
KERNEL BIN
or
4B 45 52 4E 45 4C 20 20 42 49 4E
You can see already how I am addressing my kernel as KERNEL<space><space>BIN, so what could be the problem?

Here is the part that should load my kernel:

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Setup and Run COM program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     ax, es
        sub     ax, 10h                 ; "org 100h" stuff :) (was 100h, I made it 1000h probably to my own demise)
        mov     es, ax
        mov     ds, ax
        mov     ss, ax
        xor     sp, sp
        push    es
        push    word 1000h
        jmp     Run
Like I said, it is probably a linker issue. But, you would know better than I, so help? thanks
Free energy is indeed evil for it absorbs the light.
User avatar
Blue
Member
Member
Posts: 31
Joined: Thu Aug 02, 2007 6:34 am
Location: on the stack

Re: Loading BIN From Floppy

Post by Blue »

Hi

I do not know if this could be the problem, but I noticed that your code ends with:

Code: Select all

times 510-($-$$)  db 0           
ProgramName       db      "KERNEL  BIN"   
                        dw      0AA55h
So firstly you fill out any free space with zeros, then you write your program name after that and finally the boot signature. This would make the code fill 523 bytes, and BIOS usually only loads 512 bytes. This means that ProgramName will be "KE" and whatever might be following in the memory, hence why FileName might fail when comparing. Hope it will help you.

Blue
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Loading BIN From Floppy

Post by pcmattman »

Hi,

Change

Code: Select all

times 510-($-$$)  db 0           
ProgramName       db      "KERNEL  BIN"   
dw      0AA55h
[/code]

to

Code: Select all

ProgramName       db      "KERNEL  BIN"   
times 510-($-$$)  db 0           
dw      0AA55h
As the previous poster said, the "times 510...." code pads out the binary to 510 bytes, and then you use "dw 0AA55h" to insert the required two bytes at the end of the binary. By putting in your ProgramName after the "times 510..." you're going over the 512 byte limit.
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Loading BIN From Floppy

Post by Omega »

I think you guys solved this for me, because it appears to be finding the file now. If I change the name it says (N), if I change it back to kernel.bin then it hangs (as expected), but it will not do anything more than that. With my single stage loader I could jump right to main and I have my kernel responding to key presses which in this implementation of my loader does not; it only hangs after locating it. My kernel ran in 32 Pmode, so could that be the reason why my kernel won't execute? My kernel is really just a series of C code linked together to make a BIN file, so it isn't like a COM file that I can define an ORG, but I do do that in my linker and objcopy produces my executable BIN. thanks a lot
Free energy is indeed evil for it absorbs the light.
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Loading BIN From Floppy

Post by Omega »

Been searching all over and I found where that boot12.asm code came from; it is from DexOs. I found that code somewhere else and I don't think they ever said it was from DexOs. Anyway, after downloading DexOs (Craig Bramford's) source, I see that he is using an EXE which he writes the header in ASM and it executes using the same code as the code I posted above, except mine is COM only where his is both EXE and COM.

I have that code finding my KERNEL.BIN now except it does not execute my kernel. I am wondering if I need to do something with my linker or DJGPP to make this BIN an executable EXE. I orginally coded it to be loaded to 1000h and jmp'd to which works. I have a question:

Is there a way that I can still link my kernel to the loader and just jmp to it instead of seeking it on disk and trying to execute it that way?

How do you guys (non-GRUB users) load your kernel?

Thanks
Free energy is indeed evil for it absorbs the light.
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Loading BIN From Floppy

Post by Omega »

Never mind guys, I decided to use GRUB so that I could finally move on with my kernel. I just assembled my GRUB loader as a COFF image and linked it all together. I put GRUB on one disk and my kernel on another (for now) and it works great (no memory issues anymore). I might give the loader another go once I have my OS complete. Thanks
Free energy is indeed evil for it absorbs the light.
Post Reply