]> git.proxmox.com Git - efi-boot-shim.git/blob - gnu-efi/apps/route80h.c
New upstream version 15.3
[efi-boot-shim.git] / gnu-efi / apps / route80h.c
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 int is_device(EFI_PCI_IO *pciio, uint16_t vendor_id, uint16_t device_id)
44 {
45 lpcif_t lpcif;
46 EFI_STATUS rc;
47
48 rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint16, 0, 2, &lpcif);
49 if (EFI_ERROR(rc))
50 return 0;
51
52 if (vendor_id == lpcif.vendor_id && device_id == lpcif.device_id)
53 return 1;
54 return 0;
55 }
56
57 static EFI_STATUS find_pci_device(uint16_t vendor_id, uint16_t device_id,
58 EFI_PCI_IO **pciio)
59 {
60 EFI_STATUS rc;
61 EFI_HANDLE *Handles;
62 UINTN NoHandles, i;
63
64 if (!pciio)
65 return EFI_INVALID_PARAMETER;
66
67 rc = LibLocateHandle(ByProtocol, &PciIoProtocol, NULL, &NoHandles,
68 &Handles);
69 if (EFI_ERROR(rc))
70 return rc;
71
72 for (i = 0; i < NoHandles; i++) {
73 void *pciio_tmp = NULL;
74 rc = uefi_call_wrapper(BS->OpenProtocol, 6, Handles[i],
75 &PciIoProtocol, &pciio_tmp, ImageHandle,
76 NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
77 if (EFI_ERROR(rc))
78 continue;
79 *pciio = pciio_tmp;
80 if (!is_device(*pciio, vendor_id, device_id)) {
81 *pciio = NULL;
82 continue;
83 }
84
85 return EFI_SUCCESS;
86 }
87 return EFI_NOT_FOUND;
88 }
89
90 EFI_STATUS
91 efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
92 {
93 InitializeLib(image_handle, systab);
94 EFI_PCI_IO *pciio = NULL;
95 lpcif_t lpcif;
96 EFI_STATUS rc = EFI_SUCCESS;
97 struct {
98 uint16_t vendor;
99 uint16_t device;
100 } devices[] = {
101 { VENDOR_ID_INTEL, DEVICE_ID_LPCIF },
102 { VENDOR_ID_INTEL, DEVICE_ID_COUGARPOINT_LPCIF },
103 { 0, 0 }
104 };
105 int i;
106
107 ImageHandle = image_handle;
108 for (i = 0; devices[i].vendor != 0; i++) {
109 rc = find_pci_device(devices[i].vendor, devices[i].device, &pciio);
110 if (EFI_ERROR(rc))
111 continue;
112 }
113
114 if (rc == EFI_NOT_FOUND) {
115 Print(L"Device not found.\n");
116 return rc;
117 } else if (EFI_ERROR(rc)) {
118 return rc;
119 }
120
121 rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint32,
122 EFI_FIELD_OFFSET(lpcif_t, rcba), 1, &lpcif.rcba);
123 if (EFI_ERROR(rc))
124 return rc;
125 if (!(lpcif.rcba & 1)) {
126 Print(L"rcrb is not mapped, cannot route port 80h\n");
127 return EFI_UNSUPPORTED;
128 }
129 lpcif.rcba &= ~1UL;
130
131 Print(L"rcba: 0x%8x\n", lpcif.rcba, lpcif.rcba);
132 set_bit((uint32_t *)(intptr_t)(lpcif.rcba + GCS_OFFSET_ADDR),
133 GCS_RPR_SHIFT, GCS_RPR_PCI);
134
135 return EFI_SUCCESS;
136 }