From a1a65bf7925491b3692fc8a78cf7987f7f422c48 Mon Sep 17 00:00:00 2001 From: "E. C. Masloch" Date: Fri, 10 Oct 2025 18:52:13 +0200 Subject: [PATCH 1/3] sys.c: in _dos_findfirst set DTA rather than copying from PSP:80h Running prior to this commit, a /K switch with a name at a certain position will write all-blanks into the boot sector loader. If that happens, lDOS instsect will not detect a valid load file name: C:\>sys a: /bootonly /k ldos.com System transferred. C:\>instsect /bo a: Detected FAT12 FS. Keeping original sector loader. Sector valid, FS ID match and proper jump. Type heuristic: "FreeDOS (FreeDOS)" No name detected. Unit selection code not found in sector. Keeping as is. Part info code not found in sector. Keeping as is. Query geometry code not found in sector. Keeping as is. Auto LBA detection (HDD only) found in sector. Keeping as is. Previous geometry: 2 CHS Heads, 18 CHS Sectors, 0 Hidden Writing boot sector to sector. C:\> Running after this commit sets the name as desired: C:\>sys a: /bootonly /k ldos.com System transferred. C:\>instsect /bo a: Detected FAT12 FS. Keeping original sector loader. Sector valid, FS ID match and proper jump. Type heuristic: "FreeDOS (FreeDOS)" 1st name: "LDOS.COM" Unit selection code not found in sector. Keeping as is. Part info code not found in sector. Keeping as is. Query geometry code not found in sector. Keeping as is. Auto LBA detection (HDD only) found in sector. Keeping as is. Previous geometry: 2 CHS Heads, 18 CHS Sectors, 0 Hidden Writing boot sector to sector. C:\> For reference, the libi86 implementation of _dos_findfirst also sets the DTA to the user buffer rather than copying around the resulting search record. So it is likely that Turbo C or Watcom do it similarly to this: https://gitlab.com/tkchia/libi86/-/blob/3ecc4164999a5807c40cf2c159dc94dd07f7df03/host-gcc/dos/dos-findfirst.c#L43 --- sys/sys.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sys/sys.c b/sys/sys.c index a3ea6454..604b8deb 100644 --- a/sys/sys.c +++ b/sys/sys.c @@ -197,13 +197,19 @@ int _dos_findfirst(const char *file_name, unsigned int attr, struct find_t *find_tbuf) { union REGS in, out; + struct SREGS sr; + in.h.ah = 0x1A; /* set DTA */ + in.x.dx = FP_OFF(find_tbuf); + sr.ds = FP_SEG(find_tbuf); + intdosx(&in, &out, &sr); in.h.ah = 0x4e; in.x.dx = FP_OFF(file_name); in.x.cx = attr; intdos(&in, &out); if (out.x.cflag) return out.x.ax; - memcpy(find_tbuf, (void *)0x80, sizeof(*find_tbuf)); + /* memcpy(find_tbuf, (void *)0x80, sizeof(*find_tbuf)); */ + /* did set DTA to find_tbuf prior */ return 0; } #else From d655a34e525d8f9a0a66cd098a180c8759cae91f Mon Sep 17 00:00:00 2001 From: "E. C. Masloch" Date: Fri, 10 Oct 2025 19:17:03 +0200 Subject: [PATCH 2/3] sys.c: work around Xi8088 ROM-BIOS bug for int 13.41 [#156] This commit contains a number of changes: 1. int86x gets and sets struct SREGS members ds and es 2. int86x patches itself (SMC) using a cs: segment override prefix, as ds may no longer equal cs. 3. int86x interrupt number is %7 rather than %5 4. int86x assembly part doesn't push and pop ds, it is handled by the compiler instead (in practice it puts a push ss \ pop ds at the end of the function to restore the near data segment). 5. int86 is implemented by calling int86x (with ds = es = 0) 6. findfirst, int2526readwrite, fat32readwrite also changed to use int86x because they need to set ds. This used to be implied as the same ds that the compiler already used by default. 7. Finally, haveLBA changed to set ds to 40h. The inline assembly constraints for gcc-ia16 are documented in https://gitlab.com/tkchia/gcc-ia16/-/blob/ca893320926dc93552390b892a202e9373d040c0/gcc/doc/md.texi#L2379 --- sys/sys.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/sys/sys.c b/sys/sys.c index 604b8deb..fbacbe92 100644 --- a/sys/sys.c +++ b/sys/sys.c @@ -105,24 +105,34 @@ struct _diskfree_t { unsigned short avail_clusters, sectors_per_cluster, bytes_per_sector; }; -int int86(int ivec, union REGS *in, union REGS *out) +int int86x(int ivec, union REGS *in, union REGS *out, struct SREGS *s) { /* must save sp for int25/26 */ - asm("mov %5, (1f+1); jmp 0f; 0:push %%ds; mov %%di, %%dx; mov %%sp, %%di;" + asm("mov %7, %%cs:(1f+1); jmp 0f; 0:" + "mov %%di, %%dx; mov %%sp, %%di;" "push %%di; push %%di;" /* push twice to work both for int 25h/26h and int 21h */ "1:int $0x00; pop %%di; pop %%di;" /* second pop always reads the correct SP value. the first pop may read the FL left on stack. */ - "mov %%di, %%sp; pop %%ds; sbb %0, %0" : + "mov %%di, %%sp; sbb %0, %0" : "=r"(out->x.cflag), - "=a"(out->x.ax), "=b"(out->x.bx), "=c"(out->x.cx), "=d"(out->x.dx) : + "=a"(out->x.ax), "=b"(out->x.bx), "=c"(out->x.cx), "=d"(out->x.dx), + "=e"(s->es), "=Rds"(s->ds) : "q"((unsigned char)ivec), "a"(in->x.ax), "b"(in->x.bx), - "c"(in->x.cx), "D"(in->x.dx), "S"(in->x.si) : + "c"(in->x.cx), "D"(in->x.dx), "S"(in->x.si), "e"(s->es), + "Rds"(s->ds) + : "cc", "memory"); return out->x.ax; } +int int86(int ivec, union REGS *in, union REGS *out) +{ + struct SREGS sr = {0,}; + return int86x(ivec, in, out, &sr); +} + int intdos(union REGS *in, union REGS *out) { return int86(0x21, in, out); @@ -205,7 +215,8 @@ int _dos_findfirst(const char *file_name, unsigned int attr, in.h.ah = 0x4e; in.x.dx = FP_OFF(file_name); in.x.cx = attr; - intdos(&in, &out); + sr.ds = FP_SEG(file_name); + intdosx(&in, &out, &sr); if (out.x.cflag) return out.x.ax; /* memcpy(find_tbuf, (void *)0x80, sizeof(*find_tbuf)); */ @@ -1140,12 +1151,14 @@ int generic_block_ioctl(unsigned drive, unsigned cx, unsigned char *par); int int2526readwrite(int DosDrive, void *diskReadPacket, unsigned intno) { union REGS regs; + struct SREGS sregs; regs.h.al = (BYTE) DosDrive; regs.x.bx = (short)diskReadPacket; regs.x.cx = 0xffff; + sregs.ds = FP_SEG(diskReadPacket); - int86(intno, ®s, ®s); + int86x(intno, ®s, ®s, &sregs); return regs.x.cflag; } @@ -1161,13 +1174,15 @@ int2526readwrite(DosDrive, diskReadPacket, 0x26) int fat32readwrite(int DosDrive, void *diskReadPacket, unsigned intno) { union REGS regs; + struct SREGS sregs; regs.x.ax = 0x7305; regs.h.dl = DosDrive; regs.x.bx = (short)diskReadPacket; regs.x.cx = 0xffff; regs.x.si = intno; - intdos(®s, ®s); + sregs.ds = FP_SEG(diskReadPacket); + int86x(0x21, ®s, ®s, &sregs); return regs.x.cflag; } /* fat32readwrite */ @@ -1292,10 +1307,15 @@ BOOL haveLBA(void); /* return TRUE if we have LBA BIOS, FALSE otherwise */ BOOL haveLBA(void) { union REGS r; + struct SREGS sr; r.x.ax = 0x4100; r.x.bx = 0x55AA; r.h.dl = 0x80; - int86(0x13, &r, &r); + sr.ds = 0x40; + /* ds = 40h is to work around a Xi8088 ROM-BIOS bug, + refer to https://github.com/FDOS/kernel/issues/156 + and https://www.bttr-software.de/forum/forum_entry.php?id=21275 */ + int86x(0x13, &r, &r, &sr); return r.x.bx == 0xAA55 && r.x.cx & 1; } #endif From a57aae8846a03f2cdd5fc455efa4a469ec3607e7 Mon Sep 17 00:00:00 2001 From: "E. C. Masloch" Date: Fri, 10 Oct 2025 19:37:23 +0200 Subject: [PATCH 3/3] sys.c: set ds = 40h for 13.41 on Watcom build too --- sys/sys.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/sys.c b/sys/sys.c index fbacbe92..6e79b2da 100644 --- a/sys/sys.c +++ b/sys/sys.c @@ -1293,7 +1293,11 @@ BOOL haveLBA(void); /* return TRUE if we have LBA BIOS, FALSE otherwise */ "mov ax, 0x4100" /* IBM/MS Int 13h Extensions - installation check */ \ "mov bx, 0x55AA" \ "mov dl, 0x80" \ + "push ds" \ + "mov cx, 0x40" \ + "mov ds, cx" \ "int 0x13" \ + "pop ds" \ "xor ax, ax" \ "cmp bx, 0xAA55" \ "jne quit" \