vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / bus_managers / pci / arch / x86 / pci_controller.cpp
blob2c1934e5b99ca1f9e385001a18e5be83a42408ab
1 /*
2 * Copyright 2006, Marcus Overhagen. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <KernelExport.h>
8 #include <driver_settings.h>
9 #include <string.h>
11 #include "pci_acpi.h"
12 #include "arch_cpu.h"
13 #include "pci_bios.h"
14 #include "pci_controller.h"
15 #include "pci_irq.h"
16 #include "pci_private.h"
18 #include "acpi.h"
21 #define PCI_MECH1_REQ_PORT 0xCF8
22 #define PCI_MECH1_DATA_PORT 0xCFC
23 #define PCI_MECH1_REQ_DATA(bus, device, func, offset) \
24 (0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (offset & ~3))
26 #define PCI_MECH2_ENABLE_PORT 0x0cf8
27 #define PCI_MECH2_FORWARD_PORT 0x0cfa
28 #define PCI_MECH2_CONFIG_PORT(dev, offset) \
29 (uint16)(0xC00 | (dev << 8) | offset)
31 #define PCI_LOCK_CONFIG(cpu_status) \
32 { \
33 cpu_status = disable_interrupts(); \
34 acquire_spinlock(&sConfigLock); \
37 #define PCI_UNLOCK_CONFIG(cpu_status) \
38 { \
39 release_spinlock(&sConfigLock); \
40 restore_interrupts(cpu_status); \
43 spinlock sConfigLock = B_SPINLOCK_INITIALIZER;
45 static status_t
46 pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
47 uint16 offset, uint8 size, uint32 *value)
49 cpu_status cpu;
50 status_t status = B_OK;
52 if (offset > 0xff)
53 return B_BAD_VALUE;
55 PCI_LOCK_CONFIG(cpu);
56 out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
57 switch (size) {
58 case 1:
59 *value = in8(PCI_MECH1_DATA_PORT + (offset & 3));
60 break;
61 case 2:
62 *value = in16(PCI_MECH1_DATA_PORT + (offset & 3));
63 break;
64 case 4:
65 *value = in32(PCI_MECH1_DATA_PORT);
66 break;
67 default:
68 status = B_ERROR;
69 break;
71 PCI_UNLOCK_CONFIG(cpu);
73 return status;
77 static status_t
78 pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
79 uint16 offset, uint8 size, uint32 value)
81 cpu_status cpu;
82 status_t status = B_OK;
84 if (offset > 0xff)
85 return B_BAD_VALUE;
87 PCI_LOCK_CONFIG(cpu);
88 out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
89 switch (size) {
90 case 1:
91 out8(value, PCI_MECH1_DATA_PORT + (offset & 3));
92 break;
93 case 2:
94 out16(value, PCI_MECH1_DATA_PORT + (offset & 3));
95 break;
96 case 4:
97 out32(value, PCI_MECH1_DATA_PORT);
98 break;
99 default:
100 status = B_ERROR;
101 break;
103 PCI_UNLOCK_CONFIG(cpu);
105 return status;
109 static status_t
110 pci_mech1_get_max_bus_devices(void *cookie, int32 *count)
112 *count = 32;
113 return B_OK;
117 static status_t
118 pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
119 uint16 offset, uint8 size, uint32 *value)
121 cpu_status cpu;
122 status_t status = B_OK;
124 if (offset > 0xff)
125 return B_BAD_VALUE;
127 PCI_LOCK_CONFIG(cpu);
128 out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
129 out8(bus, PCI_MECH2_FORWARD_PORT);
130 switch (size) {
131 case 1:
132 *value = in8(PCI_MECH2_CONFIG_PORT(device, offset));
133 break;
134 case 2:
135 *value = in16(PCI_MECH2_CONFIG_PORT(device, offset));
136 break;
137 case 4:
138 *value = in32(PCI_MECH2_CONFIG_PORT(device, offset));
139 break;
140 default:
141 status = B_ERROR;
142 break;
144 out8(0, PCI_MECH2_ENABLE_PORT);
145 PCI_UNLOCK_CONFIG(cpu);
147 return status;
151 static status_t
152 pci_mech2_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
153 uint16 offset, uint8 size, uint32 value)
155 cpu_status cpu;
156 status_t status = B_OK;
158 if (offset > 0xff)
159 return B_BAD_VALUE;
161 PCI_LOCK_CONFIG(cpu);
162 out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
163 out8(bus, PCI_MECH2_FORWARD_PORT);
164 switch (size) {
165 case 1:
166 out8(value, PCI_MECH2_CONFIG_PORT(device, offset));
167 break;
168 case 2:
169 out16(value, PCI_MECH2_CONFIG_PORT(device, offset));
170 break;
171 case 4:
172 out32(value, PCI_MECH2_CONFIG_PORT(device, offset));
173 break;
174 default:
175 status = B_ERROR;
176 break;
178 out8(0, PCI_MECH2_ENABLE_PORT);
179 PCI_UNLOCK_CONFIG(cpu);
181 return status;
185 static status_t
186 pci_mech2_get_max_bus_devices(void *cookie, int32 *count)
188 *count = 16;
189 return B_OK;
193 addr_t sPCIeBase = 0;
194 uint8 sStartBusNumber;
195 uint8 sEndBusNumber;
196 #define PCIE_VADDR(base, bus, slot, func, reg) ((base) + \
197 ((((bus) & 0xff) << 20) | (((slot) & 0x1f) << 15) | \
198 (((func) & 0x7) << 12) | ((reg) & 0xfff)))
200 static status_t
201 pci_mechpcie_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
202 uint16 offset, uint8 size, uint32 *value)
204 // fallback to mechanism 1 for out of range busses
205 if (bus < sStartBusNumber || bus > sEndBusNumber) {
206 return pci_mech1_read_config(cookie, bus, device, function, offset,
207 size, value);
210 status_t status = B_OK;
212 addr_t address = PCIE_VADDR(sPCIeBase, bus, device, function, offset);
214 switch (size) {
215 case 1:
216 *value = *(uint8*)address;
217 break;
218 case 2:
219 *value = *(uint16*)address;
220 break;
221 case 4:
222 *value = *(uint32*)address;
223 break;
224 default:
225 status = B_ERROR;
226 break;
228 return status;
232 static status_t
233 pci_mechpcie_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
234 uint16 offset, uint8 size, uint32 value)
236 // fallback to mechanism 1 for out of range busses
237 if (bus < sStartBusNumber || bus > sEndBusNumber) {
238 return pci_mech1_write_config(cookie, bus, device, function, offset,
239 size, value);
242 status_t status = B_OK;
244 addr_t address = PCIE_VADDR(sPCIeBase, bus, device, function, offset);
245 switch (size) {
246 case 1:
247 *(uint8*)address = value;
248 break;
249 case 2:
250 *(uint16*)address = value;
251 break;
252 case 4:
253 *(uint32*)address = value;
254 break;
255 default:
256 status = B_ERROR;
257 break;
260 return status;
264 static status_t
265 pci_mechpcie_get_max_bus_devices(void *cookie, int32 *count)
267 *count = 32;
268 return B_OK;
272 phys_addr_t
273 pci_ram_address(phys_addr_t physical_address_in_system_memory)
275 return physical_address_in_system_memory;
279 pci_controller pci_controller_x86_mech1 =
281 pci_mech1_read_config,
282 pci_mech1_write_config,
283 pci_mech1_get_max_bus_devices,
284 pci_x86_irq_read,
285 pci_x86_irq_write,
288 pci_controller pci_controller_x86_mech2 =
290 pci_mech2_read_config,
291 pci_mech2_write_config,
292 pci_mech2_get_max_bus_devices,
293 pci_x86_irq_read,
294 pci_x86_irq_write,
297 pci_controller pci_controller_x86_mechpcie =
299 pci_mechpcie_read_config,
300 pci_mechpcie_write_config,
301 pci_mechpcie_get_max_bus_devices,
302 pci_x86_irq_read,
303 pci_x86_irq_write,
306 pci_controller pci_controller_x86_bios =
308 pci_bios_read_config,
309 pci_bios_write_config,
310 pci_bios_get_max_bus_devices,
311 pci_x86_irq_read,
312 pci_x86_irq_write,
316 status_t
317 pci_controller_init(void)
319 bool search_mech1 = true;
320 bool search_mech2 = true;
321 bool search_mechpcie = true;
322 bool search_bios = true;
323 void *config = NULL;
324 status_t status;
326 status = pci_x86_irq_init();
327 if (status != B_OK)
328 return status;
330 config = load_driver_settings("pci");
331 if (config) {
332 const char *mech = get_driver_parameter(config, "mechanism",
333 NULL, NULL);
334 if (mech) {
335 search_mech1 = search_mech2 = search_mechpcie = search_bios = false;
336 if (strcmp(mech, "1") == 0)
337 search_mech1 = true;
338 else if (strcmp(mech, "2") == 0)
339 search_mech2 = true;
340 else if (strcmp(mech, "pcie") == 0)
341 search_mechpcie = true;
342 else if (strcmp(mech, "bios") == 0)
343 search_bios = true;
344 else
345 panic("Unknown pci config mechanism setting %s\n", mech);
347 unload_driver_settings(config);
350 // TODO: check safemode "don't call the BIOS" setting and unset search_bios!
352 // PCI configuration mechanism PCIe is the preferred one.
353 // If it doesn't work, try mechanism 1.
354 // If it doesn't work, try mechanism 2.
355 // Finally, try to fallback to PCI BIOS
357 if (search_mechpcie) {
358 acpi_init();
359 struct acpi_table_mcfg* mcfg =
360 (struct acpi_table_mcfg*)acpi_find_table("MCFG");
361 if (mcfg != NULL) {
362 struct acpi_mcfg_allocation* end = (struct acpi_mcfg_allocation*)
363 ((char*)mcfg + mcfg->Header.Length);
364 struct acpi_mcfg_allocation* alloc = (struct acpi_mcfg_allocation*)
365 (mcfg + 1);
366 for (; alloc < end; alloc++) {
367 dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: "
368 "%x, end: %x\n", alloc->Address, alloc->PciSegment,
369 alloc->StartBusNumber, alloc->EndBusNumber);
370 if (alloc->PciSegment == 0) {
371 area_id mcfgArea = map_physical_memory("acpi mcfg",
372 alloc->Address, (alloc->EndBusNumber + 1) << 20,
373 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA
374 | B_KERNEL_WRITE_AREA, (void **)&sPCIeBase);
375 if (mcfgArea < 0)
376 break;
377 sStartBusNumber = alloc->StartBusNumber;
378 sEndBusNumber = alloc->EndBusNumber;
379 dprintf("PCI: mechanism pcie controller found\n");
380 return pci_controller_add(&pci_controller_x86_mechpcie,
381 NULL);
387 if (search_mech1) {
388 // check for mechanism 1
389 out32(0x80000000, PCI_MECH1_REQ_PORT);
390 if (0x80000000 == in32(PCI_MECH1_REQ_PORT)) {
391 dprintf("PCI: mechanism 1 controller found\n");
392 return pci_controller_add(&pci_controller_x86_mech1, NULL);
396 if (search_mech2) {
397 // check for mechanism 2
398 out8(0x00, 0xCFB);
399 out8(0x00, 0xCF8);
400 out8(0x00, 0xCFA);
401 if (in8(0xCF8) == 0x00 && in8(0xCFA) == 0x00) {
402 dprintf("PCI: mechanism 2 controller found\n");
403 return pci_controller_add(&pci_controller_x86_mech2, NULL);
407 if (search_bios) {
408 // check for PCI BIOS
409 if (pci_bios_init() == B_OK) {
410 dprintf("PCI: BIOS support found\n");
411 return pci_controller_add(&pci_controller_x86_bios, NULL);
415 dprintf("PCI: no configuration mechanism found\n");
416 return B_ERROR;