flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Bootloader example error

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
DataHunter2009



Joined: 10 Jun 2005
Posts: 144
DataHunter2009 10 Aug 2005, 03:33
I downloaded the example bootloader from the FASM site, but when I try to compile it, I get the following error:
Quote:
rb 7C00h+512-2-$ ;fill up to the boot record signature
error: invalid value.

So, I tried taking off the "-$" part, and it compiles fine, but the filesize says 33kb, not 512 like it's supposed to. ANy idea why this is happening?
Post 10 Aug 2005, 03:33
View user's profile Send private message Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 10 Aug 2005, 07:43
Here is how I tackle what their trying to do:

Code:
BootSector:                 ; Label in order to determine size of code for padding.
. . .
TIMES 510-($-BootSector)    DB 0
                            DW 0AA55h
    

The label BootSector is placed at the begining of the code. The math works out like this: 510 - (current relative location minus BootSector). So that anything less than 510 bytes will be filled with DB 0.

Looking at the example you give, I can not acertain what is up. It is using a reserved byte, then using the origin (supposing boot sector of 07C00h) adding 512 then deleting 2 (why not just use 510?) minus the current location. It makes sense that it is 30 some K, since 7C00h is somewhere near that...but it doesn't make any sense in relation to the size of the boot sector code (it's all relative, as that smart guy once said).
Post 10 Aug 2005, 07:43
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
Tomasz Grysztar 10 Aug 2005, 12:50
The "rb 7C00h+512-2-$" is OK, since the boot sector has the origin 7C00h, so $ is 7C00h+current position in sector. If it causes "invalid value" error it means that the value is negative, that is that $ is higher than 7C00h+510, what means that the code is too large to fit in the 512 bytes - you must have altered the source somehow that it does no longer fit in the single sector.
Post 10 Aug 2005, 12:50
View user's profile Send private message Visit poster's website Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1614
Location: Ukraine
shoorick 10 Aug 2005, 13:29
you can continue code beyond this signature, just inside first 512 bytes you will need load these additional sectors.
Post 10 Aug 2005, 13:29
View user's profile Send private message Visit poster's website Reply with quote
DataHunter2009



Joined: 10 Jun 2005
Posts: 144
DataHunter2009 10 Aug 2005, 14:07
Okay... um i didn't understand that last post by shoorick, becuase I'm new to this.

And all I did was changed the strings that displayed while the loader was, um... loading. SO I don't see how that could have changed much since iI only added one or two words. ANd I also took out the huge block of comments at the top... which to me, would have made it even smaller...
Post 10 Aug 2005, 14:07
View user's profile Send private message Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 10 Aug 2005, 14:24
@Tom, I see what you're saying. In my example BootSector is = org = 7C00h, and instead of padding with 0, rb doesn't transform the existing bytes in memory. Why put 512 - 2? Is that to show that the size for the entire boot sector has to be 512 bytes?

@DataHunter2009, if you increased teh number of characters then you have increased the number of bytes the boot loader is, which if it is over 510 bytes, will produce an error. From what I make of shoorick's message, he is saying that you can continue to code in the following sectors, so long as you load those sectors too, for your code. Just remember, the last two bytes of the first sector (the boot sector) has to be 55h and AAh. (equivelent to DW 0AA55h, due to endian-ness).
Post 10 Aug 2005, 14:24
View user's profile Send private message Reply with quote
DataHunter2009



Joined: 10 Jun 2005
Posts: 144
DataHunter2009 10 Aug 2005, 15:42
I don't see what could be causing the problem then... I mean, all I did was took out a huge block of comments and added two words to the loading message... Everything else is exactly the same as the example from the site.

Here it is, if you want to have a look:

Code:
        org     7C00h

FATSize         equ 6144                ;4096*1.5, max entries*entry size
RootSize        equ 512                 ;we'll read one sector (512b) at once

start:
        jmp     byte boot_code
        nop

b08_OEM         db 'FucKnows'
wSecSize        dw 'XX'                 ;always must be a multiplier of 32!
                                        ;(actually not used, 512b assumed)
bSecsPerCluster db 'X'                  ;number of sectors per one cluster
wResSecs        dw 'XX'                 ;boot and reserved sectors
                                        ;also serves as data sector variable
bNumFATs        db 'X'                  ;number of FATs
wRootEntries    dw 'XX'                 ;number of root entries
wTotSecs        dw 'XX'                 ;total sectors
bMedia          db 'X'                  ;"media descriptor", hehehe
wSecsPerFAT     dw 'XX'                 ;number of sector occupied by one FAT
wSecsPerTrack   dw 'XX'                 ;sectors per track, should be < 64!
wSidesPerTrack  dw 'XX'                 ;number of sides
dHiddenSecs     dd 'XXXX'               ;used only by DOS instead of MBR data
dBigTotSecs     dd 'XXXX'               ;big total sectors (not used)
bDrive          db 'X'                  ;drive number, filled from BIOS
                db 'X'
bExtBootSig     db 'X'                  ;extended boot sector signature
dSerNum         dd 0BA5EC0DEh           ;serial number Smile
b11_VolumeLabel db '=cakepiece='        ;volume label, addition to ser.num.?
b08_FileSysID   db 'FAT12   '           ;completely unused FS signature...

boot_code:
;the modified DPT, along with the address of the old one, will be stored here
        push    cs
        pop     ds                      ;ds=cs (0)
        mov     [bDrive],dl             ;save the boot drive number
        cmp     word [413h],(90000h+7C00h+FATSize+RootSize)/1024+1
                                        ;do we have the memory we need?
        jb      byte error              ;can't boot if less

        mov     ax,09000h               ;set ss to 9000h
        mov     ss,ax                   ;interrupts disabled for the next op.
        mov     sp,start                ;ss:sp=9000:7C00
        mov     es,ax                   ;es=9000

        mov     si,sp                   ;si=7C00
        mov     di,sp                   ;di=7C00
        mov     ch,01h                  ;256 to 511 words Wink
;       cld                             ;hopefully not needed...
        rep     movsw                   ;copy from 0000:7C00 to 9000:7C00

        lds     si,[1Eh*4]              ;ds:si->int 1Eh "handler"
        mov     di,boot_code+4          ;es:di->boot_code+4
        mov     [cs:di-4],si            ;save the address of the old...
        mov     [cs:di-2],ds            ;...int 1Eh "handler"
        mov     [cs:1Eh*4],di           ;store the offset and...
        mov     [cs:1Eh*4+2],ax         ;...segment of new int 1Eh "handler"
        mov     cl,11                   ;copy 11 bytes (ch=0 already)
        rep     movsb                   ;from the old "handler" to the new one

        mov     ds,ax                   ;ds=9000 now
        mov     byte [di-2],15          ;set head settle time to 15ms
;       mov     al,byte [wSecsPerTrack] ;al=sectors per track (last sector)
;       mov     byte [di-7],al          ;set last sector on track
        mov     byte [di-7],36          ;set last sector on track <-- hmm, ok?

;should recalibrate after changing DPT?

        jmp     far 9000h:jump_here     ;jump to the new code

error:
        mov     si,szError              ;si->error string
        call    write

        xor     ah,ah                   ;wait key function number
        int     16h                     ;BIOS keyboard interrupt

        mov     si,szCR
        call    write

;restore the address of the old int 1Eh "handler"
        les     bx,[boot_code]          ;get the address of the old int 1Eh
        xor     ax,ax                   ;ax=0
        mov     ds,ax                   ;ds=0
        mov     [1Eh*4],bx              ;save offset to interrupt table
        mov     [1Eh*4+2],es            ;save segment to interrupt table

        int     19h                     ;bootstrap

write:
        mov     ah,0Eh                  ;TTY output function number
;       mov     bx,0007h                ;attribute (weird...)

.more:
        lodsb                           ;get a byte
        or      al,al
        jz      .done
        int     10h                     ;BIOS video interrupt
        jmp     .more                   ;repeat for the rest

.done:
        retn

jump_here:
;read FAT to es:bx (9000:FAT) (es=ds)
        mov     al,[bNumFATs]           ;ax=number of FATs
        mov     ah,byte [wSecsPerFAT]   ;how many sectors to read, assumed <256
        mul     ah                      ;ax=sectors per all FATs
        push    [wResSecs]              ;preserve reserved sectors variable
        add     [wResSecs],ax           ;fix up the data sector variable
                                        ;now it points to the root directory
        xchg    cx,ax                   ;cx=sectors per all FATs
        pop     ax                      ;ax=FAT sector number
        mov     bx,FAT                  ;read to es:bx, which->FAT

        call    read_linear             ;read sectors

;read the root directory to es:bx (whatever it is)
;       mov     ax,[wResSecs]           ;root directory sector number, not
                                        ;needed: root directory goes right
                                        ;after both FATs
        mov     di,[wRootEntries]       ;di=number of entries in the root dir.
        mov     cl,4                    ;shift four bits right (/16)
        shr     di,cl                   ;di=di*32/512 (assumed sector size)
                                        ;so, di=number of root dir. sectors
        add     [wResSecs],di           ;fix up the data sector variable
                                        ;now it points to the first cluster

read_root:
        push    di                      ;preserve the counter

        push    es                      ;preserve es
        mov     cl,1                    ;one sector
        call    read_linear             ;read sector (ax gets increased)
        pop     es                      ;restore es

        mov     di,bx                   ;es:di->RootDir
        mov     cl,512/32               ;16 entries, sector size of 512 assumed
                                        ;(32=size of one entry)
read_root_nextfile:
        push    cx                      ;preserve counter

        mov     cl,11                   ;file name length
        mov     si,sFileName            ;ds:di->OS file name
        repe    cmpsb                   ;compare
        je      byte found_system       ;jump if equal (file found)
        add     di,cx                   ;increase si by the rest of cx
        add     di,21                   ;and fix up by 21 bytes - move to the
                                        ;next entry
        pop     cx                      ;restore counter
        loop    read_root_nextfile      ;repeat for next entry

        pop     di                      ;restore counter
        dec     di                      ;decrease it
        jnz     byte read_root          ;if not zero, repeat for next sector

;didn't find the OS file
        jmp     byte error

found_system:
        ;pop    bx                      ;pop two cx counters
        ;pop    bx
        mov     si,szLoading
        call    write

        mov     di,[es:di+15]           ;di=cluster number from directory entry

        mov     ax,160h                 ;0160 (segment)
        mov     es,ax                   ;load to 0160:0000 (0000:1600)
        xor     bx,bx                   ;0000 (offset)

next_block:
        xor     cx,cx
        mov     cl,[bSecsPerCluster]    ;reset sector count to 1 cluster
        mov     si,di                   ;si=next should-be cluster for
                                        ;contiguous reads
next_contiguous:
        mov     ax,3                    ;3
        mul     si                      ;multiply cluster number by 3
                                        ;dx assumed to be 0, it's a floppy!
        shr     ax,1                    ;divide by two
        xchg    bp,ax                   ;bp=ax
        mov     ax,word [FAT+bp]        ;ax=FAT element with junk
                                        ;(addressing with bp, since ss=ds)
        jc      byte odd_cluster        ;jump if the value was odd

even_cluster:
        and     ax,0FFFh                ;leave only lower 12 bits
        jmp     got_cluster             ;got it

odd_cluster:
        push    cx                      ;preserve sector count
        mov     cl,4                    ;shift four bits right
        shr     ax,cl                   ;(leave only bits 4-15)
        pop     cx                      ;restore sector count

got_cluster:
        inc     si                      ;si=current cluster+1
;the following two lines may be omitted, since it would give an error (fatal)
;only if at cluster FF7-FFE there would be FF8-FFF (EOF), then, yes, this will
;think that FAT entry #FF7-FFE points to cluster FF8-FFF (contiguous) and will
;continue the process, which will definitely lead to an error. But since on
;usual floppies there's normally no such cluster numbers... well, we can skip
;this part and the code that follows it will do all we need
;       cmp     ax,0FF8h                ;EOF (FF8-FFF)?
;       jae     byte force_read         ;if yes, force read

        cmp     ax,si                   ;next cluster=current cluster+1?
        je      byte still_contiguous   ;it's still contiguous

force_read:
        xchg    di,ax                   ;ax=di (base cluster), di=new cluster
        dec     ax                      ;decrease by 2 to get the actual... (1)
        dec     ax                      ;...cluster number (2)
;currently 1 sector per cluster assumed for floppies
        xor     dx,dx
        mov     dl,[bSecsPerCluster]
        mul     dx                      ;multiply by sectors per cluster
                                        ;(dx ignored)
        add     ax,[wResSecs]           ;fix up by data sector variable
        call    read_linear             ;read cx sectors at ax to es:bx Smile

        cmp     di,0FF8h                ;the new cluster is EOF (FF8-FFF)?
        jb      byte next_block         ;if not in this range, read next block

;we got it all!
all_read:
        jmp     far 0000h:1600h         ;jump to the code we've read

still_contiguous:
;prevent overflow of cx... but since the number of sectors on a normal floppy
;can't even get more than 4096, don't care. this is indeed stupid...
;?
;       cmp     cx,640*1024/512         ;anyway, not more than 640kb at once Smile
;       jae     byte force_read         ;if it's more... Wink (this is stupid)
;?
        add     cl,[bSecsPerCluster]    ;increase sector count by 1 cluster
        adc     ch,0
        jmp     next_contiguous

read_linear:    ;in: ax=LBA starting sector, cx - number, es:bx->buffer

;!!! The supplied es:bx should not only be paragraph aligned in physical !!!
;!!!                memory, but even 512-byte page aligned               !!!

;should preserve ax,bx,???
;destroys: es (increased, points to memory right after the last sector read),
;               bp, si...

;read:
; convert x (LBA starting sector) to CHS triple
; count=SecsPerTrack-S+1
; if count>n (number of sectors to read) then count=n
; calculate the maximum number of sectors that can be read between the
;   physical address of es:bx and the next 64kb boundary
; if count>number then count=number
; read count sectors at CHS to es:bx
; sub n,count
; add x,count
; if n<>0 then jmp read

read_linear_next:
        push    ax                      ;preserve LBA sector number
        push    cx                      ;preserve count

;convert LBA sector number to CHS triple
;       cmp     dx,[SecsPerTrack]       ;prevent overflow
;       jnb     byte read_linear_fail
;won't overflow on a floppy in normal conditions, and since we don't use dx at
;all, zero it (cwd used since the LBA sector will definitely be below 8000h on
;a floppy... lots of assumptions!):
        cwd                             ;dx=0

        div     [wSecsPerTrack]         ;dx=0-based sector (hopefully, < 256
                                        ;and even < 64), ax=quotient
        inc     dx                      ;make sector 1-based
        push    dx                      ;preserve it
        cwd                             ;dx=0 again
        div     [wSidesPerTrack]        ;dx=head, ax=track (should be < 256)
        pop     cx                      ;restore sector number to cx
        mov     ch,al                   ;ch=track number (only bits 7-0)
        mov     dh,dl                   ;dh=head number, cl=sector (bits 5-0)
        mov     dl,[bDrive]             ;dl=drive number

        mov     ax,[wSecsPerTrack]      ;al=sectors per track, should be < 256
        sub     al,cl                   ;al=sectors we can read at once
        inc     ax                      ;need to do that: sectors are 1-based
                                        ;(can_read=SecsPerTrack-S+1)

;may be we can address the saved cx using [ss:imm]?
        pop     si                      ;restore count to si
        push    si                      ;and save si back
        cmp     ax,si                   ;may be even less is left to be read?
        jna     byte read_linear_count_ok       ;no, not less

        xchg    si,ax                   ;yes, less, so ax=si

read_linear_count_ok:
;now calculate the maximum number of sectors that can be read between the
;physical address of es:bx and the next 64kb boundary
; -= the following code sucks =-
        push    bx                      ;begin suck - preserve them all!
        push    cx
        push    ax

        mov     ax,es                   ;ax=segment and bx=offset to read to
        mov     cl,4                    ;shift four bits right, divide by 16
        shr     bx,cl                   ;bx=offset/16
        add     ax,bx                   ;ax=physical address in paragraphs
        mov     bx,ax                   ;and bx is the same
        and     bx,0F000h               ;mask of lower 12 bits
        add     bh,010h                 ;increase bits 12-15
                                        ;(so we got the next 64kb boundary)
        sub     bx,ax                   ;so, bx=number of paragraphs between
                                        ;es:bx and the next 64kb boundary
        inc     cx                      ;cl=5 (for shift, divide by 32)
        shr     bx,cl                   ;now bx=number of 512b blocks between
                                        ;es:bx and the next 64kb boundary
        pop     ax                      ;restore ax
        pop     cx                      ;restore cx

        cmp     al,bl                   ;may be we're trying to read too much?
        jna     byte read_linear_count_really_ok        ;no, quite fair amount

        xchg    ax,bx                   ;yes, so read less (till the next 64kb
                                        ;boundary)
read_linear_count_really_ok:
        pop     bx                      ;end suck - restore the last register

        mov     bp,3                    ;number of retries

read_linear_again:
        push    ax                      ;save ax; count can be destroyed? RIGHT
        mov     ah,02h                  ;read sectors
        int     13h                     ;BIOS disk interrupt
        jnc     byte read_linear_ok     ;cool, no error (really?!! Cool )

        xor     ah,ah                   ;recalibrate
        int     13h                     ;well, dl already contains drive
                                        ;number if somebody needs it :I
        pop     ax                      ;restore count
        dec     bp                      ;decrease tries counter
        jnz     byte read_linear_again  ;jump if not zero (try again)

        jmp     error                   ;well, error            <-- hmm

read_linear_ok:
;-= this code also sucks! =-
        pop     ax                      ;restore count
        push    ax                      ;and preserve it again
        mov     cl,5                    ;shift five bits left (*32)
        shl     ax,cl                   ;ax=number of paragraphs we've read
                                        ;(number of sectors*512/16=...*32)
        mov     cx,es                   ;cx=current es
        add     cx,ax                   ;fix up cx
        mov     es,cx                   ;and put it back to es
        pop     si                      ;restore count to si

        pop     cx                      ;restore the number of sectors to read
        pop     ax                      ;restore LBA sector number
        add     ax,si                   ;increase it by the number of sectors
                                        ;already read
        sub     cx,si                   ;decrease it by the number of sectors
                                        ;already read
        jnz     byte read_linear_next   ;if any more sectors to read, do

        retn                            ;bye

szLoading       db 'Loading Reactor Operating System'
szCR            db 13,10,0
szError         db 'Load error or no code>',0
sFileName       db 'BASECODE   '        ;mister, what's that? guess yourself

                rb 7C00h+512-2-$        ;fill up to the boot record signature
                db 055h,0AAh            ;the signature itself

;end of sector - offset 200h (512)

FAT             rb 3072*2    
Post 10 Aug 2005, 15:42
View user's profile Send private message Reply with quote
DataHunter2009



Joined: 10 Jun 2005
Posts: 144
DataHunter2009 10 Aug 2005, 17:00
Sorry for the double post, but I am using a different boot loader now. It's simpler. But the problem is, it reboots when it tried to load the kernel. I'm guessing it can't find it, but I copied it onto the floppy just like I normally do.

Here's the code:

Code:
use16

start:
        mov ax, 0x7C00     ; init stack  - orig mov ax, 0x07C0     ; init stack
        mov ss, ax         ;
        mov bp, 0          ;
        mov sp, 0          ;
        mov ds, ax         ; init ds
        mov ax, 0x07E0     ; init es
        mov es, ax         ;
        mov ax, 0x0000     ; init fs
        mov fs, ax         ;

        mov ah, 0x00       ; init floppy
        mov dl, 0x01       ;
        int 0x13           ;
        jc @f              ; if error then reboot

        mov ah, 0x02       ; load kernel
        mov al, 10         ; read 5kb
        mov bx, 0x0000     ; the kernel's targetadress
        mov cx, 0x0002     ; read cylinder:0  sector:1
        mov dx, 0x0000     ; read head:0  drive:0 (A)
        int 0x13           ;
        jc @f              ; if error then reboot

        jmp 0x7C00:0x0000 ; run kernel - orig  call 0x07E0:0x0000

    @@: mov ax, [warmboot] ; reboot
        mov [fs:0x0472], ax;
        jmp 0xFFFF:0       ;

daten:
        warmboot dw 0x1234
        coldboot dw 0x0000

times 512-($-start)-2 db 0
dw 0xAA55    


Any ideas?
Post 10 Aug 2005, 17:00
View user's profile Send private message Reply with quote
THEWizardGenius



Joined: 14 Jan 2005
Posts: 382
Location: California, USA
THEWizardGenius 10 Aug 2005, 17:31
As I recall, the output file, without adding
Code:
rb 7C00h+512-2-$        ;fill up to the boot record signature
db 055h,0AAh              ;the signature itself
    

comes out to only a few bytes less than 510 bytes. Your code (not including the boot signature and null-padding) must not exceed 510 bytes. I'm guessing that by adding "Reactor Operating System" you made the file too long. Thus, (7C00h+512-2-$) evaluated to a negative value, which clearly wouldn't work too well. So you have to make it smaller.

I would recommend changing the loading message to "Loading ReactorOS" or "Loading ReactOS" or even "Loading ROS". The smaller, the better. You could just make it "Loading", too. Of course, you have to add a NULL at the end (if you wanted you could completely remove szCR and put NULL at the end of the message, but then all subsequent messages would be on the same line, until your kernel changed it).

In short, make it smaller and it'll work.

BTW, the thread "Bootloader" (started by me) has a bootloader based on the one you are using. It enters protected mode, so if you don't want that it won't be what you need. However, it works fine so you might try that. You do have to modify it a bit (read the last couple posts in the thread).
Post 10 Aug 2005, 17:31
View user's profile Send private message AIM Address Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 10 Aug 2005, 17:59
@DataHunter2009, I shortended the variable:
Code:
szLoading       db 'Loading ROS' 
    

and it compiled like a champ. Each character you add to the program adds to the byte count. Room in a the boot sector is precious stuff, eeking out every last bit (pun intended) of memory is a must.
Post 10 Aug 2005, 17:59
View user's profile Send private message Reply with quote
DataHunter2009



Joined: 10 Jun 2005
Posts: 144
DataHunter2009 10 Aug 2005, 18:12
Thanks! I changed the string and it compile fine, but now it says "load error or no code>" when it boots. I even changed "BASECODE " to "KERNEL BIN" and it still doesn't work.
Post 10 Aug 2005, 18:12
View user's profile Send private message Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1614
Location: Ukraine
shoorick 10 Aug 2005, 18:27
i'm not familiar with booting well, but as i know fat should start from 1 track, not directly from the first sector - there empty space on the track 0 i recommended to use before, but i can be wrong - has no docs near.

regards!
Post 10 Aug 2005, 18:27
View user's profile Send private message Visit poster's website Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1614
Location: Ukraine
shoorick 11 Aug 2005, 00:15
i was really wrong about floppy - it is possible to shift fat with increasing amount of reseved sectors in bpb
Post 11 Aug 2005, 00:15
View user's profile Send private message Visit poster's website Reply with quote
DataHunter2009



Joined: 10 Jun 2005
Posts: 144
DataHunter2009 11 Aug 2005, 00:53
Can someone please explain to me (in plain english) why this bootloader doesn't load my kernel? I don't know much of what you are saying, so I'm not sure i understand it all... hopefully I will once i get this crap working. Razz
Post 11 Aug 2005, 00:53
View user's profile Send private message Reply with quote
THEWizardGenius



Joined: 14 Jan 2005
Posts: 382
Location: California, USA
THEWizardGenius 11 Aug 2005, 01:13
I think you need two spaces between "KERNEL" and "BIN". In FAT, the main filename must be exactly 8 characters, and the extension exactly 3. If you have less you must pad with spaces. KERNEL is 6 characters, so put two spaces to make it 8. BIN is 3 characters, so you do not need to pad with spaces at all. So it should be "KERNEL BIN". Here's the (modified) code:
Code:
org     7C00h 

FATSize         equ 6144                ;4096*1.5, max entries*entry size 
RootSize        equ 512                 ;we'll read one sector (512b) at once 

start: 
        jmp     byte boot_code 
        nop 

b08_OEM         db 'FucKnows' 
wSecSize        dw 'XX'                 ;always must be a multiplier of 32! 
                                        ;(actually not used, 512b assumed) 
bSecsPerCluster db 'X'                  ;number of sectors per one cluster 
wResSecs        dw 'XX'                 ;boot and reserved sectors 
                                        ;also serves as data sector variable 
bNumFATs        db 'X'                  ;number of FATs 
wRootEntries    dw 'XX'                 ;number of root entries 
wTotSecs        dw 'XX'                 ;total sectors 
bMedia          db 'X'                  ;"media descriptor", hehehe 
wSecsPerFAT     dw 'XX'                 ;number of sector occupied by one FAT 
wSecsPerTrack   dw 'XX'                 ;sectors per track, should be < 64! 
wSidesPerTrack  dw 'XX'                 ;number of sides 
dHiddenSecs     dd 'XXXX'               ;used only by DOS instead of MBR data 
dBigTotSecs     dd 'XXXX'               ;big total sectors (not used) 
bDrive          db 'X'                  ;drive number, filled from BIOS 
                db 'X' 
bExtBootSig     db 'X'                  ;extended boot sector signature 
dSerNum         dd 0BA5EC0DEh           ;serial number  
b11_VolumeLabel db '=cakepiece='        ;volume label, addition to ser.num.? 
b08_FileSysID   db 'FAT12   '           ;completely unused FS signature... 

boot_code: 
;the modified DPT, along with the address of the old one, will be stored here 
        push    cs 
        pop     ds                      ;ds=cs (0) 
        mov     [bDrive],dl             ;save the boot drive number 
        cmp     word [413h],(90000h+7C00h+FATSize+RootSize)/1024+1 
                                        ;do we have the memory we need? 
        jb      byte error              ;can't boot if less 

        mov     ax,09000h               ;set ss to 9000h 
        mov     ss,ax                   ;interrupts disabled for the next op. 
        mov     sp,start                ;ss:sp=9000:7C00 
        mov     es,ax                   ;es=9000 

        mov     si,sp                   ;si=7C00 
        mov     di,sp                   ;di=7C00 
        mov     ch,01h                  ;256 to 511 words  
;       cld                             ;hopefully not needed... 
        rep     movsw                   ;copy from 0000:7C00 to 9000:7C00 

        lds     si,[1Eh*4]              ;ds:si->int 1Eh "handler" 
        mov     di,boot_code+4          ;es:di->boot_code+4 
        mov     [cs:di-4],si            ;save the address of the old... 
        mov     [cs:di-2],ds            ;...int 1Eh "handler" 
        mov     [cs:1Eh*4],di           ;store the offset and... 
        mov     [cs:1Eh*4+2],ax         ;...segment of new int 1Eh "handler" 
        mov     cl,11                   ;copy 11 bytes (ch=0 already) 
        rep     movsb                   ;from the old "handler" to the new one 

        mov     ds,ax                   ;ds=9000 now 
        mov     byte [di-2],15          ;set head settle time to 15ms 
;       mov     al,byte [wSecsPerTrack] ;al=sectors per track (last sector) 
;       mov     byte [di-7],al          ;set last sector on track 
        mov     byte [di-7],36          ;set last sector on track <-- hmm, ok? 

;should recalibrate after changing DPT? 

        jmp     far 9000h:jump_here     ;jump to the new code 

error: 
        mov     si,szError              ;si->error string 
        call    write 

        xor     ah,ah                   ;wait key function number 
        int     16h                     ;BIOS keyboard interrupt 

        mov     si,szCR 
        call    write 

;restore the address of the old int 1Eh "handler" 
        les     bx,[boot_code]          ;get the address of the old int 1Eh 
        xor     ax,ax                   ;ax=0 
        mov     ds,ax                   ;ds=0 
        mov     [1Eh*4],bx              ;save offset to interrupt table 
        mov     [1Eh*4+2],es            ;save segment to interrupt table 

        int     19h                     ;bootstrap 

write: 
        mov     ah,0Eh                  ;TTY output function number 
;       mov     bx,0007h                ;attribute (weird...) 

.more: 
        lodsb                           ;get a byte 
        or      al,al 
        jz      .done 
        int     10h                     ;BIOS video interrupt 
        jmp     .more                   ;repeat for the rest 

.done: 
        retn 

jump_here: 
;read FAT to es:bx (9000:FAT) (es=ds) 
        mov     al,[bNumFATs]           ;ax=number of FATs 
        mov     ah,byte [wSecsPerFAT]   ;how many sectors to read, assumed <256 
        mul     ah                      ;ax=sectors per all FATs 
        push    [wResSecs]              ;preserve reserved sectors variable 
        add     [wResSecs],ax           ;fix up the data sector variable 
                                        ;now it points to the root directory 
        xchg    cx,ax                   ;cx=sectors per all FATs 
        pop     ax                      ;ax=FAT sector number 
        mov     bx,FAT                  ;read to es:bx, which->FAT 

        call    read_linear             ;read sectors 

;read the root directory to es:bx (whatever it is) 
;       mov     ax,[wResSecs]           ;root directory sector number, not 
                                        ;needed: root directory goes right 
                                        ;after both FATs 
        mov     di,[wRootEntries]       ;di=number of entries in the root dir. 
        mov     cl,4                    ;shift four bits right (/16) 
        shr     di,cl                   ;di=di*32/512 (assumed sector size) 
                                        ;so, di=number of root dir. sectors 
        add     [wResSecs],di           ;fix up the data sector variable 
                                        ;now it points to the first cluster 

read_root: 
        push    di                      ;preserve the counter 

        push    es                      ;preserve es 
        mov     cl,1                    ;one sector 
        call    read_linear             ;read sector (ax gets increased) 
        pop     es                      ;restore es 

        mov     di,bx                   ;es:di->RootDir 
        mov     cl,512/32               ;16 entries, sector size of 512 assumed 
                                        ;(32=size of one entry) 
read_root_nextfile: 
        push    cx                      ;preserve counter 

        mov     cl,11                   ;file name length 
        mov     si,sFileName            ;ds:di->OS file name 
        repe    cmpsb                   ;compare 
        je      byte found_system       ;jump if equal (file found) 
        add     di,cx                   ;increase si by the rest of cx 
        add     di,21                   ;and fix up by 21 bytes - move to the 
                                        ;next entry 
        pop     cx                      ;restore counter 
        loop    read_root_nextfile      ;repeat for next entry 

        pop     di                      ;restore counter 
        dec     di                      ;decrease it 
        jnz     byte read_root          ;if not zero, repeat for next sector 

;didn't find the OS file 
        jmp     byte error 

found_system: 
        ;pop    bx                      ;pop two cx counters 
        ;pop    bx 
        mov     si,szLoading 
        call    write 

        mov     di,[es:di+15]           ;di=cluster number from directory entry 

        mov     ax,160h                 ;0160 (segment) 
        mov     es,ax                   ;load to 0160:0000 (0000:1600) 
        xor     bx,bx                   ;0000 (offset) 

next_block: 
        xor     cx,cx 
        mov     cl,[bSecsPerCluster]    ;reset sector count to 1 cluster 
        mov     si,di                   ;si=next should-be cluster for 
                                        ;contiguous reads 
next_contiguous: 
        mov     ax,3                    ;3 
        mul     si                      ;multiply cluster number by 3 
                                        ;dx assumed to be 0, it's a floppy! 
        shr     ax,1                    ;divide by two 
        xchg    bp,ax                   ;bp=ax 
        mov     ax,word [FAT+bp]        ;ax=FAT element with junk 
                                        ;(addressing with bp, since ss=ds) 
        jc      byte odd_cluster        ;jump if the value was odd 

even_cluster: 
        and     ax,0FFFh                ;leave only lower 12 bits 
        jmp     got_cluster             ;got it 

odd_cluster: 
        push    cx                      ;preserve sector count 
        mov     cl,4                    ;shift four bits right 
        shr     ax,cl                   ;(leave only bits 4-15) 
        pop     cx                      ;restore sector count 

got_cluster: 
        inc     si                      ;si=current cluster+1 
;the following two lines may be omitted, since it would give an error (fatal) 
;only if at cluster FF7-FFE there would be FF8-FFF (EOF), then, yes, this will 
;think that FAT entry #FF7-FFE points to cluster FF8-FFF (contiguous) and will 
;continue the process, which will definitely lead to an error. But since on 
;usual floppies there's normally no such cluster numbers... well, we can skip 
;this part and the code that follows it will do all we need 
;       cmp     ax,0FF8h                ;EOF (FF8-FFF)? 
;       jae     byte force_read         ;if yes, force read 

        cmp     ax,si                   ;next cluster=current cluster+1? 
        je      byte still_contiguous   ;it's still contiguous 

force_read: 
        xchg    di,ax                   ;ax=di (base cluster), di=new cluster 
        dec     ax                      ;decrease by 2 to get the actual... (1) 
        dec     ax                      ;...cluster number (2) 
;currently 1 sector per cluster assumed for floppies 
        xor     dx,dx 
        mov     dl,[bSecsPerCluster] 
        mul     dx                      ;multiply by sectors per cluster 
                                        ;(dx ignored) 
        add     ax,[wResSecs]           ;fix up by data sector variable 
        call    read_linear             ;read cx sectors at ax to es:bx  

        cmp     di,0FF8h                ;the new cluster is EOF (FF8-FFF)? 
        jb      byte next_block         ;if not in this range, read next block 

;we got it all! 
all_read: 
        jmp     far 0000h:1600h         ;jump to the code we've read 

still_contiguous: 
;prevent overflow of cx... but since the number of sectors on a normal floppy 
;can't even get more than 4096, don't care. this is indeed stupid... 
;? 
;       cmp     cx,640*1024/512         ;anyway, not more than 640kb at once  
;       jae     byte force_read         ;if it's more...  (this is stupid) 
;? 
        add     cl,[bSecsPerCluster]    ;increase sector count by 1 cluster 
        adc     ch,0 
        jmp     next_contiguous 

read_linear:    ;in: ax=LBA starting sector, cx - number, es:bx->buffer 

;!!! The supplied es:bx should not only be paragraph aligned in physical !!! 
;!!!                memory, but even 512-byte page aligned               !!! 

;should preserve ax,bx,??? 
;destroys: es (increased, points to memory right after the last sector read), 
;               bp, si... 

;read: 
; convert x (LBA starting sector) to CHS triple 
; count=SecsPerTrack-S+1 
; if count>n (number of sectors to read) then count=n 
; calculate the maximum number of sectors that can be read between the 
;   physical address of es:bx and the next 64kb boundary 
; if count>number then count=number 
; read count sectors at CHS to es:bx 
; sub n,count 
; add x,count 
; if n<>0 then jmp read 

read_linear_next: 
        push    ax                      ;preserve LBA sector number 
        push    cx                      ;preserve count 

;convert LBA sector number to CHS triple 
;       cmp     dx,[SecsPerTrack]       ;prevent overflow 
;       jnb     byte read_linear_fail 
;won't overflow on a floppy in normal conditions, and since we don't use dx at 
;all, zero it (cwd used since the LBA sector will definitely be below 8000h on 
;a floppy... lots of assumptions!): 
        cwd                             ;dx=0 

        div     [wSecsPerTrack]         ;dx=0-based sector (hopefully, < 256 
                                        ;and even < 64), ax=quotient 
        inc     dx                      ;make sector 1-based 
        push    dx                      ;preserve it 
        cwd                             ;dx=0 again 
        div     [wSidesPerTrack]        ;dx=head, ax=track (should be < 256) 
        pop     cx                      ;restore sector number to cx 
        mov     ch,al                   ;ch=track number (only bits 7-0) 
        mov     dh,dl                   ;dh=head number, cl=sector (bits 5-0) 
        mov     dl,[bDrive]             ;dl=drive number 

        mov     ax,[wSecsPerTrack]      ;al=sectors per track, should be < 256 
        sub     al,cl                   ;al=sectors we can read at once 
        inc     ax                      ;need to do that: sectors are 1-based 
                                        ;(can_read=SecsPerTrack-S+1) 

;may be we can address the saved cx using [ss:imm]? 
        pop     si                      ;restore count to si 
        push    si                      ;and save si back 
        cmp     ax,si                   ;may be even less is left to be read? 
        jna     byte read_linear_count_ok       ;no, not less 

        xchg    si,ax                   ;yes, less, so ax=si 

read_linear_count_ok: 
;now calculate the maximum number of sectors that can be read between the 
;physical address of es:bx and the next 64kb boundary 
; -= the following code sucks =- 
        push    bx                      ;begin suck - preserve them all! 
        push    cx 
        push    ax 

        mov     ax,es                   ;ax=segment and bx=offset to read to 
        mov     cl,4                    ;shift four bits right, divide by 16 
        shr     bx,cl                   ;bx=offset/16 
        add     ax,bx                   ;ax=physical address in paragraphs 
        mov     bx,ax                   ;and bx is the same 
        and     bx,0F000h               ;mask of lower 12 bits 
        add     bh,010h                 ;increase bits 12-15 
                                        ;(so we got the next 64kb boundary) 
        sub     bx,ax                   ;so, bx=number of paragraphs between 
                                        ;es:bx and the next 64kb boundary 
        inc     cx                      ;cl=5 (for shift, divide by 32) 
        shr     bx,cl                   ;now bx=number of 512b blocks between 
                                        ;es:bx and the next 64kb boundary 
        pop     ax                      ;restore ax 
        pop     cx                      ;restore cx 

        cmp     al,bl                   ;may be we're trying to read too much? 
        jna     byte read_linear_count_really_ok        ;no, quite fair amount 

        xchg    ax,bx                   ;yes, so read less (till the next 64kb 
                                        ;boundary) 
read_linear_count_really_ok: 
        pop     bx                      ;end suck - restore the last register 

        mov     bp,3                    ;number of retries 

read_linear_again: 
        push    ax                      ;save ax; count can be destroyed? RIGHT 
        mov     ah,02h                  ;read sectors 
        int     13h                     ;BIOS disk interrupt 
        jnc     byte read_linear_ok     ;cool, no error (really?!!  ) 

        xor     ah,ah                   ;recalibrate 
        int     13h                     ;well, dl already contains drive 
                                        ;number if somebody needs it :I 
        pop     ax                      ;restore count 
        dec     bp                      ;decrease tries counter 
        jnz     byte read_linear_again  ;jump if not zero (try again) 

        jmp     error                   ;well, error            <-- hmm 

read_linear_ok: 
;-= this code also sucks! =- 
        pop     ax                      ;restore count 
        push    ax                      ;and preserve it again 
        mov     cl,5                    ;shift five bits left (*32) 
        shl     ax,cl                   ;ax=number of paragraphs we've read 
                                        ;(number of sectors*512/16=...*32) 
        mov     cx,es                   ;cx=current es 
        add     cx,ax                   ;fix up cx 
        mov     es,cx                   ;and put it back to es 
        pop     si                      ;restore count to si 

        pop     cx                      ;restore the number of sectors to read 
        pop     ax                      ;restore LBA sector number 
        add     ax,si                   ;increase it by the number of sectors 
                                        ;already read 
        sub     cx,si                   ;decrease it by the number of sectors 
                                        ;already read 
        jnz     byte read_linear_next   ;if any more sectors to read, do 

        retn                            ;bye 

szLoading       db 'Loading ROS'
szCR            db 13,10,0 
szError         db 'Load error or no code>',0 
sFileName       db 'KERNEL  BIN'        ;mister, what's that? guess yourself 

                rb 7C00h+512-2-$        ;fill up to the boot record signature 
                db 055h,0AAh            ;the signature itself 

;end of sector - offset 200h (512) 

FAT             rb 3072*2
    


Note: I haven't yet tried this, haven't even compiled it, but it should work. You could always try mine if not Wink
Post 11 Aug 2005, 01:13
View user's profile Send private message AIM Address Reply with quote
DataHunter2009



Joined: 10 Jun 2005
Posts: 144
DataHunter2009 11 Aug 2005, 01:19
I already tried that, but thanks for posting Smile. It doidn't work either. Still gave me the load error. Sad
Post 11 Aug 2005, 01:19
View user's profile Send private message Reply with quote
THEWizardGenius



Joined: 14 Jan 2005
Posts: 382
Location: California, USA
THEWizardGenius 11 Aug 2005, 01:22
Odd... you could try my bootloader. It does pmode, which maybe you don't want, but you can try it and if it works remove the pmode code from the bootloader. A test kernel for use with the bootloader:
Code:
;A test kernel for JOS1
format binary
use32
org 0x10000

;Write a "J" on the screen
mov word [0xB8000],'JJ'
mov word [0xB8002],'aa'
mov word [0xB8004],'mm'
mov word [0xB8006],'ee'
mov word [0xB8008],'ss'
mov word [0xB800A],'!!'

;And "hlt", which saves more power than "jmp $"
cli
hlt

;gdt:                      dw  0x0000, 0x0000, 0x0000, 0x0000
;codesel:                  dw  0xFFFF, 0x0000, 0x9800, 0x00CF
;datasel:                  dw  0xFFFF, 0x0000, 0x9200, 0x00CF
;gdt_end:
;gdtr:                     dw  gdt_end - gdt - 1
;                          dd  gdt
    


Description: The bootloader.
Download
Filename: JOS1Boot.asm
Filesize: 11.09 KB
Downloaded: 355 Time(s)


_________________
FASM Rules!
OS Dev is fun!
Pepsi tastes nasty!
Some ants toot!
It's over!
Post 11 Aug 2005, 01:22
View user's profile Send private message AIM Address Reply with quote
DataHunter2009



Joined: 10 Jun 2005
Posts: 144
DataHunter2009 11 Aug 2005, 02:00
That doesn't work either. I actually think that Virtual PC is messing everything up. I've tried almost 13 bootloaders and every one of them has locked up or restarted on VPC. I recently caught my testbed computer on fire, so I have to use an emulator to test everything. Razz I think i'll download VMware and try it on that.
Post 11 Aug 2005, 02:00
View user's profile Send private message Reply with quote
THEWizardGenius



Joined: 14 Jan 2005
Posts: 382
Location: California, USA
THEWizardGenius 11 Aug 2005, 16:42
Well in that case why not try a real PC? Razz Maybe it will work...
Post 11 Aug 2005, 16:42
View user's profile Send private message AIM Address Reply with quote
DataHunter2009



Joined: 10 Jun 2005
Posts: 144
DataHunter2009 11 Aug 2005, 17:42
Like I said already, my testbed machine caught fire, so I can't use it. And my nly other system is way to expensive to test this on.
Post 11 Aug 2005, 17:42
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.