acpi: Use x86 PCI config method directly during startup
Fixes #18778, #19602, #19716, #19948, #20165 The ACPI tables on certain recent-ish Intel platforms read some values from PCI config space during ACPI init. Since we haven't initialized PCI yet during ACPI init, instead of reading from config space, the ACPI bytecode gets garbage values. These values are later used in an address compution. An address compution with garbage values produces a garbage address. That garbage address has certain upper bits set, which causes the corresponding page table entry to have those upper bits set as well (since the page mapping code doesn't sanitize the address). These upper bits being set triggers a page fault due to invalid bits being set in the page table, which we erroneously think is an SMAP violation. Co-authored-by: Augustin Cavalier <[email protected]> Change-Id: If75dffe47ebf3e14831ceac1dfbe492c6a6a6964 Reviewed-on: https://review.haiku-os.org/c/haiku/+/11272 Reviewed-by: waddlesplash <[email protected]> (cherry picked from commit aa519fec255ea2196453b7e62c6f1540efbeefee) Reviewed-on: https://review.haiku-os.org/c/haiku/+/11281
This commit is contained in:
committed by
waddlesplash
parent
46fb8f1ca3
commit
b422ca4d3a
@@ -130,6 +130,10 @@
|
||||
# include <boot_item.h>
|
||||
# include <kernel.h>
|
||||
# include <vm/vm.h>
|
||||
|
||||
# if defined(__i386__) || defined(__x86_64__)
|
||||
# include "../../busses/pci/x86/PCI_x86.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
__BEGIN_DECLS
|
||||
@@ -940,6 +944,33 @@ AcpiOsReadPciConfiguration(ACPI_PCI_ID *pciId, UINT32 reg, UINT64 *value,
|
||||
#ifdef _KERNEL_MODE
|
||||
DEBUG_FUNCTION();
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
// On some x86 machines, ACPI initialization accesses PCI configuration space,
|
||||
// but PCI won't be initialized yet, as ECAM depends on ACPI being initialized.
|
||||
// To break the circular dependency, we access config space directly during early boot.
|
||||
if (gKernelStartup) {
|
||||
if (reg > 0xff)
|
||||
return AE_ERROR;
|
||||
|
||||
out32(PCI_MECH1_REQ_DATA(pciId->Bus, pciId->Device, pciId->Function, reg),
|
||||
PCI_MECH1_REQ_PORT);
|
||||
switch (width / 8) {
|
||||
case 1:
|
||||
*value = in8(PCI_MECH1_DATA_PORT + (reg & 3));
|
||||
break;
|
||||
case 2:
|
||||
*value = in16(PCI_MECH1_DATA_PORT + (reg & 3));
|
||||
break;
|
||||
case 4:
|
||||
*value = in32(PCI_MECH1_DATA_PORT);
|
||||
break;
|
||||
default:
|
||||
return AE_ERROR;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (width) {
|
||||
case 8:
|
||||
case 16:
|
||||
@@ -977,6 +1008,31 @@ AcpiOsWritePciConfiguration(ACPI_PCI_ID *pciId, UINT32 reg,
|
||||
{
|
||||
#ifdef _KERNEL_MODE
|
||||
DEBUG_FUNCTION();
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (gKernelStartup) {
|
||||
if (reg > 0xff)
|
||||
return AE_ERROR;
|
||||
|
||||
out32(PCI_MECH1_REQ_DATA(pciId->Bus, pciId->Device, pciId->Function, reg),
|
||||
PCI_MECH1_REQ_PORT);
|
||||
switch (width / 8) {
|
||||
case 1:
|
||||
out8((uint8)value, (uint16)(PCI_MECH1_DATA_PORT + (reg & 3)));
|
||||
break;
|
||||
case 2:
|
||||
out16((uint16)value, (uint16)(PCI_MECH1_DATA_PORT + (reg & 3)));
|
||||
break;
|
||||
case 4:
|
||||
out32((uint32)value, (uint16)PCI_MECH1_DATA_PORT);
|
||||
break;
|
||||
default:
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
gPCIManager->write_pci_config(
|
||||
pciId->Bus, pciId->Device, pciId->Function, reg, width / 8, value);
|
||||
return AE_OK;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2022-2026, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PCI_X86_H
|
||||
#define PCI_X86_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
#define PCI_MECH1_REQ_PORT 0xCF8
|
||||
#define PCI_MECH1_DATA_PORT 0xCFC
|
||||
#define PCI_MECH1_REQ_DATA(bus, device, func, offset) \
|
||||
(0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (offset & ~3))
|
||||
|
||||
|
||||
#define PCI_MECH2_ENABLE_PORT 0x0cf8
|
||||
#define PCI_MECH2_FORWARD_PORT 0x0cfa
|
||||
#define PCI_MECH2_CONFIG_PORT(dev, offset) \
|
||||
(uint16)(0xC00 | (dev << 8) | offset)
|
||||
|
||||
|
||||
#endif // PCI_X86_H
|
||||
@@ -14,19 +14,10 @@
|
||||
#include <string.h>
|
||||
#include <new>
|
||||
|
||||
|
||||
#define PCI_MECH1_REQ_PORT 0xCF8
|
||||
#define PCI_MECH1_DATA_PORT 0xCFC
|
||||
#define PCI_MECH1_REQ_DATA(bus, device, func, offset) \
|
||||
(0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (offset & ~3))
|
||||
|
||||
#define PCI_MECH2_ENABLE_PORT 0x0cf8
|
||||
#define PCI_MECH2_FORWARD_PORT 0x0cfa
|
||||
#define PCI_MECH2_CONFIG_PORT(dev, offset) \
|
||||
(uint16)(0xC00 | (dev << 8) | offset)
|
||||
#include "PCI_x86.h"
|
||||
|
||||
|
||||
//#pragma mark - driver
|
||||
// #pragma mark - driver
|
||||
|
||||
|
||||
float
|
||||
@@ -247,14 +238,15 @@ X86PCIControllerMeth1::WriteConfig(
|
||||
}
|
||||
|
||||
|
||||
status_t X86PCIControllerMeth1::GetMaxBusDevices(int32& count)
|
||||
status_t
|
||||
X86PCIControllerMeth1::GetMaxBusDevices(int32& count)
|
||||
{
|
||||
count = 32;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
//#pragma mark - X86PCIControllerMeth2
|
||||
// #pragma mark - X86PCIControllerMeth2
|
||||
|
||||
|
||||
status_t
|
||||
@@ -334,14 +326,15 @@ X86PCIControllerMeth2::WriteConfig(
|
||||
}
|
||||
|
||||
|
||||
status_t X86PCIControllerMeth2::GetMaxBusDevices(int32& count)
|
||||
status_t
|
||||
X86PCIControllerMeth2::GetMaxBusDevices(int32& count)
|
||||
{
|
||||
count = 16;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
//#pragma mark - X86PCIControllerMethPcie
|
||||
// #pragma mark - X86PCIControllerMethPcie
|
||||
|
||||
|
||||
status_t
|
||||
|
||||
Reference in New Issue
Block a user