Skip to content

Commit ad5b233

Browse files
fix: select default drive
1 parent 4e3872d commit ad5b233

2 files changed

Lines changed: 85 additions & 6 deletions

File tree

src/Spice86.Core/Emulator/InterruptHandlers/Dos/DosInt21Handler.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,16 +1721,19 @@ public override void Run() {
17211721
/// The number of potentially valid drive letters in AL.
17221722
/// </returns>
17231723
public void SelectDefaultDrive() {
1724-
if (_dosDriveManager.TryGetValue(DosDriveManager.DriveLetters.ElementAtOrDefault(State.DL).Key, out VirtualDrive? mountedDrive)) {
1725-
_dosDriveManager.CurrentDrive = mountedDrive;
1726-
}
1727-
if (State.DL > DosDriveManager.MaxDriveCount && LoggerService.IsEnabled(LogEventLevel.Error)) {
1728-
LoggerService.Error("DOS INT21H: Could not set default drive! Unrecognized index in State.DL: {DriveIndex}", State.DL);
1724+
byte driveIndex = State.DL;
1725+
if (driveIndex < DosDriveManager.MaxDriveCount) {
1726+
char driveLetter = (char)('A' + driveIndex);
1727+
if (_dosDriveManager.TryGetValue(driveLetter, out VirtualDrive? mountedDrive)) {
1728+
_dosDriveManager.CurrentDrive = mountedDrive;
1729+
}
1730+
} else if (LoggerService.IsEnabled(LogEventLevel.Error)) {
1731+
LoggerService.Error("DOS INT21H: Could not set default drive! Unrecognized index in State.DL: {DriveIndex}", driveIndex);
17291732
}
17301733
if (LoggerService.IsEnabled(LogEventLevel.Verbose)) {
17311734
LoggerService.Verbose("SELECT DEFAULT DRIVE {@DefaultDrive}", _dosDriveManager.CurrentDrive);
17321735
}
1733-
State.AL = _dosDriveManager.NumberOfPotentiallyValidDriveLetters;
1736+
State.AL = DosDriveManager.MaxDriveCount;
17341737
}
17351738

17361739
/// <summary>

tests/Spice86.Tests/Dos/DosInt21IntegrationTests.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,82 @@ public void StandardFileHandles_AreInheritedFromParentPsp() {
925925
testHandler.Results.Should().NotContain((byte)TestResult.Failure);
926926
}
927927

928+
/// <summary>
929+
/// Tests INT 21h AH=0Eh (Select Default Drive).
930+
/// Bug 1: DL=2 (C:) should return AL=26 (total drive count), not the mounted count (3).
931+
/// Bug 2: DL >= 26 is invalid but the comparison used > instead of >=, so DL=26 was accepted.
932+
/// Bug 3: ElementAtOrDefault on DriveLetters with an out-of-range index could silently pass
933+
/// a default '\0' key to TryGetValue instead of rejecting the drive index.
934+
/// </summary>
935+
[Fact]
936+
public void SelectDefaultDrive_WithValidDrive_ReturnsMaxDriveCountAndSwitchesDrive() {
937+
// Test plan:
938+
// 1. Select C: (DL=2) via AH=0Eh → AL must be 26
939+
// 2. Read current drive via AH=19h → AL must be 2 (C:)
940+
// 3. Select invalid drive (DL=26) via AH=0Eh → drive must remain C:
941+
// 4. Read current drive again via AH=19h → AL must still be 2
942+
byte[] program = new byte[] {
943+
// --- Part 1: Select C: drive (DL=2) ---
944+
0xB4, 0x0E, // mov ah, 0Eh - Select Default Drive
945+
0xB2, 0x02, // mov dl, 02h - C: drive index
946+
0xCD, 0x21, // int 21h - AL = number of drives
947+
948+
// Write AL to details port so we can inspect the value
949+
0xBA, 0x98, 0x09, // mov dx, DetailsPort (0x998)
950+
0xEE, // out dx, al
951+
952+
// Check AL == 26 (0x1A)
953+
0x3C, 0x1A, // cmp al, 1Ah
954+
0x75, 0x22, // jne failed (offset 14 -> 48 = +34)
955+
956+
// --- Part 2: Verify current drive is C: ---
957+
0xB4, 0x19, // mov ah, 19h - Get Current Drive
958+
0xCD, 0x21, // int 21h - AL = current drive (0=A, 1=B, 2=C)
959+
960+
// Write AL to details port
961+
0xBA, 0x98, 0x09, // mov dx, DetailsPort
962+
0xEE, // out dx, al
963+
964+
// Check AL == 2 (C:)
965+
0x3C, 0x02, // cmp al, 02h
966+
0x75, 0x16, // jne failed (offset 26 -> 48 = +22)
967+
968+
// --- Part 3: Select invalid drive (DL=26, out of range) ---
969+
0xB4, 0x0E, // mov ah, 0Eh
970+
0xB2, 0x1A, // mov dl, 1Ah - index 26 (invalid)
971+
0xCD, 0x21, // int 21h
972+
973+
// --- Part 4: Verify current drive is still C: ---
974+
0xB4, 0x19, // mov ah, 19h - Get Current Drive
975+
0xCD, 0x21, // int 21h
976+
977+
// Write AL to details port
978+
0xBA, 0x98, 0x09, // mov dx, DetailsPort
979+
0xEE, // out dx, al
980+
981+
// Check AL == 2 (C: unchanged)
982+
0x3C, 0x02, // cmp al, 02h
983+
0x75, 0x04, // jne failed
984+
985+
// Success
986+
0xB0, 0x00, // mov al, TestResult.Success
987+
0xEB, 0x02, // jmp writeResult
988+
989+
// failed:
990+
0xB0, 0xFF, // mov al, TestResult.Failure
991+
992+
// writeResult:
993+
0xBA, 0x99, 0x09, // mov dx, ResultPort
994+
0xEE, // out dx, al
995+
0xF4 // hlt
996+
};
997+
998+
DosTestHandler testHandler = RunDosTest(program);
999+
1000+
testHandler.Results.Should().Contain((byte)TestResult.Success);
1001+
testHandler.Results.Should().NotContain((byte)TestResult.Failure);
1002+
}
1003+
9281004
/// <summary>
9291005
/// Runs the DOS test program and returns a test handler with results
9301006
/// </summary>

0 commit comments

Comments
 (0)