1092 lines
31 KiB
NASM
1092 lines
31 KiB
NASM
|
|
DOSSEG
|
|
.MODEL LARGE
|
|
|
|
include disk.inc
|
|
include partit.inc
|
|
|
|
.DATA
|
|
extrn _x86BootCode:far
|
|
|
|
.DATA?
|
|
extrn PartitionList:dword
|
|
extrn PartitionListCount:word
|
|
|
|
.CODE
|
|
ASSUME ds:NOTHING
|
|
|
|
extrn _malloc:far
|
|
extrn _free:far
|
|
extrn _qsort:far
|
|
extrn _ReadDisk:far
|
|
extrn _WriteDisk:far
|
|
extrn _GetDiskInfoByHandle:far
|
|
|
|
.386
|
|
|
|
;++
|
|
;
|
|
; INT
|
|
; _far
|
|
; MakePartitionAtStartOfDisk(
|
|
; IN HDISK DiskHandle,
|
|
; OUT FPVOID SectorBuffer,
|
|
; IN ULONG MinimumSectorCount,
|
|
; IN UINT PartitionClass,
|
|
; IN BYTE SystemId OPTIONAL
|
|
; );
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine makes a new primary partition of at least
|
|
; a given number of sectors. The partition may be larger
|
|
; to keep it aligned on the proper cyl/track boundary.
|
|
;
|
|
; Only int13 disk units are supported.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; DiskHandle - supplies a disk handle as returned by OpenDisk().
|
|
;
|
|
; SectorBuffer - supplies a pointer to a buffer suitable for use
|
|
; for i/o of a single sector. This buffer must not
|
|
; cross a DMA boundary, but the caller is responsible
|
|
; for ensuring this.
|
|
;
|
|
; MinimumSectorCount - supplies the minimum number of sectors
|
|
; that the partition should contain.
|
|
;
|
|
; PartitionClass - supplies a value indicating what class of system id
|
|
; should be used for the partition.
|
|
;
|
|
; PARTCLASS_FAT - creates a type 1, 4, or 6, or e partition
|
|
; depending on size and availability of xint13
|
|
; services for the drive.
|
|
;
|
|
; PARTCLASS_FAT32 - creates a type b or c partition depending
|
|
; on availability of xint13 services for the drive.
|
|
;
|
|
; PARTCLASS_NTFS - creates a type 7 partition.
|
|
;
|
|
; PARTCLASS_OTHER - create a partition whose type is given by
|
|
; the SystemId parameter.
|
|
;
|
|
; SystemId - if PartitionClass is PARTCLASS_OTHER, supplies the
|
|
; system id for the partition. Ignored otherwise.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; Partition id of newly created partition, or -1 if failure.
|
|
;
|
|
;--
|
|
|
|
DiskHandle equ dword ptr [bp+6]
|
|
DiskHandlel equ word ptr [bp+6]
|
|
DiskHandleh equ word ptr [bp+8]
|
|
SectorBuffer equ dword ptr [bp+10]
|
|
SectorBufferl equ word ptr [bp+10]
|
|
SectorBufferh equ word ptr [bp+12]
|
|
MinimumSectorCount equ dword ptr [bp+14]
|
|
MinimumSectorCountl equ word ptr [bp+14]
|
|
MinimumSectorCounth equ word ptr [bp+16]
|
|
PartitionClass equ word ptr [bp+18]
|
|
SystemId equ byte ptr [bp+20]
|
|
|
|
ExtSecCnth equ word ptr [bp-2]
|
|
ExtSecCntl equ word ptr [bp-4]
|
|
ExtSecCnt equ dword ptr [bp-4]
|
|
Cylinders equ word ptr [bp-6]
|
|
Heads equ word ptr [bp-8]
|
|
SectorsPerTrack equ byte ptr [bp-9]
|
|
Int13UnitNumber equ byte ptr [bp-10]
|
|
SectorsPerCylinder equ word ptr [bp-12]
|
|
DiskSizeh equ word ptr [bp-14]
|
|
DiskSizel equ word ptr [bp-16]
|
|
DiskSize equ dword ptr [bp-16]
|
|
DiskId equ word ptr [bp-18]
|
|
Tableh equ word ptr [bp-20]
|
|
Tablel equ word ptr [bp-22]
|
|
Table equ dword ptr [bp-22]
|
|
FreeStarth equ word ptr [bp-24]
|
|
FreeStartl equ word ptr [bp-26]
|
|
FreeStart equ dword ptr [bp-26]
|
|
|
|
START_AND_SIZE STRUC
|
|
PartStartl dw ?
|
|
PartStarth dw ?
|
|
PartSizel dw ?
|
|
PartSizeh dw ?
|
|
START_AND_SIZE ENDS
|
|
|
|
public _MakePartitionAtStartOfDisk
|
|
_MakePartitionAtStartOfDisk proc far
|
|
|
|
push bp
|
|
mov bp,sp
|
|
sub sp,26
|
|
|
|
push ds
|
|
push es
|
|
push bx
|
|
push si
|
|
push di
|
|
|
|
;
|
|
; Get disk info. This also makes sure the handle is open,
|
|
; calculates the number of sectors we can address on the disk,
|
|
; and the number of sectors in a cylinder.
|
|
;
|
|
call near ptr pGetDiskValues
|
|
jnc @f
|
|
mov ax,0ffffh
|
|
jc done2
|
|
|
|
;
|
|
; Allocate a buffer for our table.
|
|
; Make sure ds addresses DGROUP for crt
|
|
;
|
|
@@: push ds
|
|
push DGROUP
|
|
pop ds
|
|
push 5 * SIZE START_AND_SIZE
|
|
call _malloc
|
|
add sp,2
|
|
pop ds
|
|
mov cx,ax
|
|
or cx,dx
|
|
jnz @f
|
|
dec ax ; ax = -1 for error return
|
|
jmp done2
|
|
@@: mov Tableh,dx
|
|
mov Tablel,ax
|
|
|
|
;
|
|
; Read sector 0 of the disk.
|
|
;
|
|
push SectorBuffer
|
|
push 1
|
|
push 0
|
|
push 0
|
|
push DiskHandle
|
|
call _ReadDisk
|
|
add sp,14
|
|
cmp ax,0
|
|
jne @f
|
|
dec ax
|
|
jmp done1 ; ax = -1 for error exit
|
|
|
|
;
|
|
; Make sure the MBR is valid.
|
|
;
|
|
@@: lds si,SectorBuffer
|
|
cmp word ptr [si+510],0aa55h
|
|
je @f
|
|
mov ax,0ffffh
|
|
jmp done1
|
|
|
|
;
|
|
; Zero out the start/offset table.
|
|
;
|
|
@@: les di,Table ; es:di -> local start/size table
|
|
mov ax,0
|
|
mov cx,4*(SIZE START_AND_SIZE)
|
|
cld
|
|
rep stosb
|
|
|
|
;
|
|
; Build the start/offset table.
|
|
;
|
|
mov cx,4 ; cx = loop count
|
|
add si,1beh ; ds:si -> start of partition table
|
|
mov di,Tablel ; es:di -> local start/size table
|
|
nextent:
|
|
cmp byte ptr [si+4],0
|
|
jnz @f
|
|
add si,16
|
|
loop nextent
|
|
jmp short chkfull
|
|
@@: add si,8 ; ds:si -> relative sector field
|
|
movsw ; start low
|
|
movsw ; start high
|
|
movsw ; count low
|
|
movsw ; count high
|
|
inc al ; remember number of used entries
|
|
loop nextent
|
|
|
|
;
|
|
; See if the partition table is full.
|
|
;
|
|
chkfull:
|
|
cmp al,4
|
|
jne @f
|
|
mov ax,0ffffh
|
|
je done1
|
|
|
|
;
|
|
; Sort the local start/size table. Before calling crt
|
|
; make sure ds addresses DGROUP.
|
|
;
|
|
@@: push ds
|
|
push DGROUP
|
|
pop ds
|
|
push ax ; save table length
|
|
push SEG CompareStartSize
|
|
push OFFSET CompareStartSize ; compare routine pointer
|
|
push SIZE START_AND_SIZE ; size of each element
|
|
push ax ; number of elements to sort
|
|
push Table ; array of elements to sort
|
|
call _qsort
|
|
add sp,12
|
|
pop bx ; restore table length
|
|
pop ds
|
|
|
|
;
|
|
; Put a "fence" entry at the end of the table
|
|
; for space at the end of the disk.
|
|
;
|
|
mov al,SIZE START_AND_SIZE
|
|
mul bl ; ax = byte offset to fence entry
|
|
inc bl ; account for fence entry
|
|
les di,Table
|
|
add di,ax ; es:di -> fence entry
|
|
mov ax,DiskSizel
|
|
mov es:[di].PartStartl,ax
|
|
mov ax,DiskSizeh
|
|
mov es:[di].PartStarth,ax
|
|
mov es:[di].PartSizel,1
|
|
mov es:[di].PartSizeh,0
|
|
|
|
;
|
|
; Initialize for loop. The first space starts on the first sector
|
|
; of the second head.
|
|
;
|
|
mov al,SectorsPerTrack
|
|
cbw
|
|
mov FreeStartl,ax
|
|
mov FreeStarth,0
|
|
|
|
mov cl,bl
|
|
xor ch,ch ; cx = # entries in table
|
|
les di,Table ; es:di -> start/offset table
|
|
jmp short aligned1
|
|
|
|
;
|
|
; Get the start of the partition and align to cylinder boundary
|
|
;
|
|
nextspace:
|
|
mov dx,FreeStarth
|
|
mov ax,FreeStartl ; dx:ax = start of free space
|
|
div SectorsPerCylinder ; dx = sector within cylinder
|
|
cmp dx,0 ; already aligned?
|
|
jz aligned1 ; yes
|
|
mov bx,SectorsPerCylinder
|
|
sub bx,dx ; bx = adjustment to next boundary
|
|
add FreeStartl,bx
|
|
adc FreeStarth,0 ; FreeStart now aligned
|
|
|
|
aligned1:
|
|
mov dx,es:[di].PartStarth
|
|
mov ax,es:[di].PartStartl ; dx:ax = start of partition
|
|
sub ax,FreeStartl
|
|
sbb dx,FreeStarth ; dx:ax = size of free space
|
|
push ax
|
|
push dx
|
|
|
|
;
|
|
; Now make sure the end of the free space is aligned.
|
|
;
|
|
add ax,FreeStartl
|
|
adc dx,FreeStarth ; dx:ax = first sector past free space
|
|
div SectorsPerCylinder ; dx = sector within cylinder (may be 0)
|
|
mov bx,dx
|
|
pop dx
|
|
pop ax ; dx:ax = size of free space
|
|
sub ax,bx
|
|
sbb dx,0 ; dx:ax = size of aligned free space
|
|
js nextspace1 ; just in case
|
|
|
|
;
|
|
; Check the free space to see if it's large enough.
|
|
;
|
|
cmp dx,MinimumSectorCounth
|
|
ja makepart ; it's large enough
|
|
jb nextspace1
|
|
cmp ax,MinimumSectorCountl
|
|
jae makepart
|
|
nextspace1:
|
|
mov ax,es:[di].PartStartl
|
|
add ax,es:[di].PartSizel
|
|
mov FreeStartl,ax
|
|
mov ax,es:[di].PartStarth
|
|
adc ax,es:[di].PartSizeh
|
|
mov FreeStarth,ax ; next space is after this partition
|
|
add di,SIZE START_AND_SIZE ; point at next table entry
|
|
loop nextspace
|
|
mov ax,cx ; no room, set ax for error return
|
|
dec ax
|
|
jmp done1
|
|
|
|
;
|
|
; If we get here, we've found a free space that will work
|
|
; for our partition.
|
|
;
|
|
; FreeStart has the start of the free space.
|
|
;
|
|
makepart:
|
|
mov ax,FreeStartl
|
|
add ax,MinimumSectorCountl
|
|
mov dx,FreeStarth
|
|
adc dx,MinimumSectorCounth
|
|
|
|
div SectorsPerCylinder ; dx = sector within cylinder
|
|
cmp dx,0 ; aligned already?
|
|
jz @f ; yes
|
|
mov bx,SectorsPerCylinder
|
|
sub bx,dx ; bx = adjustment to next cyl boundary
|
|
add MinimumSectorCountl,bx
|
|
adc MinimumSectorCounth,0
|
|
|
|
;
|
|
; Now MinimumSectorCount has the actual sector count.
|
|
; Find a free table entry. We know there is one or else
|
|
; we'd have errored out a while ago.
|
|
;
|
|
@@: lds si,SectorBuffer
|
|
add si,1beh ; ds:si -> partition table
|
|
@@: cmp byte ptr [si+4],0
|
|
jz makepart1
|
|
add si,16
|
|
jmp short @b
|
|
|
|
makepart1:
|
|
mov ax,FreeStartl
|
|
mov dx,FreeStarth
|
|
mov [si+8],ax
|
|
mov [si+10],dx
|
|
add si,1
|
|
call pMakeCHS
|
|
mov ax,MinimumSectorCountl
|
|
mov dx,MinimumSectorCounth
|
|
mov [si+11],ax
|
|
mov [si+13],dx
|
|
add ax,FreeStartl
|
|
adc dx,FreeStarth
|
|
sub ax,1
|
|
sbb dx,0
|
|
add si,4
|
|
call pMakeCHS ; al = xint13 required flag
|
|
sub si,1 ; ds:si -> system id byte
|
|
|
|
;
|
|
; Figure out the partition id.
|
|
; al is xint13 required flag
|
|
;
|
|
mov dx,PartitionClass
|
|
mov ah,SystemId
|
|
call pDetermineSystemId
|
|
mov [si],al ; store away system id
|
|
|
|
sub si,4 ; ds:si -> partition table entry
|
|
call pNewPartitionRecord
|
|
cmp ax,0ffffh
|
|
je done1 ; error, bail now
|
|
|
|
;
|
|
; Phew. Write out the master boot sector.
|
|
;
|
|
push ax ; save partition id
|
|
push SectorBuffer
|
|
push 1
|
|
push 0
|
|
push 0
|
|
push DiskHandle
|
|
call _WriteDisk
|
|
add sp,14 ; ax set for return
|
|
pop dx ; dx = partition id
|
|
cmp ax,0 ; error?
|
|
jne @f ; no
|
|
dec ax ; ax = -1 for error return
|
|
jmp short done1
|
|
@@: mov ax,dx ; ax = partition id for return
|
|
|
|
done1:
|
|
push ax
|
|
push Table
|
|
push DGROUP
|
|
pop ds ; address DGROUP for crt
|
|
call _free
|
|
add sp,4
|
|
pop ax
|
|
|
|
done2:
|
|
pop di
|
|
pop si
|
|
pop bx
|
|
pop es
|
|
pop ds
|
|
|
|
leave
|
|
retf
|
|
|
|
_MakePartitionAtStartOfDisk endp
|
|
|
|
Comparand1 equ dword ptr [bp+6]
|
|
Comparand2 equ dword ptr [bp+10]
|
|
|
|
CompareStartSize proc far
|
|
|
|
push bp
|
|
mov bp,sp
|
|
|
|
push ds
|
|
push es
|
|
push di
|
|
push si
|
|
|
|
lds si,Comparand1
|
|
les di,Comparand2
|
|
|
|
mov dx,es:[di].PartStarth
|
|
mov ax,es:[di].PartStartl
|
|
|
|
cmp [si].PartStarth,dx
|
|
jb less1
|
|
ja greater1
|
|
|
|
cmp [si].PartStartl,ax
|
|
jb less1
|
|
ja greater1
|
|
|
|
xor ax,ax
|
|
jmp short compdone
|
|
|
|
less1:
|
|
mov ax,0ffffh
|
|
jmp short compdone
|
|
|
|
greater1:
|
|
mov ax,1
|
|
|
|
compdone:
|
|
pop si
|
|
pop di
|
|
pop es
|
|
pop ds
|
|
|
|
leave
|
|
retf
|
|
|
|
CompareStartSize endp
|
|
|
|
|
|
;++
|
|
;
|
|
; INT
|
|
; _far
|
|
; MakePartitionAtEndOfEmptyDisk(
|
|
; IN HDISK DiskHandle,
|
|
; OUT FPVOID SectorBuffer,
|
|
; IN ULONG MinimumSectorCount,
|
|
; IN BOOL NewMasterBootCode
|
|
; );
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine creates an partition at the very end of a disk.
|
|
; The disk MUST be completely empty. If no valid MBR exists,
|
|
; one will be created.
|
|
;
|
|
; The partition will be made active.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; DiskHandle - supplies handle to open disk, from OpenDisk().
|
|
;
|
|
; SectorBuffer - supplies a pointer to a buffer suitable for use
|
|
; for i/o of a single sector. This buffer must not
|
|
; cross a DMA boundary, but the caller is responsible
|
|
; for ensuring this.
|
|
;
|
|
; MinimumSectorCount - supplies minimum number of sectors
|
|
; for the partition. The actual size may be larger
|
|
; to account for rounding, etc.
|
|
;
|
|
; This routine does NOT properly deal with partitions
|
|
; that start on cylinder 0 or are larger than the size
|
|
; of the disk! The caller must ensure that these cases
|
|
; do not occur.
|
|
;
|
|
; NewMasterBootCode - if non-0, then new master boot code will
|
|
; be written regardless of the current state of the MBR.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; Partition id of newly created partition.
|
|
; -1 means failure
|
|
;
|
|
;--
|
|
|
|
DiskHandle equ dword ptr [bp+6]
|
|
DiskHandlel equ word ptr [bp+6]
|
|
DiskHandleh equ word ptr [bp+8]
|
|
SectorBuffer equ dword ptr [bp+10]
|
|
SectorBufferl equ word ptr [bp+10]
|
|
SectorBufferh equ word ptr [bp+12]
|
|
MinimumSectorCount equ dword ptr [bp+14]
|
|
MinimumSectorCountl equ word ptr [bp+14]
|
|
MinimumSectorCounth equ word ptr [bp+16]
|
|
NewMasterBootCode equ word ptr [bp+18]
|
|
|
|
ExtSecCnth equ word ptr [bp-2]
|
|
ExtSecCntl equ word ptr [bp-4]
|
|
ExtSecCnt equ dword ptr [bp-4]
|
|
Cylinders equ word ptr [bp-6]
|
|
Heads equ word ptr [bp-8]
|
|
SectorsPerTrack equ byte ptr [bp-9]
|
|
Int13UnitNumber equ byte ptr [bp-10]
|
|
SectorsPerCylinder equ word ptr [bp-12]
|
|
DiskSizeh equ word ptr [bp-14]
|
|
DiskSizel equ word ptr [bp-16]
|
|
DiskSize equ dword ptr [bp-16]
|
|
DiskId equ word ptr [bp-18]
|
|
|
|
public _MakePartitionAtEndOfEmptyDisk
|
|
_MakePartitionAtEndOfEmptyDisk proc far
|
|
|
|
push bp
|
|
mov bp,sp
|
|
sub sp,18
|
|
|
|
push ds
|
|
push es
|
|
push bx
|
|
push si
|
|
push di
|
|
|
|
;
|
|
; Get disk info. This also makes sure the handle is open,
|
|
; calculates the number of sectors we can address on the disk,
|
|
; and the number of sectors in a cylinder.
|
|
;
|
|
call near ptr pGetDiskValues
|
|
jnc @f
|
|
mov ax,0ffffh
|
|
jc mpaod_4
|
|
|
|
@@:
|
|
;
|
|
; Read the mbr.
|
|
;
|
|
push SectorBuffer
|
|
push 1
|
|
push 0
|
|
push 0
|
|
push DiskHandle
|
|
call _ReadDisk
|
|
add sp,14
|
|
cmp ax,0
|
|
jne @f
|
|
dec ax ; ax = -1 for error return
|
|
jmp mpaod_4
|
|
|
|
;
|
|
; Check the mbr. If not valid, make it valid.
|
|
;
|
|
@@: les di,SectorBuffer
|
|
cmp NewMasterBootCode,0
|
|
jnz makembr ; caller wants new master boot code
|
|
cmp byte ptr es:[di+510],055h
|
|
jne makembr
|
|
cmp byte ptr es:[di+511],0aah
|
|
je mbrok
|
|
makembr:
|
|
mov byte ptr es:[di+510],055h
|
|
mov byte ptr es:[di+511],0aah
|
|
mov si,offset DGROUP:_x86BootCode
|
|
mov cx,1b8h/2 ; don't overwrite NTFT sig or table
|
|
rep movsw
|
|
|
|
mbrok:
|
|
;
|
|
; Make sure all entries are empty.
|
|
;
|
|
lds si,SectorBuffer
|
|
add si,1beh
|
|
mov cx,0
|
|
mov ax,cx
|
|
dec ax ; ax = -1
|
|
cmp [si+04h],cl
|
|
jnz mpaod_4
|
|
cmp [si+14h],cl
|
|
jnz mpaod_4
|
|
cmp [si+24h],cl
|
|
jnz mpaod_4
|
|
cmp [si+34h],cl
|
|
jnz mpaod_4
|
|
|
|
;
|
|
; Calculate the starting sector. We don't worry about aligning
|
|
; the end sector because in the conventional int13 case we
|
|
; calculated the disk size based on cylinder count, which means
|
|
; it is guaranteed to be aligned; in the xint13 case CHS isn't
|
|
; even relevent and in any case there won't be any partitions
|
|
; on the disk after this one.
|
|
;
|
|
mov ax,DiskSizel
|
|
sub ax,MinimumSectorCountl
|
|
mov dx,DiskSizeh
|
|
sbb dx,MinimumSectorCounth ; dx:ax = start sector of partition
|
|
mov [si+8],ax
|
|
mov [si+10],dx ; save in partition table
|
|
div SectorsPerCylinder ; ax = cyl, dx = sector within cyl
|
|
sub [si+8],dx ; note: dx is zero if already aligned
|
|
sbb [si+10],cx ; partition table has aligned start
|
|
mov ax,MinimumSectorCountl
|
|
add ax,dx ; grow to account for alignment
|
|
mov [si+12],ax
|
|
mov ax,MinimumSectorCounth
|
|
adc ax,cx
|
|
mov [si+14],ax ; put adjusted size in partition table
|
|
|
|
;
|
|
; Make the partition active.
|
|
;
|
|
mov byte ptr [si],80h
|
|
|
|
;
|
|
; Fill in CHS values for the partition
|
|
;
|
|
mov ax,[si+8]
|
|
mov dx,[si+10] ; dx:ax = start sector
|
|
inc si ; ds:si -> start CHS in part table
|
|
call pMakeCHS
|
|
mov ax,[si+7]
|
|
add ax,[si+11]
|
|
mov dx,[si+9]
|
|
adc dx,[si+13]
|
|
sub ax,1
|
|
sbb dx,0 ; dx:ax = last sector
|
|
add si,4 ; ds:si -> end CHS in part table
|
|
call pMakeCHS ; al = overflow flag
|
|
|
|
;
|
|
; Figure out the system id.
|
|
; al is xint13 required flag
|
|
;
|
|
mov dx,PARTCLASS_FAT
|
|
call pDetermineSystemId
|
|
mov [si-1],al ; store away system id
|
|
|
|
;
|
|
; Build a partition record for this guy and add to list.
|
|
;
|
|
sub si,5 ; ds:si -> partition table entry
|
|
call pNewPartitionRecord
|
|
cmp ax,0ffffh
|
|
je mpaod_4 ; error, ax set for return
|
|
|
|
;
|
|
; The mbr is ready, write it out.
|
|
;
|
|
push ax
|
|
push SectorBuffer
|
|
push 1
|
|
push 0
|
|
push 0
|
|
push DiskHandle
|
|
call _WriteDisk
|
|
add sp,14
|
|
mov dx,ax
|
|
pop ax ; ax = partition id
|
|
cmp dx,0 ; write error?
|
|
jnz mpaod_4 ; no, ax = partition id for exit
|
|
mov ax,0ffffh ; set ax for error return
|
|
|
|
mpaod_4:
|
|
pop di
|
|
pop si
|
|
pop bx
|
|
pop es
|
|
pop ds
|
|
|
|
leave
|
|
retf
|
|
|
|
_MakePartitionAtEndOfEmptyDisk endp
|
|
|
|
|
|
;++
|
|
;
|
|
; INT
|
|
; _far
|
|
; ReinitializePartitionTable(
|
|
; IN HDISK DiskHandle,
|
|
; OUT FPVOID SectorBuffer
|
|
; );
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine wipes a disk completely clean by clearning
|
|
; the partition table and writing new boot code.
|
|
;
|
|
; NOTE: after this routine, partition ids may change!
|
|
;
|
|
; Arguments:
|
|
;
|
|
; DiskHandle - supplies handle to open disk, from OpenDisk().
|
|
;
|
|
; SectorBuffer - supplies a pointer to a buffer suitable for use
|
|
; for i/o of a single sector. This buffer must not
|
|
; cross a DMA boundary, but the caller is responsible
|
|
; for ensuring this.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; The new number of total partitions, -1 if error
|
|
;
|
|
;--
|
|
|
|
DiskHandle equ dword ptr [bp+6]
|
|
SectorBuffer equ dword ptr [bp+10]
|
|
|
|
public _ReinitializePartitionTable
|
|
_ReinitializePartitionTable proc far
|
|
|
|
push bp
|
|
mov bp,sp
|
|
|
|
push ds
|
|
push es
|
|
push si
|
|
push di
|
|
pushf
|
|
|
|
;
|
|
; This is very simple. Move template boot code
|
|
; into the sector buffer and write it out.
|
|
;
|
|
les di,SectorBuffer
|
|
push DGROUP
|
|
pop ds
|
|
mov si,OFFSET DGROUP:_x86BootCode
|
|
mov cx,512/2
|
|
|
|
cld
|
|
rep movsw
|
|
|
|
push SectorBuffer
|
|
push 1
|
|
push 0
|
|
push 0
|
|
push DiskHandle
|
|
call _WriteDisk
|
|
add sp,14
|
|
cmp ax,0
|
|
jnz rpt2
|
|
dec ax ; ax = -1 for return
|
|
jmp short rpt8
|
|
|
|
;
|
|
; Now go through the partition list, removing all entries that were
|
|
; on this disk.
|
|
;
|
|
rpt2:
|
|
les di,DiskHandle
|
|
mov bx,es:[di].DiskInfoDiskId ; bx = id of disk we're wiping
|
|
mov dx,[PartitionListCount]
|
|
mov si,OFFSET DGROUP:PartitionList ; ds:si = &PartitionList
|
|
.errnz PartInfoNext
|
|
|
|
rpt3:
|
|
mov cx,[si].PartInfoNextl
|
|
or cx,[si].PartInfoNexth
|
|
jz rpt5 ; done
|
|
les di,[si].PartInfoNext ; es:di -> current, ds:si -> prev
|
|
cmp es:[di].PartInfoDiskId,bx ; partition on disk we wiped?
|
|
jne rpt4 ; no
|
|
|
|
dec dx ; one fewer total partitions
|
|
|
|
mov ax,es:[di].PartInfoNextl
|
|
mov [si].PartInfoNextl,ax
|
|
mov ax,es:[di].PartInfoNexth
|
|
mov [si].PartInfoNexth,ax ; prev->next = current->next
|
|
|
|
push bx
|
|
push ds
|
|
push DGROUP
|
|
pop ds ; make sure we're addressing DGROUP
|
|
push es
|
|
push di
|
|
call _free ; free(current)
|
|
add sp,4
|
|
pop ds
|
|
pop bx ; restore disk id
|
|
|
|
jmp short rpt3
|
|
|
|
rpt4: mov ax,es
|
|
mov ds,ax
|
|
mov si,di ; prev = current
|
|
jmp short rpt3
|
|
|
|
rpt5:
|
|
push DGROUP
|
|
pop ds
|
|
mov [PartitionListCount],dx ; save new count
|
|
mov ax,dx ; ax = return value
|
|
|
|
;
|
|
; Now reassign partition ids so they are contiguous.
|
|
;
|
|
mov si,OFFSET DGROUP:PartitionList
|
|
rpt6: mov cx,[si].PartInfoNextl
|
|
or cx,[si].PartInfoNexth
|
|
jz rpt8
|
|
dec dx
|
|
lds si,[si].PartInfoNext
|
|
mov [si].PartInfoDiskId,dx
|
|
jmp short rpt6
|
|
|
|
rpt8:
|
|
popf
|
|
pop di
|
|
pop si
|
|
pop es
|
|
pop ds
|
|
|
|
leave
|
|
retf
|
|
|
|
_ReinitializePartitionTable endp
|
|
|
|
|
|
|
|
;
|
|
; dx:ax = sector to translate
|
|
; ds:si -> CHS bytes
|
|
;
|
|
pMakeCHS proc near
|
|
|
|
div SectorsPerCylinder ; ax = cylinder, dx = sector in cyl
|
|
|
|
cmp ax,Cylinders ; overflow?
|
|
jb chsok ; no, continue
|
|
|
|
push 1 ; overflow flag
|
|
mov ax,Cylinders
|
|
dec ax ; store max cylinder in table
|
|
jmp short chs1
|
|
|
|
chsok:
|
|
push 0 ; no overflow flag
|
|
chs1: mov cx,ax
|
|
xchg cl,ch
|
|
shl cl,6
|
|
|
|
;
|
|
; small divide is acceptable here since head is 1-255, sector is
|
|
; 1-63 (and thus max sector within cyl is (63*256)-1).
|
|
;
|
|
mov ax,dx
|
|
div SectorsPerTrack ; al = head, ah = sector
|
|
inc ah ; sector is 1-based
|
|
or cl,ah ; cx has cyl/sector in int13 format
|
|
|
|
storechs:
|
|
mov [si+1],cx ; store in partition table entry
|
|
mov [si],al ; store head in partition table entry
|
|
|
|
pop ax ; return overflow flag
|
|
ret
|
|
|
|
pMakeCHS endp
|
|
|
|
|
|
;
|
|
; ds:si -> partition table entry with lba and sysid fields filled in
|
|
; preserves none
|
|
; returns new part ordinal or -1
|
|
;
|
|
pNewPartitionRecord proc near
|
|
|
|
;
|
|
; Allocate a new partition record
|
|
;
|
|
push ds
|
|
push si
|
|
push DGROUP
|
|
pop ds
|
|
mov si,OFFSET DGROUP:PartitionListCount
|
|
push [si] ; save count for later
|
|
inc word ptr [si]
|
|
push SIZE PART_INFO
|
|
call _malloc
|
|
add sp,2
|
|
pop bx ; restore partition count
|
|
pop si
|
|
pop ds ; ds:si -> partition table entry
|
|
mov cx,ax
|
|
or cx,dx
|
|
jnz @f ; malloc ok
|
|
mov ax,0ffffh
|
|
jz npr_done ; return failure
|
|
|
|
@@: push bx
|
|
mov cx,DGROUP
|
|
mov es,cx
|
|
mov di,OFFSET DGROUP:PartitionList ; es:di = &PartitionList
|
|
|
|
.errnz PartInfoNext
|
|
mov cx,es:[di] ; get current head of list in bx:cx
|
|
mov bx,es:[di+2]
|
|
|
|
mov es:[di],ax
|
|
mov es:[di+2],dx ; insert new record at head of list
|
|
|
|
mov es,dx
|
|
mov di,ax ; es:di -> new record
|
|
mov es:[di].PartInfoNextl,cx
|
|
mov es:[di].PartInfoNexth,bx
|
|
|
|
mov ax,DiskId
|
|
mov es:[di].PartInfoDiskId,ax
|
|
pop ax ; partition ordinal, also return val
|
|
mov es:[di].PartInfoOrdinal,ax
|
|
mov cx,[si+8]
|
|
mov es:[di].PartInfoStartSectorl,cx
|
|
mov cx,[si+10]
|
|
mov es:[di].PartInfoStartSectorh,cx
|
|
mov cx,[si+12]
|
|
mov es:[di].PartInfoSectorCountl,cx
|
|
mov cx,[si+14]
|
|
mov es:[di].PartInfoSectorCounth,cx
|
|
mov cl,[si+4]
|
|
mov es:[di].PartInfoSystemId,cl
|
|
|
|
;
|
|
; Indicate partition not open
|
|
;
|
|
mov es:[di].PartInfoPartOpen,0
|
|
mov es:[di].PartInfoDiskHandlel,0
|
|
mov es:[di].PartInfoDiskHandleh,0
|
|
|
|
npr_done:
|
|
ret
|
|
|
|
pNewPartitionRecord endp
|
|
|
|
|
|
;
|
|
; No params, nested in top-level routines above
|
|
;
|
|
pGetDiskValues proc near
|
|
|
|
;
|
|
; Get disk info. This also makes sure the handle is open.
|
|
;
|
|
push ss
|
|
lea bx,DiskId
|
|
push bx
|
|
push ss
|
|
lea bx,ExtSecCnt
|
|
push bx
|
|
push ss
|
|
lea bx,Cylinders
|
|
push bx
|
|
push ss
|
|
lea bx,Heads
|
|
push bx
|
|
push ss
|
|
lea bx,SectorsPerTrack
|
|
push bx
|
|
push ss
|
|
lea bx,Int13UnitNumber
|
|
push bx
|
|
push DiskHandle
|
|
call _GetDiskInfoByHandle
|
|
add sp,28
|
|
cmp ax,0
|
|
jnz @f
|
|
stc
|
|
ret
|
|
|
|
;
|
|
; Calculate the number of sectors we can address on the disk.
|
|
; Also precalculate the number of sectors in a cylinder.
|
|
;
|
|
@@: mov al,SectorsPerTrack
|
|
cbw
|
|
mul Heads ; ax = sectors per cylinder, dx = 0
|
|
mov SectorsPerCylinder,ax
|
|
cmp ExtSecCntl,dx
|
|
jnz usexcnt
|
|
cmp ExtSecCnth,dx
|
|
jnz usexcnt
|
|
mul Cylinders ; dx:ax = sectors on disk
|
|
jmp short storsize
|
|
usexcnt:
|
|
mov dx,ExtSecCnth
|
|
mov ax,ExtSecCntl
|
|
storsize:
|
|
mov DiskSizeh,dx
|
|
mov DiskSizel,ax
|
|
clc
|
|
gv3: ret
|
|
|
|
pGetDiskValues endp
|
|
|
|
|
|
;
|
|
; No params, nested in top-level routines above
|
|
; al = xint13 required flag
|
|
; dx = partition class
|
|
; ah = sysid if unknown class
|
|
;
|
|
; returns system id in al
|
|
;
|
|
pDetermineSystemId proc near
|
|
|
|
cmp dx,PARTCLASS_FAT
|
|
jne tryfat32
|
|
cmp al,0
|
|
je @f
|
|
mov al,0eh ; type e = fat xint13
|
|
jmp short gotsysid
|
|
@@: cmp MinimumSectorCounth,0
|
|
jne bigfat
|
|
cmp MinimumSectorCountl,32680
|
|
jb fat12
|
|
mov al,4 ; type 4 = fat16
|
|
jmp short gotsysid
|
|
fat12: mov al,1 ; type 1 = fat12
|
|
jmp short gotsysid
|
|
bigfat: mov al,6 ; type 6 = huge fat
|
|
jmp short gotsysid
|
|
|
|
tryfat32:
|
|
cmp dx,PARTCLASS_FAT32
|
|
jne tryntfs
|
|
cmp al,0
|
|
jne @f
|
|
mov al,0bh ; type b = fat32 non-xint13
|
|
jmp short gotsysid
|
|
@@: mov al,0ch ; type c = fat32 xint13
|
|
jmp short gotsysid
|
|
|
|
tryntfs:
|
|
cmp dx,PARTCLASS_NTFS
|
|
jne othersys
|
|
mov al,7 ; type 7 = ntfs
|
|
jmp short gotsysid
|
|
|
|
othersys:
|
|
mov al,ah
|
|
|
|
gotsysid:
|
|
ret
|
|
|
|
pDetermineSystemId endp
|
|
|
|
end
|