1

I am reading sectors from my extended drive in Real Mode using the interrupt 0x13 with the function of extended drives 0x42.

I define DAP to be 16 bytes in the following structure:

DAP:
    db  0x10        ; size of DAP
    db  0           ; Reserved zero
    dw  0x0001      ; Number of sectors to read
    dd  0x00000200  ; Memory Location to load the sector (s)
    dq  0           ; Start of the sectors to be read

The DAP segment is of 8-bytes length as you could notice. During seeking for my sector (looping over sectors), I increment the segment and compare it to the real size of my drive. The wrong code that I am using to increment is limited to 16-bit mode:

mov     ax, [DAP+0x08]
inc     ax
mov     [DAP+0x08], ax

I don't want to use several general purpose registers in a complicated addressing mode to achieve my purpose, I guess you have some simple and efficient way.

  • Segment isn't an 8 byte (64-bit value). What you have listed as an 8-byte value is the LBA (Logical block address). The segment. Is actually the second 2 bytes of what you have listed as `offset`. The four byte value you have listed as `offset` is actually a real mode segment:offset pair. – Michael Petch May 07 '17 at 14:25
  • @MichaelPetch, you are right about my code comments. This was due to a wrong of copying a part of the code from some where. Anyway, I modified the code comments. – محمد جعفر نعمة May 07 '17 at 14:36
  • The 4 byte value 0x200 is actually the same as 0x00000200 which translates to a segment offset pair of 0x0000:0x0200 . I hope that isn't where in memory you started to read sectors because that happens to be on top of the interrupt vector table in lower memory that runs from 0x0000 to 0x3fff. After that is the BIOS Data Area from 0x400 to 0x4ff. On ancient hardware there are reserved bytes starting at 0x500. I'd recommend starting to read 0x0000:0x0600 – Michael Petch May 07 '17 at 14:38
  • Thank you again. I indeed add a segment (FS) 0x7c0 which means that I am loading into 0x7e00 which should be free. I am not using the higher two bytes. – محمد جعفر نعمة May 07 '17 at 14:41
  • @MichaelPetch Yes you are right :/ I don't know why he deleted it. – محمد جعفر نعمة May 07 '17 at 14:43
  • Are you using _NASM_? – Michael Petch May 07 '17 at 14:56
  • @MichaelPetch, yes I am using NASM. I added it now to tags. – محمد جعفر نعمة May 07 '17 at 15:02
  • If you want the extended disk read to read into physical memory at 0x7e00 for example you would either have to use `dd 0x00007e00` as a start or use `dd 0x07c00200`. – Michael Petch May 07 '17 at 15:07
  • Yes dear @MichaelPetch. But I already have a segment *FS* pointing to 0x7c00 so I am using it. Is there any difference between using FS:0x0200 and 0x00007e00? – محمد جعفر نعمة May 07 '17 at 15:09
  • The extended disk reads do not use the segment register contents to determine where the disk read will load into memory. The memory address to read into has to be in the DAP as a fully qualified segment:offset pair. As it stands that DAP you created is overwriting the interrupt vector table at 0x0000:0200 – Michael Petch May 07 '17 at 15:13
  • 1
    I would break up `dd 0x00000200` into two separate 16-bit words for readability. And have it as `dw 0x0000 ; offset` followed by `dw 0x07e0 ; segment` That represents 0x07e0:0x0000 which is physical address (0x07e0<<4)+0x0000=0x7e00 – Michael Petch May 07 '17 at 15:31
  • Thank you dear @MichaelPetch. Always teaching me and highlighting even my small faults. – محمد جعفر نعمة May 07 '17 at 15:34
  • 2
    Reading into the wrong memory address isn't a small fault. It is a bug. – Michael Petch May 07 '17 at 15:37

1 Answers1

4

To increment a 64-bit QWORD, you can use the add and adc instructions:

ADD WORD [DAP+ 8], 1
ADC WORD [DAP+10], 0
ADC WORD [DAP+12], 0
ADC WORD [DAP+14], 0

Or, if you aren't targeting an 8088, 8086, or 80286, you can also use a 32-bit add/adc:

ADD DWORD [DAP+ 8], 1
ADC DWORD [DAP+12], 0

Note that you can't use INC WORD [DAP+ 8] instead of ADD WORD [DAP+ 8], 1 because the former doesn't set the carry flag.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • Thank you @FUZ. I am using NASM and they are not working for me for now, I will be back. – محمد جعفر نعمة May 07 '17 at 15:04
  • 3
    @fuz: Or you could go the direct route and abuse the FPU if you've got one (`FILD qword [DAP+8] / FLD1 / FADDP / FISTP qword [DAP+8]`). Admittedly terrible but the x87 has sufficient precision and correct overflow semantics to do the right thing. – doynax May 07 '17 at 15:16
  • @doynax Indeed, that would work, though, it might perform worse. – fuz May 07 '17 at 15:19
  • The performance would be *much* worse if you did this using the x87 FPU. Precision isn't important here, these are integers. It would also make the code less readable. Use the standard idiom for large-integer arithmetic: adding with carry. – Cody Gray - on strike May 07 '17 at 15:42
  • I think what he is saying about precision is that with the floating point you can represent all the values between 0 and (2^64)-1 precisely since internally the FPU is using 80-bit floating point representation where 64 of those bits are for the significand – Michael Petch May 07 '17 at 16:04
  • If space constrained (especially if in a bootloader) I'd choose whatever mechanism yielded smaller code not necessarily which ran faster. My big complaint with the FPU isn't with performance for something like this but as doynax points out the caveat "abuse the FPU if you've got one". If you are targeting for platforms and old processors that may not have an FPU that is an issue in the same way using 32-bit instruction prefixes would tie you to 386+. – Michael Petch May 07 '17 at 16:15
  • If targeting a processor that is pre-386 with an FPU then doynax's method would come out 8 bytes shorter than the 4 add/adc. I say it really depends on what processor you are targeting and if you need smaller code. I personally wouldn't dismiss doynax's suggestion. It may actually have merit depending on requirements. – Michael Petch May 07 '17 at 16:27