; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;-----------------------------------------------------------------------------
; DHREADSC contains the following DosHlp routine:
;
;       DHReadSectors           - Read logical sectors from boot drive
;-----------------------------------------------------------------------------

        .286P
        .xlist
        include segments.inc    ;segment declarations
        include basemaca.inc
        include dbprtdef.inc    ;DBPRT macro definition
        include doshlp.inc      ;doshlp macros
        include struc.inc       ;Structure macros
        include bpb.inc         ;BPB structure definition
        .list


PARASHIFT       equ     4

SECTSHIFT       equ     9                        ; ASSUMES 512 byte sectors
SECTSIZE        equ     (1 shl SECTSHIFT)        ; bytes in a paragraph

doubleword      STRUC
        loword  DW      ?
        hiword  DW      ?
doubleword      ENDS

DoubleWord      struc
        lsw     dw      ?
        msw     dw      ?
DoubleWord      ends

EXTRN   _BootErrMem:near
EXTRN   _BootErrRead:near
EXTRN   _TopOfStack:byte

_BSS segment
EXTRN   LastSeg:WORD            ; Upper limit of BootDD-usable memory
EXTRN   BootBPB:BYTE            ; Boot bpb
EXTRN   BootDrive:BYTE          ; Boot drive
EXTRN   CurrentSector:BYTE      ; Sector for read
EXTRN   CurrentHead:BYTE        ; Head..
EXTRN   CurrentTrack:WORD       ; Cylinder
EXTRN   SectorCount:WORD        ; Number of sectors for this operation.
EXTRN   SectorBase:DWORD
_BSS ends

_DATA segment
EXTRN   _SysInitSeg:WORD
EXTRN   _doshlp_status:WORD

BuffAddr    DD  ?               ; address of last buffer read
LastSector  DD  ?               ; last sector read
ScratchBuff DB  512 DUP (?)     ; Scratch Buffer for final sector reads
_DATA  ENDS

_TEXT      SEGMENT

;***    DHReadSectors - DosHlpReadSectors function to read logical sectors
;
;       This routine is called by the kernel to load the base device drivers
;       from the boot drive.  DHReadSectors performs the following:
;
;       1) convert the logical sector number to a physical track, head, sector.
;          (The offset to this partition is obtained from the BIOS BPB and
;          added to the logical sector number prior to conversion.)
;       2) Read using a BIOS int 13H ... incrementing the track, sector, and
;          head numbers appropriately.  Before each read it must be determined
;          that the part of user's buffer (passed in at ES:DI) where we are
;          currently reading does not cross the 64k DMA boundary.  If so, then:
;               - read the sectors before the boundary
;               - read the sector on the boundary into our temporary buffer
;               - copy the temporary buffer into the user's buffer
;               - read the rest of the sectors (except for the last one)
;               - read the last sector into our temporary buffer
;          Also the last sector is read through the temporary buffer so that
;          only the bytes requested (passed in BX) are copied to the user's
;          buffer.
;
;       ENTRY:  REAL MODE
;               DX:AX = starting physical logical sector (partition relative)
;               CX = number of sectors to read (must be at least 1)
;               BX = number of bytes to be read from last sector
;               ES:DI -> user buffer
;
;       EXIT:   Carry set => Hard error
;               Carry clear => successful read
;
;       USES:   Flags
;
        assume  cs:DGROUP,ds:DGROUP,es:nothing,ss:DGROUP

        PUBLIC  DHReadSectors
DHReadSectors   PROC FAR

;       DBPRT   1,4,<DHRS: #Sec=$x FirstSec=$x$x DTA=$x:$x DataSeg=$x\n>,<CX,DX,AX,ES,DI,DS>
        push    ds
        push    es
        pusha
        pushf

        push    cs
        pop     ds                      ; DS = DosHlpData
        ASSUME  DS:DGROUP

        dec     cx                      ; last read is a special case
        push    bx                      ; save final read count
        jcxz    dhrs10

        mov     BuffAddr.loword,di      ; save Buffer Address

        CALL    DiskRD                  ; Read the sectors

        mov     di,BuffAddr.loword      ; setup Write addr for final sector
        mov     ax,BuffAddr.hiword
        mov     es,ax

        mov     ax,[SectorBase].lsw     ; setup sector addr
        mov     dx,[SectorBase].msw     ;

dhrs10:
        push    es                      ; save buffer address
        push    di                      ;
        mov     di, Offset ScratchBuff  ; point to temp buffer
        push    ds                      ;
        pop     es                      ;
        mov     cx,1                    ; read a single sector

        CALL    DiskRD                  ; Read the sector

        mov     si, Offset ScratchBuff  ; reset tmp buffer to scratch buff
        pop     di                      ; restore buffer address
        pop     es                      ;
        pop     cx                      ; restore byte count

        cld
        rep     movsb                   ; last sector

;
; Set CX to indicate success/failure
;
        mov     cx,0                    ; Carry Set => CX = 1 (xor clears C)
        adc     cx,0                    ; Carry Clear => CX = 0
;
; restore registers and exit
;
        popf

        cmp     ch,cl                   ; CX = 1 => Carry Set
                                        ; CX = 0 => Carry Clear
        popa
        pop     es
        ASSUME  ES:NOTHING
        POP     DS
        ASSUME  DS:NOTHING

        ret

DHReadSectors   ENDP


;***    DiskRD - boot strap disk I/O handler
;
;       ENTRY   (CX)    = Number of sectors to read
;               (DX:AX) = First sector to read
;               (ES:DI) = Transfer address
;       EXIT    'C' Clear if successful
;               'C' Set if failure
;       USES    DI, Flags
Procedure DiskRD
    assume ds:DGROUP,es:nothing,ss:DGROUP
;       DBPRT   1,4,<DiskRd: #Sec=$x FirstSec=$x$x DTA=$x:$x DataSeg=$x\n>,<cx,dx,ax,es,di,ds>
        clc
        jcxz    short drdx
        xchg    bx,di                   ; (es:bx) = transfer address
        push    ax                      ; save sector number
        push    dx
        add     ax,cx
        adc     dx,0
        cmp     [BootBPB].BPB_TotalSectors,0
        jnz     short drd10             ; We have small total sectors

;       DBPRT   1,4,<DiskRd: LARGE Total Sectors\n>
        cmp     dx,[BootBPB].BPB_BigTotalSectors.hiword
        ja      short drd20             ; Beyond range of disk
        jb      short drd30
        cmp     ax,[BootBPB].BPB_BigTotalSectors.loword
        ja      short drd20             ; Beyond range of disk
        jmp     short drd30

drd10:
;       DBPRT   1,4,<DiskRd: SMALL TotSec\n>
        or      dx,dx
        jnz     short drd20             ; Beyond range of disk

;       compare against max sectors in partition

        cmp     ax,[BootBPB].BPB_TotalSectors
        jbe     short drd30
drd20:
;       DBPRT   1,4,<DiskRd: Sec out of range\n>
        pop     dx                      ; restore sector number
        pop     ax
        stc
drdx:   ret

;       (CX)    = Number of sectors to read
;       (ES:BX) = Transfer address
;       TOS (dword) = LSN of first sector to read

drd30:  pop     dx                      ; restore sector number
        pop     ax
        push    di
        push    es
        mov     [SectorCount],cx        ; Save count
        mov     [SectorBase].hiword,dx  ; SectorBase is
        mov     [SectorBase].loword,ax

;       (ES:BX)       = Transfer address
;       [BootDrive]   = drive to read from
;       [SectorCount] = # of sectors remaining
;       [SectorBase]  = Current sector origin

drd40:  mov     ax,[SectorBase].loword
        mov     dx,[SectorBase].hiword  ; DX:AX = sector number
;       DBPRT   1,1,<DiskRd: lsec=$x$x csec=$x DTA=$x:$x\n>,<dx,ax,[SectorCount],es,bx>
        call    DoDiv                   ; Calculate head/sector #

;       Is the number of sectors remaining > track size?

        mov     ax,[BootBPB].BPB_SectorsPerTrack
        sub     al,[CurrentSector]      ; (AL) = # of sectors left on track.
        cbw                             ; (AX) = # of sectors on track
        cmp     ax,[SectorCount]        ; (AX) more than # of sectors?
        jb      short drd50
        mov     ax,[SectorCount]        ; (AX) = # of sectors on this track.
drd50:  call    DoRead                  ; Read the sectors.
        jc      short drd90             ; 'C' Set? Return with error.
        cbw                             ; (AX) = # of sectors read.
;       DBPRT   1,2,<DiskRd: Read $x sectors\n>,<ax>
        sub     [SectorCount],ax        ; Update count.
        add     [SectorBase].loword,ax
        adc     [SectorBase].hiword,0

;       DBPRT   1,4,<DiskRd: DTA=$x:$x\n>,<es,bx>
        push    cx                      ; convert AX to paragraph count
        shl     ax,SECTSHIFT-PARASHIFT  ; log2(sector siz)-log2(paragraph siz)
        mov     cx,es                   ; and add to es (load location)
        add     cx,ax
        mov     es,cx                   ; Update destination address.
        mov     BuffAddr.hiword,cx      ; save value
    assume es:nothing
        pop     cx

        cmp     [SectorCount],0         ; Done? (Remaining count=0)
        jnz     drd40           ; No, go back and read more
        clc
drd90:  pop     es
    assume      es:nothing
        pop     di                      ; Restore initial DTA.
        ret
EndProc DiskRD


;***    DoDiv - Calculate head, sector, etc number from sector number.
;
;       ENTRY   (DX:AX) = Sector number to convert
;               (ES:BX) = transfer address
;       EXIT    [CurrentSector] = sector
;               [CurrentHead] = head
;               [CurrentTrack] = track
;       USES    AX, BX, DX, ES, Flags

Procedure DoDiv
    assume ds:DGROUP,es:nothing,ss:DGROUP
;       DBPRT   1,4,<DoDiv: Sec=$x DTA=$x:$x\n>,<ax,es,bx>
        add     ax,[BootBPB].BPB_HiddenSectors.loword ;adjust for partition's base sector
        adc     dx,[BootBPB].BPB_HiddenSectors.hiword
        push    ax
        xchg    dx,ax
        xor     dx,dx                   ; dx:ax = high word of sector
        div     [BootBPB].BPB_SectorsPerTrack ; ax = high quotient, dx = high remainder
        xchg    cx,ax                   ; Save high quotient in CX
        pop     ax                      ; DX:AX = High remainder:low word of sector
        div     [BootBPB].BPB_SectorsPerTrack ; ax = low quotient, dx = low remainder
        mov     [CurrentSector],dl      ; (DX) = Start sector.
        xchg    dx,cx                   ; DX:AX = starting track
        cmp     dx,[BootBPB].BPB_Heads
        jae     short dode              ; Too large
        div     [BootBPB].BPB_Heads
;       DBPRT   1,4,<Head=$b Track=$x\n>,<dx,ax>
        mov     [CurrentHead],dl        ; (DX) = Head,
        mov     [CurrentTrack],ax       ; (AX) = Cylinder

;       DBPRT   1,4,<DoDiv: Normalized DTA=$x:$x\n>,<es,bx>
        ret

dode:   jmp     _BootErrRead
EndProc DoDiv

;***    DoRead - Perform disk read operation
;
;       ENTRY   (AL) = Number of sectors to read
;               [CurrentHead] = head
;               [CurrentTrack] = track
;               [CurrentSector] = sector
;               [BootDrive] = BIOS drive number
;               (ES:BX) = Destination address.
;       USES    CX, DX, Flags

Procedure DoRead
    assume ds:DGROUP,es:nothing,ss:DGROUP
        push    ax
        mov     dx,ax
        mov     cl,SECTSHIFT-PARASHIFT ; log2(sector size) - log2(para size)
        shl     dx,cl           ; convert to paragraph count

;       BUGBUG: what if dx >= 2048 ?????

        mov     cx,es           ; and add to es (load location)
        add     cx,dx
;       dbprt   1,2,<DOREAD: Will read up to $x\n>,<cx>
;       dbprt   1,1,<    BiosCheck: AX=$x BX=$x CX=$x DX=$x\n>,<ax,bx,cx,dx>

        push    dx
        mov     dx, cs
        .if     <[_SysInitSeg] e dx> ; has code been relocated

          ; Code has been relocated, make sure that we are not writing
          ; on top of the discardable code and/or data that shouldn't
          ; be written on

            .if <cx a dx>       ; are we writing in BiosSeg
              push        ax    ; if so, check if we're using the scratch buffer

              mov         ax,es ; get Destination Buffer Segment Address
              .if       <ax ne dx> or   ; are the BiosSeg and DestBuff the same
              .if       <bx ne <offset ScratchBuff>>
                 jmp    _BootErrMem
              .endif

              pop       ax
            .endif
        .else

          ; Code has not been relocated, check to make sure we are writing
          ; beyond our code image

            .if <cx b dx>       ; are we writing in BiosSeg
              push        ax    ; if so, check if we're using the scratch buffer

              mov         ax,es ; get Destination Buffer Segment Address
              .if       <ax ne dx> or   ; are the BiosSeg and DestBuff the same
              .if       <bx ne <offset ScratchBuff>>
                 jmp    _BootErrMem
              .endif

              pop       ax
            .endif

        .endif
        pop   dx

        mov     ah,2                    ; int 13 read operation
        mov     dx,[CurrentTrack]       ; (DX) = Cylinder number
        mov     cl,6
        shl     dh,cl
        or      dh,[CurrentSector]
        mov     cx,dx
        xchg    ch,cl
        inc     cl                      ; Sector # is 1 based.
        mov     dl,[BootDrive]
        mov     dh,[CurrentHead]
;       DBPRT   1,4,<DoRead before: ax=$x cx=$x dx=$x es:bx=$x:$x\n>,<ax,cx,dx,es,bx>
        call    Int13Retries
;       DBPRT   1,4,<DoRead after:  ax=$x cx=$x dx=$x es:bx=$x:$x\n>,<ax,cx,dx,es,bx>
        pop     ax
        ret
EndProc DoRead


;***    Int13Retries - Perform int 13h with retries
;
;       Int13Retries performs int 13h with up to 5 retries.
;
;       ENTRY   Registers set for int 13h
;               (DS) = DGROUP
;       EXIT    As for int 13h except that AX is preserved.
;       USES    Flags

Procedure Int13Retries
    assume ds:DGROUP,es:nothing,ss:DGROUP
        pusha
        push    ds
        push    es
        mov     di,10           ; retry count
inr00:  push    ax
        push    di

        call    Int13Init

;       DBPRT   1,4,<Int13Retries: int13 return status=$x\n>,<ax>
        jnc     short inr80
        xor     ah,ah
        call    Int13Init       ; reset the drive
        pop     di
        pop     ax
        dec     di
        jnz     short inr00
        stc
        jmp     short inrx

inr80:  pop     di
        pop     ax
inrx:

        pop     es
        pop     ds
        popa
        ret
EndProc Int13Retries


;***    Int13Init - Perform call to ROM BIOS int13 entry.
;
;       Issue an Int 13 to the ROM and handle any DMA boundary violations
;       by splitting up the request into parts and using the ScratchBuff
;       to transfer the offending transfer.
;
;       ENTRY   Registers set for Int 13H
;               (DS) = DGROUP

OldAX   dw      0                       ; Saved version of AX.

Int13Frame struc
    Int13BP     dw      ?               ; Value of BP on stack frame
    Int13AX     dw      ?               ; Value of AX on stack frame
    Int13BX     dw      ?               ; Value of BX on stack frame
    Int13CX     dw      ?               ;  ""   "" CX ""   "  "  "
    Int13DX     dw      ?               ;  ""   "" DX ""   "  "  "
Int13Frame ends

Procedure Int13Init
    assume ds:DGROUP,es:nothing,ss:DGROUP
        mov     [OldAX],ax
;       DBPRT   1,4,<Before int13: ax=$x cx=$x dx=$x es:bx=$x:$x\n>,<ax,cx,dx,es,bx>
        int     13h
;       DBPRT   1,4,<After  int13: ax=$x cx=$x dx=$x es:bx=$x:$x\n>,<ax,cx,dx,es,bx>
        jnc     short int10                     ; Just return if no error

;       We had an error.  If it was a DMA error, we perform the special
;       action.  Otherwise, we return to the caller.
;
;       (AH) = Error code returned from ROM
;       We jam interrupts on to allow us to use POPF.

        sti                             ; Force interrupts on.
;       DBPRT   02ch,0c0h,<int13: Error: status = $x\n>,<ax>
        pushf
        cmp     ah,09h                  ; Error returned a DMA violation?
        jz      short int20             ;   Yes, go fix it
        popf
int10:  ret

;       We had a DMA violation, fix it.
;
;       We break the request into (up to) three pieces and move
;       the middle one into ScratchBuff

int20:  pop     ax                      ; Blow away flags.
        mov     ax,[OldAX]
;       DBPRT   0ch,90h,<int13: 64k boundry error\n>

;       (AX)    = Command/#Sectors to transfer
;
;       NOTE:   The order that variables are pushed on the
;               stack is EXTREMLY IMPORTANT - We expect the following:
;
;       TOS:    BP
;               AX
;               BX
;               CX
;               DX
;
;       ALSO NOTE:      We refer directly to the above registers on the
;                       stack via BP and the Int13Frame structure.

        .errnz (size Int13Frame - 10)
        push    dx
        .errnz (Int13DX-8)
        push    cx
        .errnz (Int13CX-6)
        push    bx
        .errnz (Int13BX-4)
        push    ax
        .errnz (Int13AX-2)
        push    bp
        .errnz (Int13BP-0)
        mov     bp,sp                   ; Note comments above about this frame

        call    DMAEGet_PhyAddr         ; (DX) = Physical address of start.
        add     dx,511                  ; We must transfer at least one sector

;       (DX) = Low 16 bits of physical address of transfer (plus 1 sector)
;
;       'C' set if we must transfer immediatly through ScratchBuff

        jc      short int50             ; Transfer 1 sector through
                                        ; ScratchBuff directly
;       Compute the number of sectors we can transfer before the
;       DMA Boundry.
;
;       We divide the physical address by 512 which will give
;       us the number of sectors in the 64K segment up to the request
;       address.  Then subtract that from the number of sectors in
;       64K (128).  The result is the number of sectors we can transfer.

        shr     dh,1                    ; Divide by 512 quickly.
        mov     ah,128                  ; (AH) = # of sectors in 64K
        sub     ah,dh                   ; (AH) = # of sectors left in 64K!
        .errnz  (SECTSHIFT - (8 + 1))

;       (AL) = # of sectors requested.
;       (AH) = # of sectors left in 64K.
;
;       Check to guarantee that this number is less than the number of
;       sectors requested.  If not, something went wrong!

        cmp     ah,al                   ; Can we fit request in?
        jl      short int40             ; No, break it up.
        call    DMADoInt                ; Do the bogus DMA request.
        jmp     short int90

;       We can't fit the request into the entire block.  Perform the
;       operation on the chunk up to the 64K boundry.

int40:  push    ax
        xchg    al,ah                   ; (AL) = # of sectors up to 64K
;       DBPRT   1,1,<BreakUp: reading sectors before 64k boundry\n>
        call    DMADoInt                ; Perform the command
        pop     ax
        jc      short int90             ; Return if error
        sub     byte ptr [bp].Int13AX,ah; Decrement by successful operation
        add     cl,ah                   ; Advance sector number
        add     bh,ah                   ; Advance DMA address by 256*#sectors
        add     bh,ah                   ; Advance again (To get 512 byte sect)
        call    DMAEGet_PhyAddr         ; (DX) = Physical address, 'Z' set if
        jnz     short int50             ; the DMA wrap was exact.
        mov     ax,[bp].Int13AX         ; Set AX from caller
        call    DMADoInt                ; Issue the int 13, and return, we are
        jmp     short int90                     ; done.

;       The next request will wrap the 64K boundary.
;
;       (ES:BX)      = the address of sector to transfer.
;       (CX)         = the correct track/sector info.
;       (BP).Int13AX = correct function code.

int50:  push    bx

;       We are reading a sector.  Read it into ScratchBuff,
;       and transfer into users data space.

        push    bx
        push    es

        push    cs
        pop     es
        assume es:DGROUP
        mov     bx, offset ScratchBuff
        mov     al,1            ; Read only one sector.

;       (AH)    = Function (Read)
;       (AL)    = # of sectors to read (1)
;       (ES:BX) = ScratchBuff
;       (CX)    = Track/sector number
;       (DX)    = Head/drive number

;       DBPRT   1,1,<BreakUp: reading sector at 64k boundry\n>
        call    DMADoInt

        pop     es
    assume es:nothing
        pop     bx              ; (ES:BX) = Original sector
        jc      short int90     ; Error - clean up and return
        push    di
        push    si
        push    ds
        push    cs
        pop     ds
        xchg    di,bx                   ; (ES:DI) = USERS sector buffer address
        mov     si, offset ScratchBuff  ; (DS:SI) = actual buffer
        call    Move
        pop     ds
    assume      ds:DGROUP
        pop     si
        pop     di

;       Portion of int 13 that went through ScratchBuff has
;       been taken care of and we are ready to get the rest
;       of the int 13 (we have done the first two parts of the
;       broken up request and we must finish the last one).

        pop     bx                      ; Get back sector address
        add     bh,2                    ; Advance address sector
        inc     cx                      ; Advance start sector pointer
        mov     al,byte ptr [bp].Int13AX        ; Get # sectors left
        clc
        dec     al                      ; Fix up number of sectors to do
        jz      short int90             ;  All done? Just return
;       DBPRT   1,1,<BreakUp: reading sectors after 64k boundry\n>
        call    DMADoInt

;       All done.  Pop off the frame on the stack and return to the caller.
;
;       (AX) = Final return code
;       'C' Set if error.

int90:  mov     sp,bp
        pop     bp
        .errnz (Int13BP-0)
        pop     bx              ; discard caller's AX, use error code instead
        .errnz (Int13AX-2)
        pop     bx
        .errnz (Int13BX-4)
        pop     cx
        .errnz (Int13CX-6)
        pop     dx
        .errnz (Int13DX-8)
        .errnz (size Int13Frame - 10)
;       DBPRT   1,1,<BreakUp: finished\n>
        ret
EndProc Int13Init


;***    DMADoInt - Do DMA ROM Disk request.
;
;       This routine will read a sector off the disk.
;
;       ENTRY   (SS:BP) = int13Frame pointer
;               (AH)    = # of sectors before boundary
;               (AL)    = # of sectors to read/write/...
;               (CH)    = Cylinder number
;               (CL)    = Sector number within cylinder
;                         NB:   Top two bits of (CL) are the high
;                               two bits of the cylinder
;               (ES:BX) = DTA (Disk Transfer Address)
;       EXIT    'C' Set if error (AH) = Error code
;               'C' Clear if no error.
;
;       NOTE:   The user flags are pushed from inside the Int13Frame
;               structure directly onto the stack to simulate an IRET frame.

Procedure DMADoInt
    assume ds:DGROUP,es:nothing,ss:DGROUP
        or      al,al
        jz      short ddix
        mov     dx,[bp].Int13DX
        mov     ah,byte ptr [bp].Int13AX+1      ; (AH) = Command
;       DBPRT   1,4,<DMADoInt: Before: ax=$x cx=$x dx=$x es:bx=$x:$x\n>,<ax,cx,dx,es,bx>
        int     13h
;       DBPRT   1,4,<DMADoInt: After : ax=$x cx=$x dx=$x es:bx=$x:$x\n>,<ax,cx,dx,es,bx>
ddix:   ret
EndProc DMADoInt


;***    DMAEGet_PhyAddr - Return the physical address of the destination addr
;
;       ENTRY   (ES:BX) = Address of an int 13 Request packet
;       EXIT    (DX)    = Low 16 bits of physical address
;               (Flags) = Set as appropriate -
;                         'C' set if request address wrapped 64K bound
;                         'Z' set if wrap was an even wrap.

Procedure DMAEGet_PhyAddr
    assume ds:DGROUP,es:nothing,ss:DGROUP
        mov     dx,es
        shl     dx,PARASHIFT            ; (DX) = Phys address of segment
        add     dx,bx                   ; (DX) = Phys address of buffer
;       DBPRT   1,1,<DmaGetPhyAddr: es:bx=$x:$x dx=$x\n>,<es,bx,dx>
        ret
EndProc DMAEGet_PhyAddr

;***    zap the magic word in swapper.dat so we only unhybernate once
;
;       ENTRY   (ES:DI) = Destination buffer
;               (DS:SI) = Source buffer
;
Procedure _hyberZapHdr
    assume ds:nothing,es:nothing,ss:DGROUP
    ArgVar	bufptr,Dword

	EnterProc
	pusha
;	DBPRT	1,1,<zapHdr: bfr=$x:$x\n>,<bufptr.hiword,bufptr.loword>
;	xor	ax, ax
;	xor	dx, dx
;	call	DoDiv
	xor	ax, ax
	xor	bx, bx
	xor	cx, cx
	mov	al, [BootDrive]
	mov	bl, [CurrentSector]
	mov	cl, [CurrentHead]
;	DBPRT   1,1,<zapHdr: drv=$x csec=$x ctrk=$x chead=$x\n>,<ax,bx,[CurrentTrack],cx>

	mov	bx, [bufptr].hiword
	mov	es, bx
	mov	bx, [bufptr].loword
	mov	al, 1			; one sector
        mov     ah, 3                   ; int 13 write operation
        mov     dx, [CurrentTrack]      ; (DX) = Cylinder number
        mov     cl, 6
        shl     dh, cl
        or      dh, [CurrentSector]
        mov     cx, dx
        xchg    ch, cl
        inc     cl                      ; Sector # is 1 based.
        mov     dl,[BootDrive]
        mov     dh,[CurrentHead]
;	DBPRT   1,4,<zaphdr before: ax=$x cx=$x dx=$x es:bx=$x:$x\n>,<ax,cx,dx,es,bx>
        call    Int13Retries
;       DBPRT   1,4,<zaphdr after:  ax=$x cx=$x dx=$x es:bx=$x:$x\n>,<ax,cx,dx,es,bx>
	popa
	LeaveProc
        ret
EndProc _hyberZapHdr

        .386p

;***    Move a block of memory
;
;       ENTRY   (ES:DI) = Destination buffer
;               (DS:SI) = Source buffer
;
Procedure Move
    assume ds:nothing,es:nothing,ss:DGROUP
        push    si
        push    di
        push    cx
        mov     cx,SECTSIZE/4
        cld
    rep movsd
        pop     cx
        pop     di
        pop     si
        ret
EndProc Move

_TEXT           ENDS
        END
