User Tools

Site Tools


review_of_iniload_control_flow

Review of iniload control flow

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1375 Offset: 1020, signature "lDXX". The "lD" is checked by recent lDOS compatible loaders, the "XX" is two nonblank printable ASCII text bytes to identify the payload, checked in https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l259

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1396 Offset: 1024 (third 512-bytes block), ldos_entry, the lDOS compatible entrypoint. Initialises the incoming stack with two pushes and writing a zero to lsvExtra. Checks that lsvLoadSeg is >= cs + paras(end), displays the error "Initial loader not fully loaded" otherwise. Next, clamps lsvLoadSeg so it will not point higher than => cs + paras(payload.actual_end).

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1453 init_memory, gets Low Memory Area size using int 12h and optionally adjusts it by calling the RPL. Reserves two 8 KiB buffers below the memory top, using the higher buffer as sector segment if it doesn't cross a 64 KiB boundary. Otherwise the lower buffer is used as sector segment. In any case, the other buffer is used as FAT segment.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1511 .gotsegs, subtracts from the segment pointer to the lower buffer to address the destination for the stack, load command line, load data (ld), load stack variables (lsv), and boot sector. Checks that this segment is above-or-equal the adjusted lsvLoadSeg (which as per ldos_entry is clamped to point no higher than past the actual payload), else errors out with "Out of memory.", then checks that the incoming ss:bp + 512 + 15 do not point above the destination (again erroring out if they do). Also checks that the incoming lsvFATSeg + 8 KiB doesn't point above the destination. (It is intended that the lsvFATSeg may be zero to indicate no FAT segment.)

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1557 Checks whether a command line is passed below the lsv. Stores a zero in first byte of LOADCMDLINE destination and a -1 in the last byte if not, else copies over the command line and stores a 0 in the last byte. Copies over lsv and boot sector (512 bytes) to stack destination. Zeroes an area behind the boot sector (preparing for a FAT32 EBPB which doesn't move up the trail of the boot sector).

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1585 Relocates the stack to the destination, and points ss:bp -> the relocated boot sector. Then enables interrupts (EI) using a sti instruction.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1608 Initialises the ldMemoryTop, ldLoadTop, and ldSectorSeg variables. Copies over 8 KiB from original lsvFATSeg => buffer to FAT buffer and updates lsvFATSeg. Saves the original lsvFATSeg for later. Sets ds and es to equal ss.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1631 Checks bpbSectorsPerFAT for zero to detect FAT32. If not: First, moves up BPBN and boot sector trail to make space for the pseudo-FAT32 EBPB trail. Second, zeroes high words of lsvFirstCluster and lsvFATSector. Third, inits ebpbSectorsPerFATLarge (equal to zero-extended bpbSectorsPerFAT) and ebpbFSFlags (zero).

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1656 Calls query_geometry (in first 512 bytes of iniload).

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1664 Checks size of lsvLoadSeg minus cs, if large enough then call init_memory_multi (in the fourth 512 bytes block of iniload). If any lsvExtra.flags set, check that handle_lsv_extra_flags is resident (behind end3) and then call it, or error out if any lsvExtra.flags set and it is not resident.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1686 Calculate ldClusterSize (word) variable from bpbSectorsPerCluster (byte), transforming a zero to 256 (EDR-DOS compatible). Calculate ldParaPerSector. Determine 32-bit amount of sectors in the file system, and update bpbTotalSectorsLarge to the value that is in use. Compare bpbSectorsPerFAT to 0, and branch to .got_fat_type with ldFATType equal to 32 if so. If it was not zero, subtract from 32-bit amount sectors the lsvDataStart to calculate amount of data sectors. Divide by cluster size to calculate amount of data clusters. Set ldFATType to 16 or 12.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1749 If FAT12 and the incoming lsvFATSeg was nonzero, assume the FAT was already loaded and pass it along. Otherwise, check if lsvLoadSeg is high enough to not need any further loading, if yes then force lsvFATSeg to zero to indicate FAT not loaded. Else load the FAT, either using load_fat12_multi (if multi-sector loader already enabled) or a single-sector loop. Load at most 6 KiB worth of FAT data or as many as bpbSectorsPerFAT, whichever is smaller.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1800 .got_fat12: FAT12 loaded, init cx => FAT segment, .got_fat_type: FAT16 or FAT32, init cx likewise, .got_fat12_zero: FAT12 without FAT loaded, cx = 0.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1805 Transfer to finish_continue (in the second 512-bytes block).

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l985 finish_continue (in second 512-bytes block), store cx in lsvFATSeg. Store paras(payload.actual_end) in ax, add para per sector - 1, mask AND with NOT (para per sector - 1), yielding the length of the payload rounded up to the next full sector, in paragraphs.

Add to ax the current cs, if it carries then go to relocation code. If it doesn't carry, compare ax to ldLoadTop, if ax is below or equal to ldLoadTop then branch to finish_load. Else, fall through to relocation code.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1007 Relocation code, subtract ldLoadTop from ax (needed top of last sector loaded), yielding how far in paragraphs we need to relocate down. Get lsvLoadSeg into cx, then subtract ax from lsvLoadSeg (to relocate it). Negate ax. Add cs to ax, calculating where we have to relocate cs to. If this addition doesn't carry, error out with out of memory. If the result in ax is < 61h, error out with out of memory. Push the result in ax, and call to finish_relocation. This puts the near address of relocate_to onto the stack, forming a far address that points to relocate_to in the relocation destination segment.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1176 finish_relocation, (in second 512-bytes block,) push ax => destination cs onto the stack. Decrement ax to => destination for relocator stub (at least 60h). Point es:di -> destination for the stub. Push es:di far pointer onto the stack. Point ds:si -> unrelocated relocator source. Run repeated movsw instructions to place the relocator.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1194 Prepare relocator running. Zero di and si. Subtract current cs from cx (old lsvLoadSeg), calculating how many paragraphs to be relocated. Set bx to paras(64 KiB). Set ax to cx. If ax indicates less than or equal to 64 KiB are already loaded, leave cx as is. Else set cx to paras(64 KiB) from bx. Subtract cx from ax, leaving ax as either zero or how many paragraphs to be relocated beyond the first 64 KiB. Shift left cx thrice to convert from amount paragraphs to amount words. Jump to the relocator using a retf instruction.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1166 relocator, pops es => destination of relocation (always below source), run rep movsw to relocate the first 1.5 KiB to 64 KiB, then run a retf. This last instruction branches to relocate_to.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1027 relocate_to, in second 512-bytes block. Run a rep movsw instruction (no-op on entry from relocator as cx already zero), add 1000h to es and to ds, subtract 1000h = paras(64 KiB) = bx from ax and prepare cx = 8000h = words(64 KiB), if ax was >= 1000h then branch back to relocate_to for the next full 64 KiB chunk. Afterwards add bx to ax to restore the amount of paragraphs in the last chunk. Shift left ax by 3 to convert to amount words, set cx from ax, and run a final rep movsw that moves 0 to 65520 bytes. Reset ds to equal ss and fall through to finish_load.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1070 finish_load, in second 512-bytes block. Get paras(payload.actual_end) from the stack. Add cs to it. Set ldLoadUntilSeg to result. Check whether lsvLoadSeg is already as high or higher than ldLoadUntilSeg, if yes branch to loaded_all. If no, set ldLoadingSeg to cs, get lsvFirstCluster, run check_clust, and error out if the cluster is invalid (0, 1, or beyond maximum for this FAT type).

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1094 skip/load loop, in the second 512-bytes block. This loop initially skips file data sectors already covered in full by the prior loader stage, as communicated by the incoming lsvLoadSeg => behind loaded file data. It walks the file, using the FAT when needed to read the next cluster, and calculating the first sector of each cluster then looping for the amount sectors per cluster, incrementing the sector number and load segment. As soon as the load segment calculated points above the (relocated) lsvLoadSeg, a branch to the skipped_all label occurs.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1141 skipped_all. Undoes the last addition by subtracting ldParaPerSector from bx, then either branches to skipped_all_multi, or else calls read_sector once and jumps to skipped_all_continue.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1811 skipped_all_continue (within end+32, at the start of the fourth 512-bytes block). After the first successful read_sector call for file data, at least 1536+32 bytes of the file are loaded. (32 bytes is the smallest theoretical size of a FAT FS sector.) Therefore, skipped_all_continue can be placed here. It checks whether end3 is already loaded yet, and if not then it branches back into the single-sector loop at loadorskip_next_sector. If it is loaded now, then branch to multi_late to set up the multi-sector loader for the remaining file data.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l1122 loadorskip_next_sector: As soon as skipped_all_continue branches back to loadorskip_next_sector, the prior skip loop turns into a load loop. For every sector still needed, lsvLoadSeg will be detected as being below the end of the sector, so the loop will immediately branch to skipped_all again. If the end of the FAT chain is reached, the code checks that the final FAT entry contained a valid EOC value. If not, error out as bad chain. Then it checks whether ldLoadUntilSeg is reached, if not error out as short file, else branch to loaded_all. In the load loop, if bx reaches at least ldLoadUntilSeg, branch to loaded_all.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l2507 loaded_all and loaded_all.2stack, behind end3. Check bpbSectorsPerFAT equals zero to determine if FAT32. If not, zero out several EBPB fields in the pseudo-FAT32 EBPB created for FAT12 and FAT16 earlier. Copy the query patch value into ldQueryPatchValue for next stage.

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l2575 Preserve the last byte of the LOADCMDLINE buffer (was set to 0 if valid and -1 if invalid), scan for end of command line, and fill remaining space in the command line buffer with the preserved last byte value. (An empty specified command line will end up starting with 00h 00h, while an unspecified command line will instead end up starting with 00h FFh.)

https://hg.pushbx.org/ecm/ldosboot.exp/file/fada37de0070/iniload.asm#l2587 Calculate far address at which to enter the payload, push this address, and transfer control to the payload using a retf instruction.

review_of_iniload_control_flow.txt · Last modified: 2025-10-27 20:30:29 +0100 Oct Mon by ecm