1#include <efi.h> 2#include <efilib.h> 3 4/* this example program changes the Reserved Page Route (RPR) bit on ICH10's General 5 * Control And Status Register (GCS) from LPC to PCI. In practical terms, it routes 6 * outb to port 80h to the PCI bus. */ 7 8#define GCS_OFFSET_ADDR 0x3410 9#define GCS_RPR_SHIFT 2 10#define GCS_RPR_PCI 1 11#define GCS_RPR_LPC 0 12 13#define VENDOR_ID_INTEL 0x8086 14#define DEVICE_ID_LPCIF 0x3a16 15#define DEVICE_ID_COUGARPOINT_LPCIF 0x1c56 16 17static EFI_HANDLE ImageHandle; 18 19typedef struct { 20 uint16_t vendor_id; /* 00-01 */ 21 uint16_t device_id; /* 02-03 */ 22 char pad[0xEB]; /* 04-EF */ 23 uint32_t rcba; /* F0-F3 */ 24 uint32_t reserved[3]; /* F4-FF */ 25} lpcif_t; 26 27static inline void set_bit(volatile uint32_t *flag, int bit, int value) 28{ 29 uint32_t val = *flag; 30 Print(L"current value is 0x%2x\n", val); 31 32 if (value) { 33 val |= (1 << bit); 34 } else { 35 val &= ~(1 << bit); 36 } 37 Print(L"setting value to 0x%2x\n", val); 38 *flag = val; 39 val = *flag; 40 Print(L"new value is 0x%2x\n", val); 41} 42 43static inline int configspace_matches_ids(void *config, uint32_t vendor_id, 44 uint32_t device_id) 45{ 46 uint32_t *cfg = config; 47 if (cfg[0] == vendor_id && cfg[1] == device_id) 48 return 1; 49 return 0; 50} 51 52static int is_device(EFI_PCI_IO *pciio, uint16_t vendor_id, uint16_t device_id) 53{ 54 lpcif_t lpcif; 55 EFI_STATUS rc; 56 57 rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint16, 0, 2, &lpcif); 58 if (EFI_ERROR(rc)) 59 return 0; 60 61 if (vendor_id == lpcif.vendor_id && device_id == lpcif.device_id) 62 return 1; 63 return 0; 64} 65 66static EFI_STATUS find_pci_device(uint16_t vendor_id, uint16_t device_id, 67 EFI_PCI_IO **pciio) 68{ 69 EFI_STATUS rc; 70 EFI_HANDLE *Handles; 71 UINTN NoHandles; 72 int i; 73 74 if (!pciio) 75 return EFI_INVALID_PARAMETER; 76 77 rc = LibLocateHandle(ByProtocol, &PciIoProtocol, NULL, &NoHandles, 78 &Handles); 79 if (EFI_ERROR(rc)) 80 return rc; 81 82 for (i = 0; i < NoHandles; i++) { 83 void *pciio_tmp = NULL; 84 rc = uefi_call_wrapper(BS->OpenProtocol, 6, Handles[i], 85 &PciIoProtocol, &pciio_tmp, ImageHandle, 86 NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 87 if (EFI_ERROR(rc)) 88 continue; 89 *pciio = pciio_tmp; 90 if (!is_device(*pciio, vendor_id, device_id)) { 91 *pciio = NULL; 92 continue; 93 } 94 95 return EFI_SUCCESS; 96 } 97 return EFI_NOT_FOUND; 98} 99 100EFI_STATUS 101efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab) 102{ 103 InitializeLib(image_handle, systab); 104 EFI_PCI_IO *pciio = NULL; 105 lpcif_t lpcif; 106 EFI_STATUS rc; 107 struct { 108 uint16_t vendor; 109 uint16_t device; 110 } devices[] = { 111 { VENDOR_ID_INTEL, DEVICE_ID_LPCIF }, 112 { VENDOR_ID_INTEL, DEVICE_ID_COUGARPOINT_LPCIF }, 113 { 0, 0 } 114 }; 115 int i; 116 117 ImageHandle = image_handle; 118 for (i = 0; devices[i].vendor != 0; i++) { 119 rc = find_pci_device(devices[i].vendor, devices[i].device, &pciio); 120 if (EFI_ERROR(rc)) 121 continue; 122 } 123 124 if (rc == EFI_NOT_FOUND) { 125 Print(L"Device not found.\n"); 126 return rc; 127 } else if (EFI_ERROR(rc)) { 128 return rc; 129 } 130 131 rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint32, 132 EFI_FIELD_OFFSET(lpcif_t, rcba), 1, &lpcif.rcba); 133 if (EFI_ERROR(rc)) 134 return rc; 135 if (!(lpcif.rcba & 1)) { 136 Print(L"rcrb is not mapped, cannot route port 80h\n"); 137 return EFI_UNSUPPORTED; 138 } 139 lpcif.rcba &= ~1UL; 140 141 Print(L"rcba: 0x%8x\n", lpcif.rcba, lpcif.rcba); 142 set_bit((uint32_t *)(uint64_t)(lpcif.rcba + GCS_OFFSET_ADDR), 143 GCS_RPR_SHIFT, GCS_RPR_PCI); 144 145 return EFI_SUCCESS; 146} 147