From 61b347a766d9e2f85fcbca96b535b9fdffe7fe8b Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Mon, 26 Jul 2010 17:04:12 -0400 Subject: [PATCH 2/7] Add the "route80h.efi" test program. This is a test program for PciIo. It routes port80h on ICH10 to PCI. --- apps/Makefile | 2 +- apps/route80h.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 apps/route80h.c diff --git a/apps/Makefile b/apps/Makefile index 1e43821..6bda7ea 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -58,7 +58,7 @@ LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L../lib -L../gnuefi $(CRTOBJS) LOADLIBES = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name) FORMAT = efi-app-$(ARCH) -TARGETS = t.efi t2.efi t3.efi t4.efi t5.efi t6.efi printenv.efi t7.efi tcc.efi +TARGETS = t.efi t2.efi t3.efi t4.efi t5.efi t6.efi printenv.efi t7.efi tcc.efi route80h.efi all: $(TARGETS) diff --git a/apps/route80h.c b/apps/route80h.c new file mode 100644 index 0000000..1a04b5a --- /dev/null +++ b/apps/route80h.c @@ -0,0 +1,125 @@ +#include +#include + +/* this example program changes the Reserved Page Route (RPR) bit on ICH10's General + * Control And Status Register (GCS) from LPC to PCI. In practical terms, it routes + * outb to port 80h to the PCI bus. */ + +#define GCS_OFFSET_ADDR 0x3410 +#define GCS_RPR_SHIFT 2 +#define GCS_RPR_PCI 1 +#define GCS_RPR_LPC 0 + +#define VENDOR_ID_INTEL 0x8086 +#define DEVICE_ID_LPCIF 0x3a16 + +static EFI_HANDLE ImageHandle; + +typedef struct { + uint16_t vendor_id; /* 00-01 */ + uint16_t device_id; /* 02-03 */ + char pad[0xEB]; /* 04-EF */ + uint32_t rcba; /* F0-F3 */ + uint32_t reserved[3]; /* F4-FF */ +} lpcif_t; + +static inline void set_bit(volatile uint32_t *flag, int bit, int value) +{ + uint32_t val = *flag; + Print(L"current value is 0x%2x\n", val); + + if (value) { + val |= (1 << bit); + } else { + val &= ~(1 << bit); + } + Print(L"setting value to 0x%2x\n", val); + *flag = val; + val = *flag; + Print(L"new value is 0x%2x\n", val); +} + +static inline int configspace_matches_ids(void *config, uint32_t vendor_id, + uint32_t device_id) +{ + uint32_t *cfg = config; + if (cfg[0] == vendor_id && cfg[1] == device_id) + return 1; + return 0; +} + +static int is_device(EFI_PCI_IO *pciio, uint16_t vendor_id, uint16_t device_id) +{ + lpcif_t lpcif; + EFI_STATUS rc; + + rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint16, 0, 2, &lpcif); + if (EFI_ERROR(rc)) + return 0; + + if (vendor_id == lpcif.vendor_id && device_id == lpcif.device_id) + return 1; + return 0; +} + +static EFI_STATUS find_pci_device(uint16_t vendor_id, uint16_t device_id, + EFI_PCI_IO **pciio) +{ + EFI_STATUS rc; + EFI_HANDLE *Handles; + UINTN NoHandles; + int i; + + rc = LibLocateHandle(ByProtocol, &PciIoProtocol, NULL, &NoHandles, + &Handles); + if (EFI_ERROR(rc)) + return rc; + + for (i = 0; i < NoHandles; i++) { + rc = uefi_call_wrapper(BS->OpenProtocol, 6, Handles[i], + &PciIoProtocol, pciio, ImageHandle, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(rc)) + continue; + if (!is_device(*pciio, vendor_id, device_id)) + continue; + + return EFI_SUCCESS; + } + return EFI_NOT_FOUND; +} + +EFI_STATUS +efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab) +{ + InitializeLib(image_handle, systab); + EFI_PCI_IO *pciio; + lpcif_t lpcif; + EFI_STATUS rc; + + ImageHandle = image_handle; + rc = find_pci_device(VENDOR_ID_INTEL, DEVICE_ID_LPCIF, &pciio); + + if (rc == EFI_NOT_FOUND) { + Print(L"Device not found.\n"); + return rc; + } else if (EFI_ERROR(rc)) { + return rc; + } + + rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint32, + EFI_FIELD_OFFSET(lpcif_t, rcba), 1, &lpcif.rcba); + if (EFI_ERROR(rc)) + return rc; + if (!(lpcif.rcba & 1)) { + Print(L"rcrb is not mapped, cannot route port 80h\n"); + return EFI_UNSUPPORTED; + } + lpcif.rcba &= ~1UL; + + Print(L"rcba: 0x%8x\n", lpcif.rcba, lpcif.rcba); + set_bit((uint32_t *)(lpcif.rcba + GCS_OFFSET_ADDR), + GCS_RPR_SHIFT, GCS_RPR_PCI); + + return EFI_SUCCESS; +} -- 1.7.10.4