From 040c742caccb9122f7cd1675c635171cf1add49a Mon Sep 17 00:00:00 2001 From: ReactOS Portable Systems Group Date: Fri, 1 Jan 2010 00:03:52 +0000 Subject: [PATCH] NMI Support Patch 3: [HAL]: If the current TSS does not have enough space for an I/O Privilege Map then "borrow" the default TSS while the BIOS Call is in-flight. "Return" it when the BIOS call has ended. Fixes panics during a double fault (since the double fault handler will attempt to clear the display through a Video ROM BIOS Interrupt 10h). Allows NMI panics to do BIOS calls as well (for later). svn path=/trunk/; revision=44843 --- reactos/hal/halx86/generic/bios.c | 101 +++++++++++++++++++++++++++++- reactos/hal/halx86/include/halp.h | 12 ---- 2 files changed, 100 insertions(+), 13 deletions(-) diff --git a/reactos/hal/halx86/generic/bios.c b/reactos/hal/halx86/generic/bios.c index c0e4c2a31f5..cced7d43352 100644 --- a/reactos/hal/halx86/generic/bios.c +++ b/reactos/hal/halx86/generic/bios.c @@ -19,6 +19,7 @@ HARDWARE_PTE HalpSavedPte; ULONG HalpGpfHandler; ULONG HalpBopHandler; ULONG HalpSavedEsp0; +USHORT HalpSavedTss; USHORT HalpSavedIopmBase; PUSHORT HalpSavedIoMap; USHORT HalpSavedIoMapData[32][2]; @@ -29,6 +30,98 @@ ULONG HalpSavedIoMapEntries; /* FUNCTIONS ******************************************************************/ +VOID +NTAPI +HalpBorrowTss(VOID) +{ + USHORT Tss; + PKGDTENTRY TssGdt; + ULONG_PTR TssLimit; + PKTSS TssBase; + + // + // Get the current TSS and its GDT entry + // + Tss = Ke386GetTr(); + TssGdt = &((PKIPCR)KeGetPcr())->GDT[Tss / sizeof(KGDTENTRY)]; + + // + // Get the KTSS limit and check if it has IOPM space + // + TssLimit = TssGdt->LimitLow | TssGdt->HighWord.Bits.LimitHi << 16; + + // + // If the KTSS doesn't have enough space this is probably an NMI or DF + // + if (TssLimit > IOPM_SIZE) + { + // + // We are good to go + // + HalpSavedTss = 0; + return; + } + + // + // Get the "real" TSS + // + TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / sizeof(KGDTENTRY)]; + TssBase = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | + TssGdt->HighWord.Bytes.BaseMid << 16 | + TssGdt->HighWord.Bytes.BaseHi << 24); + + // + // Switch to it + // + KeGetPcr()->TSS = TssBase; + + // + // Set it up + // + TssGdt->HighWord.Bits.Type = I386_TSS; + TssGdt->HighWord.Bits.Pres = 1; + TssGdt->HighWord.Bits.Dpl = 0; + + // + // Load new TSS and return old one + // + Ke386SetTr(KGDT_TSS); + HalpSavedTss = Tss; +} + +VOID +NTAPI +HalpReturnTss(VOID) +{ + PKGDTENTRY TssGdt; + PKTSS TssBase; + + // + // Get the original TSS + // + TssGdt = &((PKIPCR)KeGetPcr())->GDT[HalpSavedTss / sizeof(KGDTENTRY)]; + TssBase = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | + TssGdt->HighWord.Bytes.BaseMid << 16 | + TssGdt->HighWord.Bytes.BaseHi << 24); + + // + // Switch to it + // + KeGetPcr()->TSS = TssBase; + + // + // Set it up + // + TssGdt->HighWord.Bits.Type = I386_TSS; + TssGdt->HighWord.Bits.Pres = 1; + TssGdt->HighWord.Bits.Dpl = 0; + + // + // Load old TSS + // + Ke386SetTr(HalpSavedTss); +} + VOID NTAPI HalpStoreAndClearIopm(VOID) @@ -168,6 +261,9 @@ VOID NTAPI HalpSetupRealModeIoPermissionsAndTask(VOID) { + /* Switch to valid TSS */ + HalpBorrowTss(); + /* Save a copy of the I/O Map and delete it */ HalpSavedIoMap = (PUSHORT)&(KeGetPcr()->TSS->IoMaps[0]); HalpStoreAndClearIopm(); @@ -204,7 +300,10 @@ HalpRestoreIoPermissionsAndTask(VOID) HalpRestoreIopm(); /* Restore the IOPM */ - KeGetPcr()->TSS->IoMapBase = HalpSavedIopmBase; + KeGetPcr()->TSS->IoMapBase = HalpSavedIopmBase; + + /* Restore the TSS */ + if (HalpSavedTss) HalpReturnTss(); } VOID diff --git a/reactos/hal/halx86/include/halp.h b/reactos/hal/halx86/include/halp.h index 198842a648c..6e98111cbe0 100644 --- a/reactos/hal/halx86/include/halp.h +++ b/reactos/hal/halx86/include/halp.h @@ -172,18 +172,6 @@ HalpBiosDisplayReset( VOID ); -ULONG -NTAPI -HalpBorrowTss( - VOID -); - -ULONG -NTAPI -HalpReturnTss( - ULONG SavedTss -); - VOID NTAPI HalpBiosCall(