[FREELDR:PC] pcvideo.c: Fix the PcVideoGetDisplayMode() helper for regular video BIOS mode

Fix a regression introduced in commit b050a4544e (PR #8506), when
detecting the initial video mode FreeLoader has been started with.

- In `PcVideoGetDisplayMode()`, for text modes, the number of "bytes per
  scan-line" is always equal to the screen width (number of characters)
  *TIMES* 2: one byte for character, one byte for attribute.

- Systematically reset the `BytesPerScanLine` in each `PcVideoSetModeWWxHH()`
  sub-routine.

- Make `PcVideoGetBiosMode()` return the screen width in characters, and
  compare it with what's stored in the BIOS data area for consistency.
This commit is contained in:
Hermès Bélusca-Maïto
2026-08-07 19:40:17 +02:00
parent dce72d2c5c
commit bd881161ac

View File

@@ -117,7 +117,7 @@ static ULONG VideoCard = VIDEOCARD_CGA_OR_OTHER; /* Type of video card in
static USHORT BiosVideoMode = VIDEOMODE_NORMAL_TEXT; /* Current video mode as known by BIOS */
static ULONG ScreenWidth = 80; /* Screen Width in characters */
static ULONG ScreenHeight = 25; /* Screen Height in characters */
static ULONG BytesPerScanLine = 160; /* Number of bytes per scanline (delta) */
static ULONG BytesPerScanLine = (80 * 2); /* Number of bytes per scanline (delta) */
static VIDEODISPLAYMODE DisplayMode = VideoTextMode; /* Current display mode */
static BOOLEAN VesaVideoMode = FALSE; /* Are we using a VESA mode? */
static SVGA_MODE_INFORMATION VesaVideoModeInformation; /* Only valid when in VESA mode */
@@ -333,7 +333,8 @@ PcVideoVesaGetCurrentSVGAMode(
static BOOLEAN
PcVideoGetBiosMode(
_Out_ PUSHORT Mode)
_Out_ PUSHORT Mode,
_Out_opt_ PUSHORT WidthInChars)
{
REGS Regs;
@@ -375,6 +376,7 @@ PcVideoGetBiosMode(
return FALSE;
*Mode = Regs.b.al;
*WidthInChars = Regs.b.ah;
return TRUE;
}
@@ -382,6 +384,7 @@ static VOID
PcVideoGetDisplayMode(VOID)
{
USHORT Mode = 0;
USHORT WidthInChars;
/* Is the current mode VESA? */
if (PcVideoVesaGetCurrentSVGAMode(&Mode) &&
@@ -396,49 +399,23 @@ PcVideoGetDisplayMode(VOID)
VesaVideoMode = TRUE;
}
/* If not, it should be a regular BIOS mode */
else if (PcVideoGetBiosMode(&Mode))
else if (PcVideoGetBiosMode(&Mode, &WidthInChars))
{
/*
* The BIOS data area 0x400 holds information about the current video mode.
* Infos at: https://web.archive.org/web/20240119203029/http://www.bioscentral.com/misc/bda.htm
* https://stanislavs.org/helppc/bios_data_area.html
* http://www.techhelpmanual.com/93-rom_bios_variables.html
*/
UCHAR BiosMode = (*(PUCHAR)0x449) & 0x7F; /* Current video mode */
ASSERT(BiosMode == Mode);
BiosVideoMode = Mode;
TRACE("BIOS mode detected\n");
ScreenWidth = *(PUSHORT)0x44A; /* Number of screen columns */
ASSERT(ScreenWidth == WidthInChars);
ScreenHeight = 1 + *(PUCHAR)0x484; /* 1 + "Rows on the screen (less 1, EGA+)" */
/*
* Select bits 7 and 4 of "Video display data area (MCGA and VGA)"
* |7|6|5|4|3|2|1|0|
* | `------ see table below
* `--------- alphanumeric scan lines (see table below)
*
* then convert to a number and map it to the scanline number:
* Bit7 Bit4 Scan Lines
* 0 0 350 line mode
* 0 1 400 line mode
* 1 0 200 line mode
* 1 1 reserved
*/
BytesPerScanLine = (*(PUCHAR)0x489) & 0x90;
BytesPerScanLine = ((BytesPerScanLine & 0x80) >> 6) | ((BytesPerScanLine & 0x10) >> 4);
switch (BytesPerScanLine)
{
case VERTRES_200_SCANLINES:
BytesPerScanLine = 200; break;
case VERTRES_350_SCANLINES:
BytesPerScanLine = 350; break;
case VERTRES_400_SCANLINES:
BytesPerScanLine = 400; break;
default:
BytesPerScanLine = 160; break;
}
BytesPerScanLine = (ScreenWidth * 2); /* Text mode: one byte for character, one byte for attribute */
DisplayMode = VideoTextMode;
VesaVideoMode = FALSE;
}
@@ -450,7 +427,7 @@ PcVideoGetDisplayMode(VOID)
BiosVideoMode = VIDEOMODE_NORMAL_TEXT;
ScreenWidth = 80;
ScreenHeight = 25;
BytesPerScanLine = 160;
BytesPerScanLine = (ScreenWidth * 2);
DisplayMode = VideoTextMode;
VesaVideoMode = FALSE;
}
@@ -774,6 +751,7 @@ PcVideoSetMode80x25(VOID)
PcVideoSetBiosMode(0x03);
ScreenWidth = 80;
ScreenHeight = 25;
BytesPerScanLine = (ScreenWidth * 2);
return TRUE;
}
@@ -804,6 +782,7 @@ PcVideoSetMode80x50_80x43(VOID)
{
return FALSE;
}
BytesPerScanLine = (ScreenWidth * 2);
return TRUE;
}
@@ -817,6 +796,7 @@ PcVideoSetMode80x28(VOID)
PcVideoDefineCursor(11, 12);
ScreenWidth = 80;
ScreenHeight = 28;
BytesPerScanLine = (ScreenWidth * 2);
return TRUE;
}
@@ -828,6 +808,7 @@ PcVideoSetMode80x30(VOID)
PcVideoSet480ScanLines();
ScreenWidth = 80;
ScreenHeight = 30;
BytesPerScanLine = (ScreenWidth * 2);
return TRUE;
}
@@ -842,6 +823,7 @@ PcVideoSetMode80x34(VOID)
PcVideoSetDisplayEnd();
ScreenWidth = 80;
ScreenHeight = 34;
BytesPerScanLine = (ScreenWidth * 2);
return TRUE;
}
@@ -857,6 +839,7 @@ PcVideoSetMode80x43(VOID)
PcVideoDefineCursor(6, 7);
ScreenWidth = 80;
ScreenHeight = 43;
BytesPerScanLine = (ScreenWidth * 2);
return TRUE;
}
@@ -873,6 +856,7 @@ PcVideoSetMode80x60(VOID)
PcVideoSetDisplayEnd();
ScreenWidth = 80;
ScreenHeight = 60;
BytesPerScanLine = (ScreenWidth * 2);
return TRUE;
}
@@ -887,7 +871,7 @@ PcVideoSetMode(USHORT NewMode)
BiosVideoMode = NewMode;
ScreenWidth = 80;
ScreenHeight = 25;
BytesPerScanLine = 160;
BytesPerScanLine = (ScreenWidth * 2);
DisplayMode = VideoTextMode;
VesaVideoMode = FALSE;