Author: aandrejevic Date: Sun Jul 3 19:06:33 2016 New Revision: 71803
URL: http://svn.reactos.org/svn/reactos?rev=71803&view=rev Log: [NTVDM] Implement getting/setting the current VESA video mode. Reset the extended SVGA registers when switching to a standard VGA mode.
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.h trunk/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c trunk/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios/... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c [iso-8859-1] Sun Jul 3 19:06:33 2016 @@ -15,6 +15,8 @@
#include "emulator.h" #include "cpu/cpu.h" +#include "bios32p.h" +#include "hardware/video/svga.h"
#include "vbe.h"
@@ -38,7 +40,7 @@ { 0x11, 0x11, NULL /* TODO */, NULL /* VGA */ }, { 0x12, 0x12, NULL /* TODO */, NULL /* VGA */ }, { 0x13, 0x13, NULL /* TODO */, NULL /* VGA */ }, - { 0x14, 0xFFFF, NULL /* TODO */, NULL /* TODO */ }, + { 0x14, 0xFFFF, NULL /* TODO */, NULL }, { 0x54, 0x10A, NULL /* TODO */, NULL /* TODO */ }, { 0x55, 0x109, NULL /* TODO */, NULL /* TODO */ }, { 0x58, 0x102, NULL /* TODO */, NULL /* TODO */ }, @@ -56,16 +58,222 @@ { 0x6C, 0x106, NULL /* TODO */, NULL /* TODO */ }, { 0x6D, 0x107, NULL /* TODO */, NULL /* TODO */ }, { 0x71, 0x112, NULL /* TODO */, NULL /* TODO */ }, - { 0x72, 0xFFFF, NULL /* TODO */, NULL /* TODO */ }, - { 0x73, 0xFFFF, NULL /* TODO */, NULL /* TODO */ }, + { 0x72, 0xFFFF, NULL /* TODO */, NULL }, + { 0x73, 0xFFFF, NULL /* TODO */, NULL }, { 0x74, 0x117, NULL /* TODO */, NULL /* TODO */ }, { 0x75, 0x11A, NULL /* TODO */, NULL /* TODO */ }, - { 0x76, 0xFFFF, NULL /* TODO */, NULL /* TODO */ }, + { 0x76, 0xFFFF, NULL /* TODO */, NULL }, { 0x78, 0x115, NULL /* TODO */, NULL /* TODO */ }, { 0x79, 0x118, NULL /* TODO */, NULL /* TODO */ }, };
+/* PRIVATE FUNCTIONS **********************************************************/ + +PCVBE_MODE VbeGetModeByNumber(WORD Number) +{ + INT i; + + Number &= 0x1FF; + + /* Find the mode */ + for (i = 0; i < VBE_MODE_COUNT; i++) + { + if ((!(Number & 0x100) && (Number == Modes[i].Number)) + || ((Number & 0x100) && (Number== Modes[i].VesaNumber))) + { + return &Modes[i]; + } + } + + return NULL; +} + +/* This function is based on VgaSetRegisters in vidbios.c */ +static VOID VbeSetExtendedRegisters(PSVGA_REGISTERS Registers) +{ + UINT i; + + /* Disable interrupts */ + BOOLEAN Interrupts = getIF(); + setIF(0); + + /* + * Set the CRT base address according to the selected mode, + * monochrome or color. The following macros: + * VGA_INSTAT1_READ, VGA_CRTC_INDEX and VGA_CRTC_DATA are then + * used to access the correct VGA I/O ports. + */ + Bda->CrtBasePort = (Registers->Misc & 0x01) ? VGA_CRTC_INDEX_COLOR + : VGA_CRTC_INDEX_MONO; + /* Bit 1 indicates whether display is color (0) or monochrome (1) */ + Bda->VGAOptions = (Bda->VGAOptions & 0xFD) | (!(Registers->Misc & 0x01) << 1); + Bda->CrtModeControl = (Bda->CrtModeControl & 0xFB) | (!(Registers->Misc & 0x01) << 1); + + /* Update blink bit in BDA */ + if (Registers->Attribute[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_BLINK) + Bda->CrtModeControl |= (1 << 5); + else + Bda->CrtModeControl &= ~(1 << 5); + + /* Turn the video off */ + IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG); + IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) | VGA_SEQ_CLOCK_SD); + + /* Write the misc register */ + IOWriteB(VGA_MISC_WRITE, Registers->Misc); + + /* Synchronous reset on */ + IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG); + IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_AR ); + + /* Write the sequencer registers */ + for (i = 1; i < SVGA_SEQ_MAX_REG; i++) + { + if (i != VGA_SEQ_MAX_REG && i != SVGA_SEQ_UNLOCK_REG) + { + IOWriteB(VGA_SEQ_INDEX, i); + IOWriteB(VGA_SEQ_DATA , Registers->Sequencer[i]); + } + } + + /* Synchronous reset off */ + IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG); + IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_SR | VGA_SEQ_RESET_AR); + + /* Unlock CRTC registers 0-7 */ + IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_HORZ_BLANKING_REG); + IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) | 0x80); + IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_VERT_RETRACE_END_REG); + IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) & ~0x80); + // Make sure they remain unlocked + Registers->CRT[VGA_CRTC_END_HORZ_BLANKING_REG] |= 0x80; + Registers->CRT[VGA_CRTC_VERT_RETRACE_END_REG] &= ~0x80; + + /* Write the CRTC registers */ + for (i = 0; i < SVGA_CRTC_MAX_REG; i++) + { + if ((i < SVGA_CRTC_UNUSED0_REG || i > SVGA_CRTC_UNUSED6_REG) && i != SVGA_CRTC_UNUSED7_REG) + { + IOWriteB(VGA_CRTC_INDEX, i); + IOWriteB(VGA_CRTC_DATA , Registers->CRT[i]); + } + } + + /* Write the GC registers */ + for (i = 0; i < SVGA_GC_MAX_REG; i++) + { + if (i != SVGA_GC_UNUSED0_REG && i != SVGA_GC_UNUSED11_REG + && (i < SVGA_GC_UNUSED1_REG || i > SVGA_GC_UNUSED10_REG)) + { + IOWriteB(VGA_GC_INDEX, i); + IOWriteB(VGA_GC_DATA , Registers->Graphics[i]); + } + } + + /* Write the AC registers */ + for (i = 0; i < VGA_AC_MAX_REG; i++) + { + /* Write the index */ + IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state + IOWriteB(VGA_AC_INDEX, i); + + /* Write the data */ + IOWriteB(VGA_AC_WRITE, Registers->Attribute[i]); + } + + /* Perform 4 dummy reads from the DAC mask to access the hidden register */ + for (i = 0; i < 4; i++) IOReadB(VGA_DAC_MASK); + + /* Set the hidden register */ + IOWriteB(VGA_DAC_MASK, Registers->Hidden); + + /* Set the PEL mask */ + IOWriteB(VGA_DAC_MASK, 0xFF); + + /* Enable screen and disable palette access */ + IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state + IOWriteB(VGA_AC_INDEX, 0x20); + + /* Turn the video on */ + IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG); + IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) & ~VGA_SEQ_CLOCK_SD); + + /* Restore interrupts */ + setIF(Interrupts); +} + + /* PUBLIC FUNCTIONS ***********************************************************/ + +BOOLEAN WINAPI VbeSetExtendedVideoMode(BYTE ModeNumber) +{ + PCVBE_MODE Mode = VbeGetModeByNumber(ModeNumber); + + /* At this point, Mode->Registers shouldn't be NULL unless the mode is unimplemented */ + if (Mode->Registers == NULL) + { + DPRINT1("Extended video mode %02X still UNIMPLEMENTED.\n", ModeNumber); + return FALSE; + } + + /* Set the registers */ + VbeSetExtendedRegisters(Mode->Registers); + + /* Update the current video mode in the BDA */ + Bda->VideoMode = ModeNumber; + + return TRUE; +} + +VOID WINAPI VbeResetExtendedRegisters(VOID) +{ + BYTE i; + + /* Disable interrupts */ + BOOLEAN Interrupts = getIF(); + setIF(0); + + /* Reset the extended sequencer registers */ + for (i = SVGA_SEQ_EXT_MODE_REG; i < SVGA_SEQ_MAX_REG; i++) + { + if (i != VGA_SEQ_MAX_REG && i != SVGA_SEQ_UNLOCK_REG) + { + IOWriteB(VGA_SEQ_INDEX, i); + IOWriteB(VGA_SEQ_DATA, 0x00); + } + } + + /* Reset the extended CRTC registers */ + for (i = SVGA_CRTC_INTERLACE_END_REG; i < SVGA_CRTC_MAX_REG; i++) + { + if ((i < SVGA_CRTC_UNUSED0_REG || i > SVGA_CRTC_UNUSED6_REG) && i != SVGA_CRTC_UNUSED7_REG) + { + IOWriteB(VGA_CRTC_INDEX, i); + IOWriteB(VGA_CRTC_DATA, 0x00); + } + } + + /* Reset the extended GC registers */ + for (i = SVGA_GC_OFFSET_0_REG; i < SVGA_GC_MAX_REG; i++) + { + if (i != SVGA_GC_UNUSED0_REG && i != SVGA_GC_UNUSED11_REG + && (i < SVGA_GC_UNUSED1_REG || i > SVGA_GC_UNUSED10_REG)) + { + IOWriteB(VGA_GC_INDEX, i); + IOWriteB(VGA_GC_DATA, 0x00); + } + } + + /* + * And finally, reset the hidden register. This requires 4 dummy reads from + * the DAC mask register. + */ + for (i = 0; i < 4; i++) IOReadB(VGA_DAC_MASK); + IOWriteB(VGA_DAC_MASK, 0x00); + + /* Restore interrupts */ + setIF(Interrupts); +}
VOID WINAPI VbeService(LPWORD Stack) { @@ -117,36 +325,30 @@ /* Get VBE Mode Information */ case 0x01: { - WORD ModeNumber = getCX() & 0x1FF; + PCVBE_MODE Mode = VbeGetModeByNumber(getCX()); PWORD Data = NULL;
/* Function recognized */ setAL(0x4F);
- /* Find the mode */ - for (i = 0; i < VBE_MODE_COUNT; i++) - { - if ((!(ModeNumber & 0x100) && (ModeNumber == Modes[i].Number)) - || ((ModeNumber & 0x100) && (ModeNumber == Modes[i].VesaNumber))) - { - Data = (PWORD)Modes[i].Info; - - if (Data == NULL) - { - DPRINT1("WARNING: The mode information for mode %02X (%03X) is missing!\n", - Modes[i].Number, - Modes[i].VesaNumber); - } - } - } - - if (Data == NULL) + if (Mode == NULL) { /* Mode not found */ setAH(1); break; }
+ Data = (PWORD)Mode->Info; + if (Data == NULL) + { + DPRINT1("WARNING: The mode information for mode %02X (%03X) is missing!\n", + Mode->Number, + Mode->VesaNumber); + + setAH(1); + break; + } + /* Clear the buffer */ for (i = 0; i < 128; i++) { @@ -160,6 +362,52 @@ }
setAH(0); + break; + } + + /* Set VBE Mode */ + case 0x02: + { + PCVBE_MODE Mode = VbeGetModeByNumber(getBX()); + + if (Mode->Registers == NULL) + { + /* Call the VGA BIOS */ + setAH(0x00); + setAL(Mode->Number); + Int32Call(&BiosContext, BIOS_VIDEO_INTERRUPT); + + setAL(0x4F); + setAH(Bda->VideoMode == Mode->Number); + } + else + { + /* This is an extended video mode */ + setAL(0x4F); + setAH(VbeSetExtendedVideoMode(Mode->Number)); + } + + break; + } + + /* Get Current VBE Mode */ + case 0x03: + { + PCVBE_MODE Mode = VbeGetModeByNumber(Bda->VideoMode); + + setAL(0x4F); + + if (Mode) + { + setBX(Mode->VesaNumber != 0xFFFF + ? Mode->VesaNumber : Mode->Number); + setAH(0); + } + else + { + setAH(1); + } + break; }
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios/... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.h [iso-8859-1] Sun Jul 3 19:06:33 2016 @@ -100,9 +100,13 @@ PSVGA_REGISTERS Registers; // NULL means "forward to VGABIOS" } VBE_MODE, *PVBE_MODE;
+typedef const struct _VBE_MODE *PCVBE_MODE; + /* FUNCTIONS ******************************************************************/
VOID WINAPI VbeService(LPWORD Stack); +VOID WINAPI VbeResetExtendedRegisters(VOID); +BOOLEAN WINAPI VbeSetExtendedVideoMode(BYTE ModeNumber); BOOLEAN VbeInitialize(VOID);
#endif // _VBE_H_
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios/... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c [iso-8859-1] Sun Jul 3 19:06:33 2016 @@ -35,16 +35,6 @@ /**/ #include "../console/video.h" /**/ - -/* MACROS *********************************************************************/ - -// -// These macros are defined for ease-of-use of some VGA I/O ports -// whose addresses depend whether we are in Monochrome or Colour mode. -// -#define VGA_INSTAT1_READ Bda->CrtBasePort + 6 // VGA_INSTAT1_READ_MONO or VGA_INSTAT1_READ_COLOR -#define VGA_CRTC_INDEX Bda->CrtBasePort // VGA_CRTC_INDEX_MONO or VGA_CRTC_INDEX_COLOR -#define VGA_CRTC_DATA Bda->CrtBasePort + 1 // VGA_CRTC_DATA_MONO or VGA_CRTC_DATA_COLOR
/* PRIVATE VARIABLES **********************************************************/
@@ -2470,16 +2460,25 @@ /* Retrieve the real mode number and check its validity */ ModeNumber &= 0x7F; // if (ModeNumber >= ARRAYSIZE(VideoModes)) + + DPRINT1("Switching to mode %02Xh (%02Xh) %s clearing the screen; VgaRegisters = 0x%p\n", + ModeNumber, OrgModeNumber, (DoNotClear ? "without" : "and"), VideoModes[ModeNumber].VgaRegisters); + if (ModeNumber > BIOS_MAX_VIDEO_MODE) { - DPRINT1("VidBiosSetVideoMode -- Mode %02Xh invalid\n", ModeNumber); - return FALSE; + /* This could be an extended video mode, so call the VBE BIOS */ + return VbeSetExtendedVideoMode(ModeNumber); }
- DPRINT1("Switching to mode %02Xh (%02Xh) %s clearing the screen; VgaRegisters = 0x%p\n", - ModeNumber, OrgModeNumber, (DoNotClear ? "without" : "and"), VideoModes[ModeNumber].VgaRegisters); - if (!VgaSetRegisters(VideoModes[ModeNumber].VgaRegisters)) return FALSE; + if (VbeInitialized && Bda->VideoMode > BIOS_MAX_VIDEO_MODE) + { + /* + * Since we're switching from an extended video mode to a standard VGA + * mode, tell the VBE BIOS to reset the extended registers. + */ + VbeResetExtendedRegisters(); + }
VgaChangePalette(ModeNumber);
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios/... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h [iso-8859-1] Sun Jul 3 19:06:33 2016 @@ -104,6 +104,16 @@
#pragma pack(pop)
+/* MACROS *********************************************************************/ + +// +// These macros are defined for ease-of-use of some VGA I/O ports +// whose addresses depend whether we are in Monochrome or Colour mode. +// +#define VGA_INSTAT1_READ Bda->CrtBasePort + 6 // VGA_INSTAT1_READ_MONO or VGA_INSTAT1_READ_COLOR +#define VGA_CRTC_INDEX Bda->CrtBasePort // VGA_CRTC_INDEX_MONO or VGA_CRTC_INDEX_COLOR +#define VGA_CRTC_DATA Bda->CrtBasePort + 1 // VGA_CRTC_DATA_MONO or VGA_CRTC_DATA_COLOR + /* FUNCTIONS ******************************************************************/
VOID WINAPI VidBiosVideoService(LPWORD Stack);