How do I load my sector with if it's more than 512 bytes?

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.
stevewoods1986
Member
Member
Posts: 80
Joined: Wed Aug 09, 2017 7:37 am

How do I load my sector with if it's more than 512 bytes?

Post by stevewoods1986 »

Hello.

How do I load my sector with INT 13h if there is more than 512 bytes? A sector is 512 bytes. Also, could I have some resources for FAT12 please? I've checked out the Wiki. I also checked out things from Microsoft Technet and Wikipedia.

Any help would be appreciated.

Thanks
Steve.
User avatar
zaval
Member
Member
Posts: 659
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: How do I load my sector with if it's more than 512 bytes

Post by zaval »

stevewoods1986 wrote:Hello.

How do I load my sector with INT 13h if there is more than 512 bytes? A sector is 512 bytes. Also, could I have some resources for FAT12 please? I've checked out the Wiki. I also checked out things from Microsoft Technet and Wikipedia.

Any help would be appreciated.

Thanks
Steve.
You could if you wanted. :) The FAT specification is available.
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
stevewoods1986
Member
Member
Posts: 80
Joined: Wed Aug 09, 2017 7:37 am

Re: How do I load my sector with if it's more than 512 bytes

Post by stevewoods1986 »

zaval wrote:
stevewoods1986 wrote:Hello.

How do I load my sector with INT 13h if there is more than 512 bytes? A sector is 512 bytes. Also, could I have some resources for FAT12 please? I've checked out the Wiki. I also checked out things from Microsoft Technet and Wikipedia.

Any help would be appreciated.

Thanks
Steve.
You could if you wanted. :) The FAT specification is available.
I might look at that. How would I load my sector if there is more than 512 bytes?
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: How do I load my sector with if it's more than 512 bytes

Post by Octacone »

OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
stevewoods1986
Member
Member
Posts: 80
Joined: Wed Aug 09, 2017 7:37 am

Re: How do I load my sector with if it's more than 512 bytes

Post by stevewoods1986 »

Octacone wrote:"al" = number of sectors to read.
Quite simple.

For more info see: http://www.ctyme.com/intr/rb-0607.htm
This page: http://wiki.osdev.org/FAT
This page:http://www.maverick-os.dk/FileSystemFor ... ystem.html
This thread: http://forum.osdev.org/viewtopic.php?t=21155
I tried that. Doesn't work. I tried making a file that does lots of operands and including it. I changed al in my bootloader. It just stops my kernel from working. By the way, how would I load my kernel by filename?
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: How do I load my sector with if it's more than 512 bytes

Post by neon »

Hello,

What do you mean by "making a file that does lots of operands and including it?" Nothing about int 13h involves files. If you are going to use fat12, write a "Read Sector" function that reads only 1 sector. Don't worry about reading "multiple" sectors - with any of the fat filesystems you'll be reading 1 sector at a time.

How are you currently calling this interrupt? What is the expected behavior and what is currently happening? Have you tried just loading 1 sector to some location and verifying that it gets loaded? How have you verified that the function works/does not work? It is helpful to use a hex editor with bochsdbg to compare and test.

Don't worry about file systems until you are able to read sectors. (To answer the question however, you locate the file from the root directory structure which gives you the starting cluster. The fat gives you the next chain of clusters until eof. All of this is in the fat32 whitepaper linked earlier.)
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: How do I load my sector with if it's more than 512 bytes

Post by onlyonemac »

Sectors are always 512 bytes. To load more bytes, you load multiple sectors. So to read 1024 bytes, you need to read two sectors. The simplest way, I find, to do this is to loop your sector-reading function, and for each sector you increment the start sector value (carrying over to the side and/or cylinder/track values if required) and add 512 to the destination address (make sure that you've got enough space to read however much data you're trying to read).

Mine looks like this:

Code: Select all

;read sectors from disk
;ax = start sector, bx = end sector (exclusive), es = destination segment
;updates es to end of data
readsectors:
push cx
push ax
read_loop:
call readsector
mov cx, es
add cx, #0x20
mov es, cx
inc ax
cmp ax, bx
jb read_loop
pop ax
pop cx
ret

;read a sector from disk
;ax = sector, es = destination segment
readsector:
push dx
push cx
push bx
push ax
push ax
mov cl, #36
div cl
mov bl, al
pop ax
mov cl, #18
div cl
and al, #0x01
add ah, #0x01
;bl = cylinder/track, al = head, ah = sector
mov ch, bl
mov cl, ah
mov dh, al
mov dl, #0
mov ax, #0x0201
mov bx, #0x0000
int 0x13
pop ax
pop bx
pop cx
pop dx
ret
I seem to remember that cylinders/tracks are numbered from 1, not 0. EDIT: Sectors are numbered from 1, cylinders/tracks and heads are numbered from 0.
Last edited by onlyonemac on Sun Aug 13, 2017 2:17 pm, edited 1 time in total.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
LtG
Member
Member
Posts: 384
Joined: Thu Aug 13, 2015 4:57 pm

Re: How do I load my sector with if it's more than 512 bytes

Post by LtG »

onlyonemac wrote:Sectors are always 512 bytes.
Except when they aren't. Not really important within the context of this thread, but it would be good to not claim that they always are..

As for the OP, seriously, if you know how to read one sector and you can't figure out on your own how to read two or more sectors, then osdev might not be for you... Can't really think of a simpler programming problem to solve than creating a function and calling it twice..
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: How do I load my sector with if it's more than 512 bytes

Post by onlyonemac »

LtG wrote:
onlyonemac wrote:Sectors are always 512 bytes.
Except when they aren't. Not really important within the context of this thread, but it would be good to not claim that they always are..
AFAIK logical sectors are always 512 bytes. Physical sectors can, of course, be any size, but that's a hardware technicality. For standard storage device interfaces/protocols, a "sector" is always 512 bytes, even if you use LBA.
LtG wrote:Can't really think of a simpler programming problem to solve than creating a function and calling it twice..
It's a bit more complicated than that. You also need to change the destination address, and handle crossing over from one side of the disk to the other or moving to the next track. And of course if you're using the BIOS interrupt then you'll probably overlook the idea of even using a subroutine/loop and instead get confused about the built-in ability to read multiple sectors and the various BIOS bugs that affect this function (I believe that this is what happened here).
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
stevewoods1986
Member
Member
Posts: 80
Joined: Wed Aug 09, 2017 7:37 am

Re: How do I load my sector with if it's more than 512 bytes

Post by stevewoods1986 »

onlyonemac wrote:
LtG wrote:
onlyonemac wrote:Sectors are always 512 bytes.
Except when they aren't. Not really important within the context of this thread, but it would be good to not claim that they always are..
AFAIK logical sectors are always 512 bytes. Physical sectors can, of course, be any size, but that's a hardware technicality. For standard storage device interfaces/protocols, a "sector" is always 512 bytes, even if you use LBA.
LtG wrote:Can't really think of a simpler programming problem to solve than creating a function and calling it twice..
It's a bit more complicated than that. You also need to change the destination address, and handle crossing over from one side of the disk to the other or moving to the next track. And of course if you're using the BIOS interrupt then you'll probably overlook the idea of even using a subroutine/loop and instead get confused about the built-in ability to read multiple sectors and the various BIOS bugs that affect this function (I believe that this is what happened here).
So should I do?

Code: Select all

mov ah, 2
mov al, 1
mov ch, 0
mov cl, 2
mov dh, 0
mov dl, 0
mov bx, 0x7c00
mov es, bx
mov bx, 0x00
int 13h

mov ah, 2
mov al, 1
mov ch, 0
mov cl, 3
mov dh, 0
mov dl, 0
mov bx, 0x7c00
mov es, bx
mov bx, 0x00
int 13h

jmp 0x7c00:0x00
What do I do?
neon wrote:Hello,

What do you mean by "making a file that does lots of operands and including it?" Nothing about int 13h involves files. If you are going to use fat12, write a "Read Sector" function that reads only 1 sector. Don't worry about reading "multiple" sectors - with any of the fat filesystems you'll be reading 1 sector at a time.

How are you currently calling this interrupt? What is the expected behavior and what is currently happening? Have you tried just loading 1 sector to some location and verifying that it gets loaded? How have you verified that the function works/does not work? It is helpful to use a hex editor with bochsdbg to compare and test.

Don't worry about file systems until you are able to read sectors. (To answer the question however, you locate the file from the root directory structure which gives you the starting cluster. The fat gives you the next chain of clusters until eof. All of this is in the fat32 whitepaper linked earlier.)
To add bytes. Make a file with lots of moving that is over 512 bytes and see if my other code works.

Code: Select all

%include "junkymoving.asm"

more code here...
doesn't run :( thats what happens when its more than 512 bytes
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: How do I load my sector with if it's more than 512 bytes

Post by onlyonemac »

stevewoods1986 wrote:So should I do?

Code: Select all

mov ah, 2
mov al, 1
mov ch, 0
mov cl, 2
mov dh, 0
mov dl, 0
mov bx, 0x7c00
mov es, bx
mov bx, 0x00
int 13h

mov ah, 2
mov al, 1
mov ch, 0
mov cl, 3
mov dh, 0
mov dl, 0
mov bx, 0x7c00
mov es, bx
mov bx, 0x00
int 13h

jmp 0x7c00:0x00
What do I do?
I haven't tried your code but at a glance it seems to me that it will write the second sector to the same place that it wrote the first sector. Your second

Code: Select all

mov bx, 0x7c00
should probably be

Code: Select all

mov bx, 0x7e00
otherwise you'll overwrite (in memory) the first sector with the second sector.

Also why are you writing to 0x7c00:0x0000, IIRC that will overwrite your bootsector?
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
stevewoods1986
Member
Member
Posts: 80
Joined: Wed Aug 09, 2017 7:37 am

Re: How do I load my sector with if it's more than 512 bytes

Post by stevewoods1986 »

onlyonemac wrote:
stevewoods1986 wrote:So should I do?

Code: Select all

mov ah, 2
mov al, 1
mov ch, 0
mov cl, 2
mov dh, 0
mov dl, 0
mov bx, 0x7c00
mov es, bx
mov bx, 0x00
int 13h

mov ah, 2
mov al, 1
mov ch, 0
mov cl, 3
mov dh, 0
mov dl, 0
mov bx, 0x7c00
mov es, bx
mov bx, 0x00
int 13h

jmp 0x7c00:0x00
What do I do?
I haven't tried your code but at a glance it seems to me that it will write the second sector to the same place that it wrote the first sector. Your second

Code: Select all

mov bx, 0x7c00
should probably be

Code: Select all

mov bx, 0x7e00
otherwise you'll overwrite (in memory) the first sector with the second sector.

Also why are you writing to 0x7c00:0x0000, IIRC that will overwrite your bootsector?
It works. That's why. No problems. I don't think I need 0x7e00 unless I have stack problems... wait. you mean. oh
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: How do I load my sector with if it's more than 512 bytes

Post by neon »

Hello,

The provided code loads to 0x7c000 and 0x7e000 not 0x7c00. However, I suspect this might have not been done intentionally; it might be a good idea for the original poster to review segmentation.

- How are you copying the boot record to the disk image?
- What happens if you load it to 0x7e0:0 and 0x800:0? You should not need a jump since the sectors would be loaded in consecutive memory.
- Where is the stack?
Last edited by neon on Sun Aug 13, 2017 5:25 pm, edited 1 time in total.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: How do I load my sector with if it's more than 512 bytes

Post by Schol-R-LEA »

@onlyonemac: I was confused too, until I noticed that the code is setting ES, via BX, and then clearing BX. IOW, it's not not writing to 0000:7c00 (computed absolute address 7c00 hex, or 31,774 decimal), where the BIOS loads the boot sector) but to 7c00:0000 (computed absolute address 7c000, or 507,904 decimal) - which is a much higher, being about 5/6ths of the way towards the top of base RAM memory according to the Memory Map.

You're point about it overwriting the first loaded sector is correct. However, in this instance, the OP would probably use something closer to this, assuming that ES and BX are not clobbered by the BIOS:

Code: Select all

add bx, 0x10    ; advance the load location by 512 bytes
int 0x13
@stevewoods1986: In my own VERBUM boot sector demonstrator, I use an approach similar to the one onlyonemac used (as shown above), but I also used some NASM assembler macros to ease the process of calling some routines (though not the one for reading from disk), EQUates to give names to important constants, and memory variables to hold the values rather than hard-coding them.

equates:

Code: Select all

;;constants
;

%define boot_base   0x0000      ; the segment:offset pair for the
%define boot_offset 0x7C00	;  boot code entrypoint

stage2_base   	equ 0x1000      ; the segment:offset to load 
stage2_offset   equ 0x0000	; the second stage into
stack_seg  	equ 0x9000
stack_top	equ 0xFFFC

VBIOS	        equ 0x10        ; BIOS interrupt vector for video services
GOTO_XY         equ 0x02        ; VBIOS routine - go to the given x, y coordinates
block_write     equ 0x09        ; VBIOS routine - write a fixed number of times to the screen
ttype	        equ 0x0E        ; VBIOS routine - print character, teletype mode

DBIOS	        equ 0x13        ; BIOS interrupt vector for disk services
disk_reset	equ 0x00        ; disk reset service
disk_read	equ 0x02        ; disk read service

;  BIOS error codes
reset_failure   equ 0x01        ; error code returned on disk reset failure
read_failure    equ 0x02        ; error code returned on disk read failure

; operational constants 
tries           equ 0x03        ; number of times to attempt to access the FDD
macros:

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; macros
;
%define zero(x) xor x, x

%macro write 1
   mov si, %1
   call printstr
%endmacro
data section (which I put below the code):

Code: Select all

[section data]
loading         db 'Loading stage two... ', NULL
done            db 'done.', CR, LF, NULL
snd_stage	db 'Second stage loaded, proceeding to switch context.', CR, LF, NULL
returned	db 'Control returned to first stage, ', NULL
reset_failed	db 'Could not reset drive,', NULL
read_failed	db 'Could not read second stage, ', NULL
exit            db ' system halted.', NULL

bootdrv	        resb 1      ; byte reserved for boot drive ID number

; DBIOS arguments, values given are defaults
cyl             db 0        ; cylinder to read from
head	        db 0        ; head to read from
startsector	db 2        ; sector to start reading at
numsectors	db 1        ; number of sectors to read

disk reset and read functions

Code: Select all

; reset_disk
reset_disk:
  mov dl, [bootdrv]
  mov ah, disk_reset
  int DBIOS
  ret

; read_disk
read_disk:
  mov cx, tries        ; set count of attempts for disk reads
  .try_read:
    push cx
    mov cx, tries      ; set count of attempts to reset disk
    .try_reset:
      call reset_disk
      jnc short .read
      loop .try_reset       ; if the reset fails, try up to three times
      mov ax, reset_failure ; if all three fail, set an error code and return
      pop cx                ; make sure that the stack is correctly aligned
      jmp short .end_fail
  .read:
    mov ax, stage2_base
    mov es, ax
    mov dl, [bootdrv] 
    mov ch, [cyl]           ; cylinder
    mov dh, [head]          ; head
    mov cl, [startsector]   ; first sector 
    mov al, [numsectors]    ; number of sectors to load   
    mov ah, disk_read
    mov bx, stage2_offset
    int DBIOS
    jnc short .end_success
    pop cx
    loop .try_read
  mov ax, read_failure ; if attempts to read the disk fail, report error code
  jmp short .end_fail
.end_success:
  pop cx               ; make sure that the stack is correctly aligned
  zero(ax)
.end_fail:
  ret
The part of the actual loader that calls this is:

Code: Select all

  mov [bootdrv], dl   ; save boot drive info for later use

; read in the data from disk and load it to ES:BX (already initialized)
  write loading
  call read_disk
  cmp ax, reset_failure
  jne good_reset
  write reset_failed
  jmp short shutdown
The point is that just because you are using assembly doesn't mean you have to throw good coding practices out the window. In this case, I probably should re-write this to use parameters for those arguments, as onlyonemac did, rather than hard-coding in the addresses, but one thing at a time.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
stevewoods1986
Member
Member
Posts: 80
Joined: Wed Aug 09, 2017 7:37 am

Re: How do I load my sector with if it's more than 512 bytes

Post by stevewoods1986 »

neon wrote:Hello,

The provided code loads to 0x7c000 and 0x7e000 not 0x7c00. However, I suspect this might have not been done intentionally; it might be a good idea for the original poster to review segmentation.

- How are you copying the boot record to the disk image?
- What happens if you load it to 0x7e0:0 and 0x800:0? You should not need a jump since the sectors would be loaded in consecutive memory.
- Where is the stack?
What? So it's not 0x7c00? I don't need to jump to DS:BX?

I don't know where the stack is... Is it at 0x7c00?
Do I have to do mov sp, 0x7c00?

Am I an idiot?
Post Reply