NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: flyhigh427 on July 16, 2011, 06:29:56 PM
-
hi
i got this loader off the web and have been studing it and others.
this will load a **.bin file and works but i cant get it to load a **.sys file .
is there a different way to load a system file ,like dos 6.2 ?
thanks and gb
;*************************************************************************
;the ultimate boot-strap loader
;to load a file from a DOS FAT12 floppy as the OS
;*************************************************************************
[BITS 16]
[ORG 0x0000]
jmp START
OEM_ID db "QUASI-OS"
BytesPerSector dw 0x0200
SectorsPerCluster db 0x01
ReservedSectors dw 0x0001
TotalFATs db 0x02
MaxRootEntries dw 0x00E0
TotalSectorsSmall dw 0x0B40
MediaDescriptor db 0xF0
SectorsPerFAT dw 0x0009
SectorsPerTrack dw 0x0012
NumHeads dw 0x0002
HiddenSectors dd 0x00000000
TotalSectorsLarge dd 0x00000000
DriveNumber db 0x00
Flags db 0x00
Signature db 0x29
VolumeID dd 0xFFFFFFFF
VolumeLabel db "QUASI BOOT"
SystemID db "FAT12 "
START:
; code located at 0000:7C00, adjust segment registers
cli
mov ax, 0x07C0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; create stack
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF
sti
; post message
mov si, msgLoading
call DisplayMessage
LOAD_ROOT:
; compute size of root directory and store in ‘cx’
xor cx, cx
xor dx, dx
mov ax, 0x0020 ; 32 byte directory entry
mul WORD [MaxRootEntries] ; total size of directory
div WORD [BytesPerSector] ; sectors used by directory
xchg ax, cx
; compute location of root directory and store in ‘ax’
mov al, BYTE [TotalFATs] ; number of FATs
mul WORD [SectorsPerFAT] ; sectors used by FATs
add ax, WORD [ReservedSectors] ; adjust for bootsector
mov WORD [datasector], ax ; base of root directory
add WORD [datasector], cx
; read root directory into memory (7C00:0200)
mov bx, 0x0200 ; copy root dir above bootcode
call ReadSectors
; browse root directory for binary image
mov cx, WORD [MaxRootEntries] ; load loop counter
mov di, 0x0200 ; locate first root entry
.LOOP:
push cx
mov cx, 0x000B ; eleven character name
mov si, ImageName ; image name to find
push di
rep cmpsb ; test for entry match
pop di
je LOAD_FAT
pop cx
add di, 0x0020 ; queue next directory entry
loop .LOOP
jmp FAILURE
LOAD_FAT:
; save starting cluster of boot image
mov si, msgCRLF
call DisplayMessage
mov dx, WORD [di + 0x001A]
mov WORD [cluster], dx ; file’s first cluster
; compute size of FAT and store in ‘cx’
xor ax, ax
mov al, BYTE [TotalFATs] ; number of FATs
mul WORD [SectorsPerFAT] ; sectors used by FATs
mov cx, ax
; compute location of FAT and store in ‘ax’
mov ax, WORD [ReservedSectors] ; adjust for bootsector
; read FAT into memory (7C00:0200)
mov bx, 0x0200 ; copy FAT above bootcode
call ReadSectors
; read image file into memory (0100:0000)
mov si, msgCRLF
call DisplayMessage
mov ax, 0x0100 ; destination of image CS
mov es, ax
mov bx, 0x0000 ; destination for image IP
push bx
LOAD_IMAGE:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call ClusterLBA ; convert cluster to LBA
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; sectors to read
call ReadSectors
push bx
; compute next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 0x0001 ;
;divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x0200 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 0x0001
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high twelve bits
.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file
jb LOAD_IMAGE
DONE:
mov si, msgCRLF
call DisplayMessage
push WORD 0x0100
push WORD 0x0000
retf
FAILURE:
mov si, msgFailure
call DisplayMessage
mov ah, 0x00
int 0x16 ; await keypress
int 0x19 ; warm boot computer
;*************************************************************************
; PROCEDURE DisplayMessage
; display ASCIIZ string at ds:si via BIOS
;*************************************************************************
DisplayMessage:
lodsb ; load next character
or al, al ; test for NUL character
jz .DONE
mov ah, 0x0E ; BIOS teletype
mov bh, 0x00 ; display page 0
mov bl, 0x07 ; text attribute
int 0x10 ; invoke BIOS
jmp DisplayMessage
.DONE:
ret
;*************************************************************************
; PROCEDURE ReadSectors
; reads ‘cx’ sectors from disk starting at ‘ax’ into
;memory location ‘es:bx’
;*************************************************************************
ReadSectors:
.MAIN:
mov di, 0x0005 ; five retries for error
.SECTORLOOP:
push ax
push bx
push cx
call LBACHS
mov ah, 0x02 ; BIOS read sector
mov al, 0x01 ; read one sector
mov ch, BYTE [absoluteTrack] ; track
mov cl, BYTE [absoluteSector] ; sector
mov dh, BYTE [absoluteHead] ; head
mov dl, BYTE [DriveNumber] ; drive
int 0x13 ; invoke BIOS
jnc .SUCCESS ; test for read error
xor ax, ax ; BIOS reset disk
int 0x13 ; invoke BIOS
dec di ; decrement error counter
pop cx
pop bx
pop ax
jnz .SECTORLOOP ; attempt to read again
int 0x18
.SUCCESS:
mov si, msgProgress
call DisplayMessage
pop cx
pop bx
pop ax
add bx, WORD [BytesPerSector] ; queue next buffer
inc ax ; queue next sector
loop .MAIN ; read next sector
ret
;*************************************************************************
; PROCEDURE ClusterLBA
; convert FAT cluster into LBA addressing scheme
; LBA = (cluster - 2) * sectors per cluster
;*************************************************************************
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
;*************************************************************************
; PROCEDURE LBACHS
; convert ‘ax’ LBA addressing scheme to CHS addressing scheme
; absolute sector = (logical sector / sectors per track) + 1
; absolute head = (logical sector / sectors per track) MOD number of heads
; absolute track = logical sector / (sectors per track * number of heads)
;*************************************************************************
LBACHS:
xor dx, dx ; prepare dx:ax for operation
div WORD [SectorsPerTrack] ; calculate
inc dl ; adjust for sector 0
mov BYTE [absoluteSector], dl
xor dx, dx ; prepare dx:ax for operation
div WORD [NumHeads] ; calculate
mov BYTE [absoluteHead], dl
mov BYTE [absoluteTrack], al
ret
absoluteSector db 0x00
absoluteHead db 0x00
absoluteTrack db 0x00
datasector dw 0x0000
cluster dw 0x0000
ImageName db "IO SYS"
msgLoading db 0x0D, 0x0A, "Loading Boot Image ", 0x0D, 0x0A, 0x00
msgCRLF db 0x0D, 0x0A, 0x00
msgProgress db ".", 0x00
msgFailure db 0x0D, 0x0A, "ERROR : Press Any Key to Reboot", 0x00
TIMES 510-($-$$) DB 0
DW 0xAA55
;*************************************************************************
-
I can't confirm this at the moment, but I seem to recall that dos loads at (segment) 0x70, not 0x100 as you're doing. It would be easy to try, in any case...
Best,
Frank
-
;A Basic Boot Sector for DOS 2.0 to 6.22. This is non-viral!
;
;(C) 1995 American Eagle Publications, Inc. All Rights Reserved!
i found this but i havent got it to work yet
;This segment is where the first operating system file (IO.SYS) will be
;loaded and executed from. We don't know (or care) what is there, as long as
;it will execute at 0070:0000H, but we do need the address to jump to defined
;in a separate segment so we can execute a far jump to it.
DOS_LOAD SEGMENT AT 0070H
ASSUME CS:DOS_LOAD
ORG 0
LOAD: ;Start of the first operating system program
DOS_LOAD ENDS
MAIN SEGMENT BYTE
ASSUME CS:MAIN,DS:MAIN,SS:NOTHING
-
hey yall does each defferent file type load into a defferent segment?
-
Not ordinarily. A bootsector has to load "something" at a known, fixed address - segment and offset. After that, the OS would select a (free) segment... could be selected by "file type", but usually not.
Best,
Frank
-
hey there all
i put mov ax, 0x0070 in one place and tryed it and it didnt work.
i also put it in push word 0x0070 and it didnt work.
the segments say use 0070:0000H ,,am i entering it right?
; read image file into memory (0100:0000)
mov si, msgCRLF
call DisplayMessage
mov ax, 0x0100 ; destination of image CS
mov es, ax
mov bx, 0x0000 ; destination for image IP
push bx
LOAD_IMAGE:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call ClusterLBA ; convert cluster to LBA
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; sectors to read
call ReadSectors
push bx
; compute next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 0x0001 ;
;divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x0200 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 0x0001
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high twelve bits
.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file
jb LOAD_IMAGE
DONE:
mov si, msgCRLF
call DisplayMessage
push WORD 0x0100
push WORD 0x0000
retf
-
If you made both of those changes in that snippet, it "should" work if it's going to. As an alternative to the "push/push/retf", you should be able to use:
jmp 0x70:0
(in your post, you don't indicate that the "70" is hex) But they "should" do the same thing, so if one doesn't work, the other probably won't either.
One of the things that makes a bootsector "hard" is that it's hard to figure out what went wrong, if something does. One technique is to put 0xB800 in gs (or so), and do:
mov byte [gs:0], 'A'
at "critical" junctures in the code, incrementing "A" (and/or the offset - by two!) to see how far you got before things went haywire. Still not easy, especially as you're jumping into code you didn't write!
Best,
Frank
-
its finilly trying to load io.sys but then locks up
-
ImageName db "IO SYS"
Can't tell for sure how many spaces in this. "IO" should be padded out to 8, before the "SYS". "Should" be obvious if it's "not found".
Maybe the entrypoint to "io.sys" isn't zero? Can you compare a "known good" bootsector to see what it does?
Best,
Frank
-
that 11 charter thing had me puzzeled..but i got that one .
-
does fat12 and fat have anything to do with it?
-
ive been reading how dos works the breakdown of segment by segment ,but its something that sys.com writes in or loads first .
-
hey and morning all
line number 6 in first code is the problem if im right .
because in the next set of code its beening put in a different place right?
Summary of what this thing does
(1)Copy Diskette Parameter Table which is pointed to by INT 1E.
(2)Alter the copy of the Diskette Parameter Table.
(3)Alter INT 1E to point to altered Diskette Parameter Table.
(4)Do INT 13 AH=00, disk reset call.
(5)Compute sector address of root directory.
(6)Read first sector of root directory into 0000:0500.
(7)Confirm that first two directory entries are for IO.SYS and MSDOS.SYS.
(8)Read first 3 sectors of IO.SYS into 0000:0700 (or 0070:0000).
(9)Leave some information in the registers and jump to IO.SYS at 0070:0000.
; read root directory into memory (7C00:0200)
mov bx, 0x0200 ; copy root dir above bootcode
call ReadSectors
; browse root directory for binary image
mov cx, WORD [MaxRootEntries] ; load loop counter
mov di, 0x0200 ; locate first root entry
-
Well... "line 6" says that the first sector of the root directory is read to 0000:0500. The code shows (apparently) it being read to offset 200(hex). But we don't know what's in es. So it looks like a "different place", and that would be a problem. I can't imagine you're reading anything to 0000:0200, that would be in the middle of your Interrupt Vector Table. But I recently read something suggesting that dos did that! Google "AARD code". I have no idea whether that's what you're seeing or not. If so, it might account for some confusion.
I'm not sure I'm entirely clear on what you're trying to do. You've got a floppy with dos on it, right? Put there by "sys.com"? And instead of letting the bootsector load "io.sys", you want to replace that bootsector with one of your own that does the same thing? Am I "following the plot" so far?
Oh. I'm not. The code you posted (in a comment) says 7C00:0200. That seems improbable (but possible). I would think 07C0:0200 would be more sensible (right after your bootsector).
What (else) am I missing?
Best,
Frank
-
thanks frank it give me something to do,only way to learn is to start doing something
-
when you load a bootmanger into the first 512 like grub. does it make a copy of the mbr ?
thanks
-
I suppose it depends on which bootmanager. I don't know what grub does. "Use the Source, Luke!", if all else fails. You probably want to make a copy of your MBR(s) for your own use, anyway. For examination, to see what it does, and for restoration if you mess it up. :)
The "partition table" is the most important part. Restoring one by "trial and error" is no fun! You've got everything "important" backed up anyway, right? The remainder of the MBR code is "easy"... just moves itself out of the way, reads the partition table to see which partition is bootable ("active"), loads the first sector of that partition to 0x7C00, and jumps to it...
Best,
Frank
-
Actual code entrypoint of IO.SYS files are 0070h:0200h
As first 512bytes of IO.SYS are not actual code only to make it recognized as an okay file to boot. (2 bytes are checked)
offset 0200h also has 2 additional bytes, and together all these 4 bytes makes for a "valid IO.SYS". That's standard for this recogznition to happen. Bytes at 0200h are actually also effectively "NOP" code (DEC DX INC DX or similiar I cannot rember on top of my head, the source below has all the correct bytes in very few lines). so jumping 070h:200h is perfectly valid after loading IO.SYS into 70h:0000.
I have abit short of time so sorry If it's abit messy this description.. Check my source example
The filesize possible with SYS.IO's without additional own loadingcode are not impressive. Standard SYS.IO I think has code that loads rest of the massive size they may have. I have yet to discover if this is true as I'm not working this way any longer.
<CODEBOX>
; A simple io.sys example, and standardly loaded into 70h:0 (0:700h), Works with bootdisks of Win95 - Win7
db "MZ" ; signature that is needed (DEC BP, POP DX)
TIMES (512)-($-$$) db 90h ; skipped
; No ORG needed as only using absolute memory references.
BITS 16
; 70h:200h (0:900h)
db "BJ" ; signature (executable and effectively a nop)(INC DX DEC DX)
; In this example move a chunk into 7c00h, and then jump there. As any boot would do.
; move 64KB from Begin (70h:400h, which is address 0b00h), to 7c0:0, which is address 7c00h.
cli
mov ax,0xb0 ; (0b00h)
mov ds,ax
mov esi,0
mov ax,0x7c0 ; (7c00)
mov es,ax
mov edi,0
mov cx,16384
std; allow copy from overlapping memory (lower to higher)
rep movsd
mov ax,0
mov es,ax
mov fs,ax
mov gs,ax
; mov dl,bootid could be done here
jmp 0:0x7c00
TIMES (1024)-($-$$) db 90h
; 70h:400h
Begin:
;INCBIN "body.bin" ; Any ordinary bootcode with ORG 7c00h as any bootsector would, it could be larger than 512bytes of course. the limit is not explored by me as said earlier, but 4-8KB has been accomplished without any problem, but not the 200-300kb range as been succeeded without modification though so I suspect.. that IO.SYS usually includes code to load things further.
</CODEBOX>
NOTE
If what you need is having a custom bootable disc with custom bootsector, that should be easy to exchange, and while also having a perfectly working DOS disk, that you could manage files normally on..
Instead consider this I made, this is to use on any DOS disk / usbkey / camera memorycard etc, fully bootable while flexible use.
I found this to be a better solution then.
http://forum.nasm.us/index.php?topic=1154.0
-
hey yall when you write a bootmanager or loader to the mbr how do you not step on something importent?
i know you put your own program into memory and jump to it,but dos expects some of it self to be in the 512
mbr ,the names and such i think but not sure.
thanks
-
You don't step on something important by not stepping on something important - don't expect Nasm to prevent it. I don't think you'll find any of dos in your MBR - the "important" part is the partition table. The MBR will load the bootsector of the partition marked "active" (bootable). That's where you'd find names like "IO SYS" (I think).
Best,
Frank
-
My way looking at things are these; I see MBR being a regular bootsector just with a bit more rigid layout.
The BIOS itself does not look into this tables except for few things. Don't want to go deeper without reason so I don't go there if not important.
; Minimal MBR, first sector of media
; 000-1BD Code (446 bytes)
times 0x1BE - ($-$$) db 0x90 ; actual code goes here, lets fill it with NOP here.
; Partition table follows, 4 entries (no Extended MBRs used so max 4 partions possible)
; 1BE-1CD (16 bytes) - Partition 1
db 0x80 ; Active? 80h meaning bootable 0 meaning non-bootable, only one of the four should be made bootable at a time.
; Partition start (in CHS format) Note that sectors in CHS format doesn't start at 0 but 1 (CHS starts at 0 0 1)
NOTE: db 0xFE,0xFF,0xFF tells BIOS and loaders to ignore CHS and force use LBA
db 0 ; HEAD (0-255)
db 1+(0<<6) ; SECTOR (1-63, 0 not used) NOTE: The 2 highest bits are not used for sector but as 2 highest bits of cylinder
db 0 ; CYLINDER (0-1023) This bytes contain low 8 bits of its 10bits
db 0x6C ; ID. Each OS/platform/filesystem has an ID to put here. Note: Some ID's actually means something special to some BIOS'es. eg. enables/disables INT 13h ext etc.
; Where partition ends (in CHS format) NOTE: db 0xFE,0xFF,0xFF tells BIOS and loaders to ignore CHS and force use LBA
; Partition end (in CHS format)
NOTE: db 0xFE,0xFF,0xFF tells BIOS and loaders to ignore CHS and force use LBA
db 0x7F ; HEAD (0-255)
db 0x3F+(0x3<<6) ; SECTOR (1-63, 0 not used) NOTE: The 2 highest bits are not used for sector but as 2 highest bits of cylinder
db 0x13 ; CYLINDER (0x313) (0-1023) (Note from line above 03 << 6 + 13h = 313h) This is 8 lowest bits of cylinder
; Where partition starts & ends (in LBA format) Note that sectors in LBA format does start at 0.
dd 63 ; 32bit LBA, (Sector 63 being the very standard place for a long time to have first partition start at) This field is called "relative sectors"
dd 100 ; 32bit LBA Length, number of sectors the partition should have) This field is called "total sectors"
; 1CE-1DD (16 bytes) - Partition 2 (same bytelayout as above)
dd 0,0,0,0
; 1DE-1ED (16 bytes) - Partition 3 (same bytelayout as above)
dd 0,0,0,0
; 1EE-1FD (16 bytes) - Partition 4 (same bytelayout as above)
dd 0,0,0,0
; 1FE-1FF (2 bytes) - Boot signature (This is also a must for a media to be bootable at all, few machines boot regardless but to be sure let's put it, don't leave home without it)
db 0x55,0xaa
Hope that shed some light on things :)
EDIT: Cleaned the table up abit.
-
thanks dreamco
-
ive been trying to load io.sys with this witch is for loading a bin.
do i have to change something ?
thanks
;*************************************************************************
;the ultimate boot-strap loader
;to load a file from a DOS FAT12 floppy as the OS
;*************************************************************************
[BITS 16]
[ORG 0x0000]
jmp START
OEM_ID db "WILLIAM4"
;dos bpb start
BytesPerSector dw 0x0200
SectorsPerCluster db 0x01
ReservedSectors dw 0x0001
TotalFATs db 0x02
MaxRootEntries dw 0x00E0
TotalSectorsSmall dw 0x0B40
MediaDescriptor db 0xF0
SectorsPerFAT dw 0x0009
SectorsPerTrack dw 0x0012
NumHeads dw 0x0002
HiddenSectors dd 0x00000000
TotalSectorsLarge dd 0x00000000
DriveNumber db 0x00
Flags db 0x00
Signature db 0x29
VolumeID dd 0x1501431d
VolumeLabel db "Am.s.c.d.x."
SystemID db "FAT12 "
;dos bpb end
START:
; code located at 0000:7C00, adjust segment registers
cli
mov ax, 0x07C0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; create stack
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF
sti
; post message
mov si, msgLoading
call DisplayMessage
LOAD_ROOT:
; compute size of root directory and store in ‘cx’
xor cx, cx
xor dx, dx
mov ax, 0x0020 ; 32 byte directory entry
mul WORD [MaxRootEntries] ; total size of directory
div WORD [BytesPerSector] ; sectors used by directory
xchg ax, cx
; compute location of root directory and store in ‘ax’
mov al, BYTE [TotalFATs] ; number of FATs
mul WORD [SectorsPerFAT] ; sectors used by FATs
add ax, WORD [ReservedSectors] ; adjust for bootsector
mov WORD [datasector], ax ; base of root directory
add WORD [datasector], cx
; read root directory into memory (7C00:0200)
mov bx, 0x0200 ; copy root dir above bootcode
call ReadSectors
; browse root directory for binary image
mov cx, WORD [MaxRootEntries] ; load loop counter
mov di, 0x0200 ; locate first root entry
.LOOP:
push cx
mov cx, 0x000B ; eleven character name
mov si, ImageName ; image name to find
push di
rep cmpsb ; test for entry match
pop di
je LOAD_FAT
pop cx
add di, 0x0020 ; queue next directory entry
loop .LOOP
jmp FAILURE
LOAD_FAT:
; save starting cluster of boot image
mov si, msgCRLF
call DisplayMessage
mov dx, WORD [di + 0x001A]
mov WORD [cluster], dx ; file’s first cluster
; compute size of FAT and store in ‘cx’
xor ax, ax
mov al, BYTE [TotalFATs] ; number of FATs
mul WORD [SectorsPerFAT] ; sectors used by FATs
mov cx, ax
; compute location of FAT and store in ‘ax’
mov ax, WORD [ReservedSectors] ; adjust for bootsector
; read FAT into memory (7C00:0200)
mov bx, 0x0200 ; copy FAT above bootcode
call ReadSectors
; read image file into memory (0100:0000)
mov si, msgCRLF
call DisplayMessage
mov ax, 0x0070 ; destination of image CS WAS O1OO
mov es, ax
mov bx, 0x0000 ; destination for image IP
push bx
LOAD_IMAGE:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call ClusterLBA ; convert cluster to LBA
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; sectors to read
call ReadSectors
push bx
; compute next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 0x0001 ;
;divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x0200 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 0x0001
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high twelve bits
.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file
jb LOAD_IMAGE
DONE:
mov si, msgCRLF
call DisplayMessage
push WORD 0x0070 ;WAS 0100
push WORD 0x0200 ;WAS 0000
retf
FAILURE:
mov si, msgFailure
call DisplayMessage
mov ah, 0x00
int 0x16 ; await keypress
int 0x19 ; warm boot computer
;*************************************************************************
; PROCEDURE DisplayMessage
; display ASCIIZ string at ds:si via BIOS
;*************************************************************************
DisplayMessage:
lodsb ; load next character
or al, al ; test for NUL character
jz .DONE
mov ah, 0x0E ; BIOS teletype
mov bh, 0x00 ; display page 0
mov bl, 0x07 ; text attribute
int 0x10 ; invoke BIOS
jmp DisplayMessage
.DONE:
ret
;*************************************************************************
; PROCEDURE ReadSectors
; reads ‘cx’ sectors from disk starting at ‘ax’ into
;memory location ‘es:bx’
;*************************************************************************
ReadSectors:
.MAIN:
mov di, 0x0005 ; five retries for error
.SECTORLOOP:
push ax
push bx
push cx
call LBACHS
mov ah, 0x02 ; BIOS read sector
mov al, 0x01 ; read one sector
mov ch, BYTE [absoluteTrack] ; track
mov cl, BYTE [absoluteSector] ; sector
mov dh, BYTE [absoluteHead] ; head
mov dl, BYTE [DriveNumber] ; drive
int 0x13 ; invoke BIOS
jnc .SUCCESS ; test for read error
xor ax, ax ; BIOS reset disk
int 0x13 ; invoke BIOS
dec di ; decrement error counter
pop cx
pop bx
pop ax
jnz .SECTORLOOP ; attempt to read again
int 0x18
.SUCCESS:
mov si, msgProgress
call DisplayMessage
pop cx
pop bx
pop ax
add bx, WORD [BytesPerSector] ; queue next buffer
inc ax ; queue next sector
loop .MAIN ; read next sector
ret
;*************************************************************************
; PROCEDURE ClusterLBA
; convert FAT cluster into LBA addressing scheme
; LBA = (cluster - 2) * sectors per cluster
;*************************************************************************
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
;*************************************************************************
; PROCEDURE LBACHS
; convert ‘ax’ LBA addressing scheme to CHS addressing scheme
; absolute sector = (logical sector / sectors per track) + 1
; absolute head = (logical sector / sectors per track) MOD number of heads
; absolute track = logical sector / (sectors per track * number of heads)
;*************************************************************************
LBACHS:
xor dx, dx ; prepare dx:ax for operation
div WORD [SectorsPerTrack] ; calculate
inc dl ; adjust for sector 0
mov BYTE [absoluteSector], dl
xor dx, dx ; prepare dx:ax for operation
div WORD [NumHeads] ; calculate
mov BYTE [absoluteHead], dl
mov BYTE [absoluteTrack], al
ret
absoluteSector db 0x00
absoluteHead db 0x00
absoluteTrack db 0x00
datasector dw 0x0000
cluster dw 0x0000
ImageName db "IO SYS"
msgLoading db 0x0D, 0x0A, "Loading Image ", 0x0D, 0x0A, 0x00
msgCRLF db 0x0D, 0x0A, 0x00
msgProgress db ".", 0x00
msgFailure db 0x0D, 0x0A, "ERROR: Press Any Key to Reboot", 0x00
;db "IO SYSMSDOS SYS"
TIMES 510-($-$$) DB 0
DW 0xAA55
-
ive been trying to load io.sys with this witch is for loading a bin.
do i have to change something ?
thanks
Just gazing quickly through..
What I think could be what's might messes things up is that you try load io.sys into offset 200h.
io.sys are normally loaded offset 0 and containing 200h worth of noise, making the actual codestart at offset 200h. But it's meant to be loaded at offset 0. 70:0 originally but which segment I guess doesn't matter.
Perhaps that is it? I understand changing into offset 0 when in 7c00 creates overlapping problems :(
Before attacking the problem you could try diassemble the io.sys to confirm it begins with garbled noise and code starts at 200h?
I am sorry, I see you are trying to load into 70h:0 and execute 70h:200h already.
This smells like one simple tiny pesky hidden bug
ADDED:
; read image file into memory (0100:0000)
mov si, msgCRLF
call DisplayMessage
mov ax, 0x0070 ; destination of image CS WAS O1OO
mov es, ax
mov bx, 0x0000 ; destination for image IP
push bx
Could it be simply a mov ds,ax missing?
-
hey yall trying a different way
if i load the mbr in to memory at 0000:7c00 then jump to it
do i have to move this into a different part of memory?
it tryes to load then i get a dos error
thanks all
;*************************************************************************
;the ultimate boot-strap loader
;to load a file from a DOS FAT12 floppy as the OS
;*************************************************************************
[BITS 16]
[ORG 0x0000]
jmp START
OEM_ID db "WILLIAM4"
;dos bpb start
BytesPerSector dw 0x0200
SectorsPerCluster db 0x01
ReservedSectors dw 0x0001
TotalFATs db 0x02
MaxRootEntries dw 0x00E0
TotalSectorsSmall dw 0x0B40
MediaDescriptor db 0xF0
SectorsPerFAT dw 0x0009
SectorsPerTrack dw 0x0012
NumHeads dw 0x0002
HiddenSectors dd 0x00000000
TotalSectorsLarge dd 0x00000000
DriveNumber db 0x00
Flags db 0x00
Signature db 0x29
VolumeID dd 0x1501431d
VolumeLabel db "Am.s.c.d.x."
SystemID db "FAT12 "
;dos bpb end
START:
; code located at 0000:7C00, adjust segment registers
cli
mov ax, 0x07C0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; create stack
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF
sti
; post message
mov si, msgLoading
call DisplayMessage
LOAD_ROOT:
; compute size of root directory and store in ‘cx’
xor cx, cx
xor dx, dx
mov ax, 0x0020 ; 32 byte directory entry
mul WORD [MaxRootEntries] ; total size of directory
div WORD [BytesPerSector] ; sectors used by directory
xchg ax, cx
; compute location of root directory and store in ‘ax’
mov al, BYTE [TotalFATs] ; number of FATs
mul WORD [SectorsPerFAT] ; sectors used by FATs
add ax, WORD [ReservedSectors] ; adjust for bootsector
mov WORD [datasector], ax ; base of root directory
add WORD [datasector], cx
; read root directory into memory (7C00:0200)
mov bx, 0x0200 ; copy root dir above bootcode
call ReadSectors
; browse root directory for binary image
mov cx, WORD [MaxRootEntries] ; load loop counter
mov di, 0x0200 ; locate first root entry
.LOOP:
push cx
mov cx, 0x000B ; eleven character name
mov si, ImageName ; image name to find
push di
rep cmpsb ; test for entry match
pop di
je LOAD_FAT
pop cx
add di, 0x0020 ; queue next directory entry
loop .LOOP
jmp FAILURE
LOAD_FAT:
; save starting cluster of boot image
mov si, msgCRLF
call DisplayMessage
mov dx, WORD [di + 0x001A]
mov WORD [cluster], dx ; file’s first cluster
; compute size of FAT and store in ‘cx’
xor ax, ax
mov al, BYTE [TotalFATs] ; number of FATs
mul WORD [SectorsPerFAT] ; sectors used by FATs
mov cx, ax
; compute location of FAT and store in ‘ax’
mov ax, WORD [ReservedSectors] ; adjust for bootsector
; read FAT into memory (7C00:0200)
mov bx, 0x0200 ; copy FAT above bootcode
call ReadSectors
; read image file into memory (0100:0000)
mov si, msgCRLF
call DisplayMessage
mov ax, 0x7C00 ; destination of image CS WAS O1OO
mov es, ax
mov bx, 0x0000 ; destination for image IP
push bx
LOAD_IMAGE:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call ClusterLBA ; convert cluster to LBA
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; sectors to read
call ReadSectors
push bx
; compute next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 0x0001 ;
;divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x0200 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 0x0001
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high twelve bits
.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file
jb LOAD_IMAGE
DONE:
mov si, msgCRLF
call DisplayMessage
push WORD 0x7C00
push WORD 0x0000
retf
FAILURE:
mov si, msgFailure
call DisplayMessage
mov ah, 0x00
int 0x16 ; await keypress
int 0x19 ; warm boot computer
;*************************************************************************
; PROCEDURE DisplayMessage
; display ASCIIZ string at ds:si via BIOS
;*************************************************************************
DisplayMessage:
lodsb ; load next character
or al, al ; test for NUL character
jz .DONE
mov ah, 0x0E ; BIOS teletype
mov bh, 0x00 ; display page 0
mov bl, 0x07 ; text attribute
int 0x10 ; invoke BIOS
jmp DisplayMessage
.DONE:
ret
;*************************************************************************
; PROCEDURE ReadSectors
; reads ‘cx’ sectors from disk starting at ‘ax’ into
;memory location ‘es:bx’
;*************************************************************************
ReadSectors:
.MAIN:
mov di, 0x0005 ; five retries for error
.SECTORLOOP:
push ax
push bx
push cx
call LBACHS
mov ah, 0x02 ; BIOS read sector
mov al, 0x01 ; read one sector
mov ch, BYTE [absoluteTrack] ; track
mov cl, BYTE [absoluteSector] ; sector
mov dh, BYTE [absoluteHead] ; head
mov dl, BYTE [DriveNumber] ; drive
int 0x13 ; invoke BIOS
jnc .SUCCESS ; test for read error
xor ax, ax ; BIOS reset disk
int 0x13 ; invoke BIOS
dec di ; decrement error counter
pop cx
pop bx
pop ax
jnz .SECTORLOOP ; attempt to read again
int 0x18
.SUCCESS:
mov si, msgProgress
call DisplayMessage
pop cx
pop bx
pop ax
add bx, WORD [BytesPerSector] ; queue next buffer
inc ax ; queue next sector
loop .MAIN ; read next sector
ret
;*************************************************************************
; PROCEDURE ClusterLBA
; convert FAT cluster into LBA addressing scheme
; LBA = (cluster - 2) * sectors per cluster
;*************************************************************************
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
;*************************************************************************
; PROCEDURE LBACHS
; convert ‘ax’ LBA addressing scheme to CHS addressing scheme
; absolute sector = (logical sector / sectors per track) + 1
; absolute head = (logical sector / sectors per track) MOD number of heads
; absolute track = logical sector / (sectors per track * number of heads)
;*************************************************************************
LBACHS:
xor dx, dx ; prepare dx:ax for operation
div WORD [SectorsPerTrack] ; calculate
inc dl ; adjust for sector 0
mov BYTE [absoluteSector], dl
xor dx, dx ; prepare dx:ax for operation
div WORD [NumHeads] ; calculate
mov BYTE [absoluteHead], dl
mov BYTE [absoluteTrack], al
ret
absoluteSector db 0x00
absoluteHead db 0x00
absoluteTrack db 0x00
datasector dw 0x0000
cluster dw 0x0000
ImageName db "TEST2 BIN"
msgLoading db 0x0D, 0x0A, "Loading Image ", 0x0D, 0x0A, 0x00
msgCRLF db 0x0D, 0x0A, 0x00
msgProgress db ".", 0x00
msgFailure db 0x0D, 0x0A, "ERRORPress Any Key to Reboot", 0x00
TIMES 510-($-$$) DB 0
DW 0xAA55
;*************************************************************************
-
hey it does work ,so thats how they do that
thanks yall
-
Following Dreamaco's advice, I disassembled io.sys. Indeed, it starts with 200h bytes of... mostly zeros (the expected "MZ" sig and a few more bytes first). At offset 200h, I see "inc dx", "dec dx" ("BJ") as expected. Following that, I see some rather "strange" code! It looks like it is expecting a "known" value in bp, and apparently some "known" values on the stack. To find out what these values might be, I'd have to disassemble the code that loads and jumps to io.sys. (not your code, but the original dos bootsector)
I'm a little confused. ("a little" he says!) You refer to an MBR, but your code is for FAT12. It would be unusual to find FAT12 used on a hard drive, and unusual to find an MBR on a floppy, although I guess you could do either or both...
The "usual" scheme would be for the MBR, loaded by BIOS to 0x7C00, to move itself out of the way, read the partition table to discover the "active" partition (you've only got one, I guess), load the "real" bootsector to 0x7C00, and jump to it. This is where I'd expect to see io.sys found and loaded (possibly in a "second stage" loader, not the 512 byte bootsector itself). As I said, io.sys seems to be expecting some "special" values in bp and on the stack, but I may be misinterpreting what I'm looking at...
Do you know how to use ndisasm - or some other disassembler - well enough to disassemble io.sys and/or some "known good" code that loads it, to compare with what you're trying to do? I can post what I've got for io.sys... I'm not sure I've got a "real MS" bootsector installed anywhere at present...
If you're getting a "dos error" (as opposed to a hang or reboot), it sounds as if you've gotten io.sys loaded, at least. That's a good start!
Just read your latest post, so I guess you've got it working. Never mind... :)
Best,
Frank
-
And there was much rejoicing! :D
-
thanks all and frank too
ive been looking at gag boot manager that thing is big ..
next ill try figuring out how to load form c drive
-
Glad to hear things worked out! :)
-
Ya, also wanted to mention some fileysystems seem to "belong" together more than others with a MBR / GUID.
FAT-16 and FAT-32 usually comes with a MBR, and FAT-12 usually comes without a MBR, one could stop there but..
for example, using MBR with any filesystem, even FAT-12 is how you could get "superfloppy format or ZIP casette format, if anyone remembers those, very common in studios storing audio onto, as 1.4MB floppys where tad tiny to say the least).
I remember these used MBR's but they had a twist; only the 4th item of the partition table would be used, and the other 3 partitions had to be zeroed out. Also the 4th item had to have special set parameters in it CHS fields.
Anyway what I really wanted to say was;
It seems BIOS has much stopped looking at things like what bus a device uses to determine if its a floppy or HD etc. Instead they look at actual content of the first sector, determining is it a bootsector or a MBR.
If BIOS finds a MBR; it thinks it's a HD, regardless what media it really is on, and you get all advantages it brings.. the fine thing with this I find is.. that INT 13h extensions are enabled so you could use LBA instead, Thats's a big one, really useful!
This way you don't have to use CHS and disk geometrics with all its confusion.
So, putting a MBR on any media any filesystem is great way to make loader able to use simple tiny allaround loaders without special cases and fallbacks.
So for example..if first sector of media .. BIOS goes snooping to find something about it.
- If BIOS finds a MBR with 1 or several items, it would normally think of it as a HD.
- If it finds a MBR with only 4th item filled in, it would think of it as a superfloppy (this I think also has INT13h ext enabled)
- If it finds no MBR only a bootsector, it would think of it as a floppy (normally this wouldn't have INT 13h ext, but I think I've had a buggy BIOS that DID allow, but most shouldn't allow this as should)
Fooling media to be HD by putting a MBR regardless of what filesystem. And have smaller more simple loaders..
I've found this to be reliable.
Hope this helps! :)
EDIT: Some scary details next; The filesystemID of an partition in the MBR does also play a role if INT 13h ext is to be on or off.
This is a terrible way to intermix standards I feel. What does filesystems have to do with how you want to access the media?
But legacy and standards makes terrible mess.. For example 0c means LBAmapped (INT 13h extension enabled) FAT32. While 0b means the same with no INT 13h extension. So the filesystem DOES matter in that sense. This is what I didn't want to talk about details in the first place if not needed. There are ALOT of them..
For a better list check any list over MBR filesystem ID's, for example http://www.win.tue.nl/~aeb/partitions/partition_types-1.html