Retro video games delivered to your door every month!
Click above to get retro games delivered to your door ever month!
X-Hacker.org- Peter Norton Programmer's Guide - Norton Guide http://www.X-Hacker.org [<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]

  In the last chapter, where we covered the ROM BIOS video services, we
  were able to recommend that you make direct use of the ROM BIOS services
  when DOS or your programming language does not provide the support you
  need. But in the case of the ROM BIOS disk services, things are different.

  For the disk operations that a program would normally want performed, the
  manipulation and supervision of disk input/output should be left to DOS
  and performed either through the conventional file services of a
  programming language or through the DOS services. (See Chapters 14
  through 18.) There are several reasons for this. The main reason is that
  it is far easier to let DOS do the work. The DOS facilities take care of
  all fundamental disk operations, including formatting and labeling disks,
  cataloging files, and basic read and write operations. Most of the time it
  isn't necessary to go any deeper into the system software. However, there
  are times when you may want to work with disk data in an absolute and
  precise way, usually for copy protection. This is when you should use the
  ROM BIOS services.

  For our example, we'll use C to call a couple of subroutines that use ROM
  BIOS functions 02H and 03H to read and write absolute disk sectors. We
  start by defining how we want the interface to look from the C side, which
  the following program illustrates. If you are not familiar with C and
  don't want to decipher this routine, you can pass it by and still get the
  full benefit by studying the assembly-language interface example that
  follows it.

  main()
  {
          unsigned char Buffer[512];      /* a 512-byte buffer for reading */
                                          /*  or writing one sector */

          int     Drive;
          int     C,H,R;                  /* address mark parameters */
          int     StatusCode;             /* status value returned by BIOS */

          StatusCode = ReadSector( Drive, C, H, R, (char far *)Buffer );
          StatusCode = WriteSector( Drive, C, H, R, (char far *)Buffer );
  }

  This C fragment shows how you would call the ROM BIOS read and write
  services from a high-level language. The functions ReadSector() and
  WriteSector() are two assembly-language routines that use interrupt 13H to
  interface with the ROM BIOS disk services. The parameters are familiar: C,
  H, and R are the cylinder, head, and sector numbers we described earlier.
  The C compiler passes the buffer address as a segment and offset because
  of the explicit type cast (char far *).

  The form of the assembly-language interface should be familiar if you read
  the general remarks in Chapter 8 on page 161 or studied the example in
  Chapter 9 on page 194. The assembly-language routines themselves copy the
  parameters from the stack into the registers. The trick is in how the
  cylinder number is processed: The 2 high-order bits of the 10-bit cylinder
  number are combined with the 6-bit sector number in CL.

  _TEXT           SEGMENT byte public 'CODE'
                  ASSUME  cs:_TEXT

                  PUBLIC  _ReadSector
  _ReadSector     PROC    near            ; routine to read one sector

                  push    bp
                  mov     bp,sp           ; address the stack through BP

                  mov     ah,2            ; AH = ROM BIOS service number 02h
                  call    DiskService

                  pop     bp              ; restore previous BP
                  ret

  _ReadSector     ENDP

                  PUBLIC  _WriteSector
  _WriteSector    PROC    near            ; routine to write one sector

                  push    bp
                  mov     bp,sp

                  mov     ah,3            ; AH = ROM BIOS service number 03h
                  call    DiskService

                  pop     bp
                  ret

  _WriteSector    ENDP


  DiskService     PROC    near            ; Call with AH = ROM BIOS service number

                  push    ax              ; save service number on stack
                  mov     dl,[bp+4]       ; DL = drive ID
                  mov     ax,[bp+6]       ; AX = cylinder number
                  mov     dh,[bp+8]       ; DH = head number
                  mov     cl,[bp+10]      ; CL = sector number
                  and     cl,00111111b    ; limit sector number to 6 bits
                  les     bx,[bp+12]      ; ES:BX -> buffer

                  ror     ah,1            ; move bits 8 and 9
                  ror     ah,1            ;  of cylinder number
                                          ;  to bits 6 and 7 of AH
                  and     ah,11000000b
                  mov     ch,al           ; CH = bits 0-7 of cylinder number
                  or      cl,ah           ; copy bits 8 and 9
                                          ;  of cylinder number
                                          ;  to bits 6 and 7 of CL

                  pop     ax              ; AH = ROM BIOS service number
                  mov     al,1            ; AL = 1 (# of sectors to read/write)
                  int     13h             ; call ROM BIOS service

                  mov     al,ah           ; leave return status
                  xor     ah,ah           ; # in AX

                  ret

  DiskService     ENDP

  _TEXT           ENDS

  Note how the code that copies the parameters from the stack to the
  registers is consolidated in a subroutine, DiskService. When you work with
  the ROM BIOS disk services, you'll find that you can often use subroutines
  similar to DiskService because most of the ROM BIOS disk services use
  similar parameter register assignments.

Online resources provided by: http://www.X-Hacker.org --- NG 2 HTML conversion by Dave Pearson