%if 0 scanptab - Scan partition table 2019 by C. Masloch Usage of the works is permitted provided that this instrument is retained with the works, so that any entity that uses the works is notified of this instrument. DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. %endif ; _SCANPTAB_PREFIX = prefix for our variables and functions ; _SCANPTAB_DEBUG4_PREFIX = prefix for d4 function calls numdef PARTITION_TABLE_IN_CS, 1 numdef BOOTCMD_FAIL_ERROR, 1 gendef BASE, ss:bx %ifidn _BASE, ss:bx %elifidn _BASE, bp %else %error Invalid base %endif ; INP: byte [%load_unit] = unit to scan ; cx = function to call for each partition ; OUT: function called for each partition ; CHG: di, si, ax, bx, (cx), dx, es ; STT: ds => data segment (used for %load_* variables, unless bp-based) ; ; Note: Calls %read_partition_table (in this module), ; which calls %read_ae_512_bytes, which calls ; read_sector. The read_sector base must be ; zero and the geometry must be initialised. ; Function in cx is called with: ; INP: es:si -> partition table entry, ; si = %partition_table .. %partition_table+48, ; es = ss (if not _PARTITION_TABLE_IN_CS) ; es = cs (if _PARTITION_TABLE_IN_CS) ; byte [%load_current_partition] = partition number, ; 0 for diskette (unpartitioned), ; 1 to 4 for primary partitions, ; 5+ for logical partitions ; _BASE + di -> above part table metadata, ; dword [_BASE + di - 4] = root (outermost extended position) ; dword [_BASE + di - 8] = base (current table position) ; dword [es:si + piStart] = local partition start ; base + local start = absolute partition start ; _BASE -> bp value (dummy if _BASE is not bp), ; near return address of scan_partitions ; CHG: ax, (cx), dx, bx (unless part of _BASE) ; STT: ds => data segment (used for load_* variables, unless bp-based) ; Note: preserves (cx), si, di, ds, es, (bp), _BASE ; ; Note: If the function returns to scan_partitions, ; cx must be left as the function to call for ; subsequent partitions afterwards. ; Note: May load sp from _BASE then pop bp then return ; near if the scan should stop after the call. %[_SCANPTAB_PREFIX]scan_partitions: and word [ %[_SCANPTAB_PREFIX]load_partition_cycle], 0 d4 call %[_SCANPTAB_DEBUG4_PREFIX]d4message d4 asciz "In scan_partitions",13,10 push bp %ifidn _BASE, ss:bx mov bx, sp %elifidn _BASE, bp mov bp, sp %endif xor di, di push di ; [_BASE+di-2] push di ; [_BASE+di-4] push di ; [_BASE+di-6] push di ; [_BASE+di-8] cmp byte [ %[_SCANPTAB_PREFIX]load_unit], 80h jae @F push di push cx %if _PARTITION_TABLE_IN_CS push cs %else push ss %endif pop es mov di, %[_SCANPTAB_PREFIX]partition_table xor ax, ax mov cx, (4 * 16) >> 1 rep stosw ; initialise fake partition table pop cx pop di mov si, %[_SCANPTAB_PREFIX]partition_table ; -> fake PARTINFO mov byte [es:si + piBoot], 80h ; fake primary active mov byte [es:si + piType], 0FFh ; fake a type mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 0 ; special: 0 = diskette ; piLength is 0, too call cx jmp %[_SCANPTAB_PREFIX]scan_logical.end @@: xor ax, ax xor dx, dx d4 call %[_SCANPTAB_DEBUG4_PREFIX]d4message d4 asciz "In scan_partitions (before first call to read_partition_table)",13,10 call %[_SCANPTAB_PREFIX]read_partition_table d4 call %[_SCANPTAB_DEBUG4_PREFIX]d4message d4 asciz "In scan_partitions (after first call to read_partition_table)",13,10 mov si, %[_SCANPTAB_PREFIX]partition_table mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], dl ; = 0 .loop_primary_parts: inc byte [ %[_SCANPTAB_PREFIX]load_current_partition] cmp byte [es:si + piType], 0 je .loop_primary_skip call cx ; es:si -> partition table entry ; byte [load_current_partition] = which .loop_primary_skip: add si, 16 cmp si, %[_SCANPTAB_PREFIX]partition_table.end jb .loop_primary_parts %[_SCANPTAB_PREFIX]scan_logical: .: d4 call %[_SCANPTAB_DEBUG4_PREFIX]d4message d4 asciz "In scan_logical.",13,10 mov si, %[_SCANPTAB_PREFIX]partition_table .loop: inc word [ %[_SCANPTAB_PREFIX]load_partition_cycle] jz .got_partition_cycle mov al, [es:si + piType] %ifidn _BASE, bp xor bx, bx %endif test al, al jz .next cmp al, 0Fh ; extended partition (LBA aware) ? je .push ; yes --> and al, ~80h ; extended partition Linux (85h) ? cmp al, 05h ; or extended partition DOS (05h) ? je .push ; yes --> %ifidn _BASE, bp cmp word [_BASE+di-2], bx jne .logical cmp word [_BASE+di-4], bx %else cmp word [_BASE+di-2], 0 jne .logical cmp word [_BASE+di-4], 0 %endif je .next .logical: inc byte [ %[_SCANPTAB_PREFIX]load_current_partition] jz .error_too_many_partitions call cx ; CHG: ax, (cx), dx, bx if _BASE = bp ; preserve: (cx), si, di, ds, es, bx if _BASE = ss:bx .next: add si, 16 ; -> next partition table entry cmp si, %[_SCANPTAB_PREFIX]partition_table.end ; was last? jb .loop ; no, loop --> test di, di ; still some on stack? jnz .pop ; yes, pop .end: %ifidn _BASE, bp mov sp, bp ; restore sp pop bp %else mov sp, bx ; restore sp pop ax ; (discard dummy bp value) %endif retn ; and bye .push: d4 call %[_SCANPTAB_DEBUG4_PREFIX]d4message d4 asciz "In scan_logical.push",13,10 push si .push_check_empty_next: add si, 16 ; -> next cmp si, %[_SCANPTAB_PREFIX]partition_table.end ; at end? jae .replace ; yes, no other partitions found, replace --> cmp byte [es:si + piType], 0 ; is this a partition? je .push_check_empty_next ; no, check next --> ; found a partition after this, do push ; (possibly logical or another extended) .push_check_is_not_empty: d4 call %[_SCANPTAB_DEBUG4_PREFIX]d4message d4 asciz "In scan_logical.push_check_is_not_empty",13,10 pop si ; restore -> partition table entry push si ; stored at word [_BASE+di-10] sub di, 10 push word [_BASE+di+10-2] push word [_BASE+di+10-4] ; copy root mov ax, word [es:si + piStart] mov dx, word [es:si + piStart + 2] ; get extended partition offset add ax, word [_BASE+di-4] adc dx, word [_BASE+di-2] ; add in root to get absolute sector number push dx push ax ; new base .replace_common: %ifidn _BASE, bp cmp word [_BASE+di-2], bx ; have a (nonzero) root? jne .have_root cmp word [_BASE+di-4], bx %else cmp word [_BASE+di-2], 0 ; have a (nonzero) root? jne .have_root cmp word [_BASE+di-4], 0 %endif jne .have_root ; yes --> mov word [_BASE+di-2], dx mov word [_BASE+di-4], ax ; set root .have_root: call %[_SCANPTAB_PREFIX]read_partition_table jmp . .pop: d4 call %[_SCANPTAB_DEBUG4_PREFIX]d4message d4 asciz "In scan_logical.pop",13,10 add di, 10 add sp, 8 pop si mov ax, word [_BASE+di-8] mov dx, word [_BASE+di-6] call %[_SCANPTAB_PREFIX]read_partition_table jmp .next .replace: d4 call %[_SCANPTAB_DEBUG4_PREFIX]d4message d4 asciz "In scan_logical.replace",13,10 pop si ; (discard) mov ax, word [es:si + piStart] mov dx, word [es:si + piStart + 2] ; get extended partition offset add ax, word [_BASE+di - 4] adc dx, word [_BASE+di - 2] ; add in root mov word [_BASE+di - 8], ax mov word [_BASE+di - 6], dx ; set base jmp .replace_common %if _BOOTCMD_FAIL_ERROR .got_partition_cycle: mov dx, msg.boot_partition_cycle_error jmp bootcmd.fail .error_too_many_partitions: mov dx, msg.boot_too_many_partitions_error jmp bootcmd.fail %endif ; if _PARTITION_TABLE_IN_CS: ; INP: dx:ax = partition table sector to read ; CHG: ax, dx ; OUT: es = cs ; 64 bytes [es:partition_table] = partition table ; does not return if error ; else: ; INP: dx:ax = partition table sector to read ; CHG: ax, dx ; OUT: es = ss ; 64 bytes [es:partition_table] = partition table ; does not return if error %[_SCANPTAB_PREFIX]read_partition_table: push bx %ifidn _BASE, bp mov bx, word [auxbuff_segorsel] ; bx => auxbuff %else mov bx, word [bp + ldSectorSeg] %endif call %[_SCANPTAB_PREFIX]read_ae_512_bytes pop bx cmp word [es:510], 0AA55h jne .signature_fail push ds push di push si push cx push es pop ds mov si, 510 - 4*16 ; ds:si -> partition table in sectorseg %if _PARTITION_TABLE_IN_CS push cs %else push ss %endif pop es mov di, %[_SCANPTAB_PREFIX]partition_table ; es:di -> cs:%[_SCANPTAB_PREFIX]partition_table mov cx, 4*16 / 2 rep movsw pop cx pop si pop di pop ds retn %if _BOOTCMD_FAIL_ERROR .signature_fail: mov dx, msg.bootfail_sig_parttable jmp bootcmd.fail %endif