1 | /*␊ |
2 | *␊ |
3 | * Copyright 2008 by Islam M. Ahmed Zaid. All rights reserved.␊ |
4 | *␊ |
5 | */␊ |
6 | ␊ |
7 | #include "libsaio.h"␊ |
8 | #include "bootstruct.h"␊ |
9 | #include "pci.h"␊ |
10 | #include "pci_root.h"␊ |
11 | #include "modules.h"␊ |
12 | #include "device_inject.h"␊ |
13 | ␊ |
14 | #ifndef DEBUG_PCI␊ |
15 | #define DEBUG_PCI 0␊ |
16 | #endif␊ |
17 | ␊ |
18 | #if DEBUG_PCI␊ |
19 | #define DBG(x...)␉␉printf(x)␊ |
20 | #else␊ |
21 | #define DBG(x...)␊ |
22 | #endif␊ |
23 | ␊ |
24 | pci_dt_t␉*root_pci_dev;␊ |
25 | static char* dev_path;␉// TODO: Figure out what is going on here...␊ |
26 | ␊ |
27 | ␊ |
28 | uint8_t pci_config_read8(uint32_t pci_addr, uint8_t reg)␊ |
29 | {␊ |
30 | ␉pci_addr |= reg & ~3;␊ |
31 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
32 | ␉return inb(PCI_DATA_REG + (reg & 3));␊ |
33 | }␊ |
34 | ␊ |
35 | uint16_t pci_config_read16(uint32_t pci_addr, uint8_t reg)␊ |
36 | {␊ |
37 | ␉pci_addr |= reg & ~3;␊ |
38 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
39 | ␉return inw(PCI_DATA_REG + (reg & 2));␊ |
40 | }␊ |
41 | ␊ |
42 | uint32_t pci_config_read32(uint32_t pci_addr, uint8_t reg)␊ |
43 | {␊ |
44 | ␉pci_addr |= reg & ~3;␊ |
45 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
46 | ␉return inl(PCI_DATA_REG);␊ |
47 | }␊ |
48 | ␊ |
49 | void pci_config_write8(uint32_t pci_addr, uint8_t reg, uint8_t data)␊ |
50 | {␊ |
51 | ␉pci_addr |= reg & ~3;␊ |
52 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
53 | ␉outb(PCI_DATA_REG + (reg & 3), data);␊ |
54 | }␊ |
55 | ␊ |
56 | void pci_config_write16(uint32_t pci_addr, uint8_t reg, uint16_t data)␊ |
57 | {␊ |
58 | ␉pci_addr |= reg & ~3;␊ |
59 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
60 | ␉outw(PCI_DATA_REG + (reg & 2), data);␊ |
61 | }␊ |
62 | ␊ |
63 | void pci_config_write32(uint32_t pci_addr, uint8_t reg, uint32_t data)␊ |
64 | {␊ |
65 | ␉pci_addr |= reg & ~3;␊ |
66 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
67 | ␉outl(PCI_DATA_REG, data);␊ |
68 | }␊ |
69 | ␊ |
70 | void scan_pci_bus(pci_dt_t *start, uint8_t bus)␊ |
71 | {␊ |
72 | ␉pci_dt_t␉*new;␊ |
73 | ␉pci_dt_t␉**current = &start->children;␊ |
74 | ␉uint32_t␉id;␊ |
75 | ␉uint32_t␉pci_addr;␊ |
76 | ␉uint8_t␉␉dev;␊ |
77 | ␉uint8_t␉␉func;␊ |
78 | ␉uint8_t␉␉secondary_bus;␊ |
79 | ␉uint8_t␉␉header_type;␊ |
80 | ␉␊ |
81 | ␉for (dev = 0; dev < 32; dev++)␊ |
82 | ␉{␊ |
83 | ␉␉for (func = 0; func < 8; func++)␊ |
84 | ␉␉{␊ |
85 | ␉␉␉pci_addr = PCIADDR(bus, dev, func);␊ |
86 | ␉␉␉id = pci_config_read32(pci_addr, PCI_VENDOR_ID);␊ |
87 | ␉␉␉if (!id || id == 0xffffffff)␊ |
88 | ␉␉␉{␊ |
89 | ␉␉␉␉continue;␊ |
90 | ␉␉␉}␊ |
91 | ␉␉␉new = (pci_dt_t*)malloc(sizeof(pci_dt_t));␊ |
92 | if (!new) {␊ |
93 | continue;␊ |
94 | }␊ |
95 | ␉␉␉bzero(new, sizeof(pci_dt_t));␊ |
96 | ␉␉␉new->dev.addr␉= pci_addr;␊ |
97 | ␉␉␉new->vendor_id␉= id & 0xffff;␊ |
98 | ␉␉␉new->device_id␉= (id >> 16) & 0xffff;␊ |
99 | ␉␉␉new->subsys_id.subsys_id␉= pci_config_read32(pci_addr, PCI_SUBSYSTEM_VENDOR_ID);␊ |
100 | ␉␉␉new->class_id␉= pci_config_read16(pci_addr, PCI_CLASS_DEVICE);␊ |
101 | ␉␉␉new->parent␉= start;␊ |
102 | ␉␉␉␊ |
103 | ␉␉␉header_type = pci_config_read8(pci_addr, PCI_HEADER_TYPE);␊ |
104 | ␉␉␉switch (header_type & 0x7f)␊ |
105 | ␉␉␉{␊ |
106 | ␉␉␉␉case PCI_HEADER_TYPE_BRIDGE:␊ |
107 | ␉␉␉␉case PCI_HEADER_TYPE_CARDBUS:␊ |
108 | ␉␉␉␉␉secondary_bus = pci_config_read8(pci_addr, PCI_SECONDARY_BUS);␊ |
109 | ␉␉␉␉␉if (secondary_bus != 0)␊ |
110 | ␉␉␉␉␉{␊ |
111 | ␉␉␉␉␉␉scan_pci_bus(new, secondary_bus);␊ |
112 | ␉␉␉␉␉}␊ |
113 | ␉␉␉␉␉break;␊ |
114 | ␉␉␉␉default:␊ |
115 | ␉␉␉␉␉break;␊ |
116 | ␉␉␉}␊ |
117 | ␉␉␉*current = new;␊ |
118 | ␉␉␉current = &new->next;␊ |
119 | ␉␉␉␊ |
120 | ␉␉␉if ((func == 0) && ((header_type & 0x80) == 0))␊ |
121 | ␉␉␉{␊ |
122 | ␉␉␉␉break;␊ |
123 | ␉␉␉}␊ |
124 | ␉␉}␊ |
125 | ␉}␊ |
126 | }␊ |
127 | ␊ |
128 | void enable_pci_devs(void)␊ |
129 | {␊ |
130 | ␉uint16_t id;␊ |
131 | ␉uint32_t rcba, *fd;␊ |
132 | ␉␊ |
133 | ␉id = pci_config_read16(PCIADDR(0, 0x00, 0), 0x00);␊ |
134 | ␉/* make sure we're on Intel chipset */␊ |
135 | ␉if (id != 0x8086)␊ |
136 | ␉␉return;␊ |
137 | ␉rcba = pci_config_read32(PCIADDR(0, 0x1f, 0), 0xf0) & ~1;␊ |
138 | ␉fd = (uint32_t *)(rcba + 0x3418);␊ |
139 | ␉/* set SMBus Disable (SD) to 0 */␊ |
140 | ␉*fd &= ~0x8;␊ |
141 | ␉/* and all devices? */␊ |
142 | ␉//*fd = 0x1;␊ |
143 | }␊ |
144 | ␊ |
145 | ␊ |
146 | void build_pci_dt(void)␊ |
147 | {␊ |
148 | ␉dev_path = malloc(sizeof(char) * 256);␉// TODO: remove␊ |
149 | ␉␊ |
150 | ␉root_pci_dev = malloc(sizeof(pci_dt_t));␊ |
151 | ␊ |
152 | if (!dev_path || !root_pci_dev) {␊ |
153 | stop("Couldn't allocate memory for the pci root device\n");␊ |
154 | return ;␊ |
155 | }␊ |
156 | ␉bzero(root_pci_dev, sizeof(pci_dt_t));␊ |
157 | ␉enable_pci_devs();␊ |
158 | ␉scan_pci_bus(root_pci_dev, 0);␊ |
159 | #if DEBUG_PCI␊ |
160 | #ifndef OPTION_ROM␊ |
161 | ␉dump_pci_dt(root_pci_dev->children);␊ |
162 | ␉pause();␊ |
163 | #endif␊ |
164 | #endif␊ |
165 | }␊ |
166 | ␊ |
167 | #if 0␊ |
168 | char *get_pci_dev_path(pci_dt_t *pci_dt)␊ |
169 | {␊ |
170 | ␉char* buffer = malloc(sizeof(char) * 256);␊ |
171 | ␉␊ |
172 | if (!buffer) {␊ |
173 | return NULL;␊ |
174 | }␊ |
175 | ␊ |
176 | ␉pci_dt_t␉*current;␊ |
177 | ␉pci_dt_t␉*end;␊ |
178 | ␉char␉␉tmp[64];␊ |
179 | ␉␊ |
180 | ␉buffer[0] = 0;␉␊ |
181 | ␉end = root_pci_dev;␊ |
182 | ␉␊ |
183 | ␉int uid = getPciRootUID();␊ |
184 | ␉while (end != pci_dt)␊ |
185 | ␉{␊ |
186 | ␉␉current = pci_dt;␊ |
187 | ␉␉while (current->parent != end)␊ |
188 | ␉␉␉current = current->parent;␉␉␉␊ |
189 | ␉␉end = current;␊ |
190 | ␉␉if (current->parent == root_pci_dev)␊ |
191 | ␉␉{␊ |
192 | ␉␉␉sprintf(tmp, "PciRoot(0x%x)/Pci(0x%x,0x%x)", uid, ␊ |
193 | ␉␉␉␉␉current->dev.bits.dev, current->dev.bits.func);␊ |
194 | ␉␉} ␊ |
195 | ␉␉else ␊ |
196 | ␉␉{␊ |
197 | ␉␉␉sprintf(tmp, "/Pci(0x%x,0x%x)", ␊ |
198 | ␉␉␉␉␉current->dev.bits.dev, current->dev.bits.func);␊ |
199 | ␉␉}␊ |
200 | ␉␉sprintf(buffer, "%s%s", buffer, tmp);␊ |
201 | ␉}␊ |
202 | ␉return buffer;␊ |
203 | }␊ |
204 | #endif␊ |
205 | ␊ |
206 | void setup_pci_devs(pci_dt_t *pci_dt)␊ |
207 | {␊ |
208 | ␉pci_dt_t *current = pci_dt;␊ |
209 | ␉␊ |
210 | ␉while (current)␊ |
211 | ␉{␉␉␊ |
212 | ␉␉execute_hook("PCIDevice", (void*)current, NULL, NULL, NULL, NULL, NULL);␊ |
213 | ␉␉␊ |
214 | ␉␉setup_pci_devs(current->children);␊ |
215 | ␉␉current = current->next;␊ |
216 | ␉}␊ |
217 | }␊ |
218 | ␊ |
219 | #ifndef OPTION_ROM␊ |
220 | void dump_pci_dt(pci_dt_t *pci_dt)␊ |
221 | {␊ |
222 | ␉pci_dt_t␉*current;␊ |
223 | ␉␊ |
224 | ␉current = pci_dt;␊ |
225 | ␉while (current) ␊ |
226 | ␉{␊ |
227 | ␉␉printf("%02x:%02x.%x [%04x] [%04x:%04x] \n", ␊ |
228 | ␉␉␉ current->dev.bits.bus, current->dev.bits.dev, current->dev.bits.func, ␊ |
229 | ␉␉␉ current->class_id, current->vendor_id, current->device_id);␊ |
230 | ␉␉dump_pci_dt(current->children);␊ |
231 | ␉␉current = current->next;␊ |
232 | ␉}␊ |
233 | }␊ |
234 | #endif␊ |
235 | |