[e16e8f2] | 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 | |
---|
| 17 | static EFI_HANDLE ImageHandle; |
---|
| 18 | |
---|
| 19 | typedef 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 | |
---|
| 27 | static 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 | |
---|
| 43 | static 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 | |
---|
| 52 | static 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 | |
---|
| 66 | static 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 | |
---|
| 100 | EFI_STATUS |
---|
| 101 | efi_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 | } |
---|