vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / bus_managers / pci / arch / ppc / openfirmware / uninorth.cpp
blob7997129f799901491f1b0a75ee163b2024137597
1 /*
2 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5 /*-
6 * Copyright (C) 2002 Benno Rice.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * $FreeBSD$
32 #include <stdlib.h>
33 #include <string.h>
35 #include <KernelExport.h>
37 #include <platform/openfirmware/devices.h>
38 #include <platform/openfirmware/openfirmware.h>
39 #include <platform/openfirmware/pci.h>
41 #include "pci_controller.h"
42 #include "pci_io.h"
43 #include "pci_openfirmware_priv.h"
46 struct uninorth_range {
47 uint32 pci_hi;
48 uint32 pci_mid;
49 uint32 pci_lo;
50 uint32 host;
51 uint32 size_hi;
52 uint32 size_lo;
55 struct uninorth_host_bridge {
56 int device_node;
57 addr_t address_registers;
58 addr_t data_registers;
59 uint32 bus;
60 struct uninorth_range ranges[6];
61 int range_count;
65 #define out8rb(address, value) ppc_out8((vuint8*)(address), value)
66 #define out16rb(address, value) ppc_out16_reverse((vuint16*)(address), value)
67 #define out32rb(address, value) ppc_out32_reverse((vuint32*)(address), value)
68 #define in8rb(address) ppc_in8((const vuint8*)(address))
69 #define in16rb(address) ppc_in16_reverse((const vuint16*)(address))
70 #define in32rb(address) ppc_in32_reverse((const vuint32*)(address))
73 static int uninorth_enable_config(struct uninorth_host_bridge *bridge,
74 uint8 bus, uint8 slot, uint8 function, uint8 offset);
76 static status_t uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device,
77 uint8 function, uint16 offset, uint8 size, uint32 *value);
78 static status_t uninorth_write_pci_config(void *cookie, uint8 bus,
79 uint8 device, uint8 function, uint16 offset, uint8 size,
80 uint32 value);
81 static status_t uninorth_get_max_bus_devices(void *cookie, int32 *count);
82 static status_t uninorth_read_pci_irq(void *cookie, uint8 bus, uint8 device,
83 uint8 function, uint8 pin, uint8 *irq);
84 static status_t uninorth_write_pci_irq(void *cookie, uint8 bus, uint8 device,
85 uint8 function, uint8 pin, uint8 irq);
87 static pci_controller sUniNorthPCIController = {
88 uninorth_read_pci_config,
89 uninorth_write_pci_config,
90 uninorth_get_max_bus_devices,
91 uninorth_read_pci_irq,
92 uninorth_write_pci_irq,
96 static status_t
97 uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
98 uint16 offset, uint8 size, uint32 *value)
100 uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie;
102 if (offset > 0xff)
103 return B_BAD_VALUE;
105 addr_t caoff = bridge->data_registers + (offset & 0x07);
107 if (uninorth_enable_config(bridge, bus, device, function, offset) != 0) {
108 switch (size) {
109 case 1:
110 *value = in8rb(caoff);
111 break;
112 case 2:
113 *value = in16rb(caoff);
114 break;
115 case 4:
116 *value = in32rb(caoff);
117 break;
118 default:
119 *value = 0xffffffff;
120 break;
122 } else
123 *value = 0xffffffff;
125 return B_OK;
129 static status_t uninorth_write_pci_config(void *cookie, uint8 bus, uint8 device,
130 uint8 function, uint16 offset, uint8 size, uint32 value)
132 uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie;
134 if (offset > 0xff)
135 return B_BAD_VALUE;
137 addr_t caoff = bridge->data_registers + (offset & 0x07);
139 if (uninorth_enable_config(bridge, bus, device, function, offset)) {
140 switch (size) {
141 case 1:
142 out8rb(caoff, (uint8)value);
143 (void)in8rb(caoff);
144 break;
145 case 2:
146 out16rb(caoff, (uint16)value);
147 (void)in16rb(caoff);
148 break;
149 case 4:
150 out32rb(caoff, value);
151 (void)in32rb(caoff);
152 break;
156 return B_OK;
160 static status_t uninorth_get_max_bus_devices(void *cookie, int32 *count)
162 *count = 32;
163 return B_OK;
167 static status_t uninorth_read_pci_irq(void *cookie, uint8 bus, uint8 device,
168 uint8 function, uint8 pin, uint8 *irq)
170 return B_ERROR;
174 static status_t uninorth_write_pci_irq(void *cookie, uint8 bus, uint8 device,
175 uint8 function, uint8 pin, uint8 irq)
177 return B_ERROR;
181 // #pragma mark -
184 static int
185 uninorth_enable_config(struct uninorth_host_bridge *bridge, uint8 bus,
186 uint8 slot, uint8 function, uint8 offset)
188 // uint32 pass;
189 // if (resource_int_value(device_get_name(sc->sc_dev),
190 // device_get_unit(sc->sc_dev), "skipslot", &pass) == 0) {
191 // if (pass == slot)
192 // return (0);
193 // }
195 uint32 cfgval;
196 if (bridge->bus == bus) {
198 * No slots less than 11 on the primary bus
200 if (slot < 11)
201 return (0);
203 cfgval = (1 << slot) | (function << 8) | (offset & 0xfc);
204 } else {
205 cfgval = (bus << 16) | (slot << 11) | (function << 8) |
206 (offset & 0xfc) | 1;
209 do {
210 out32rb(bridge->address_registers, cfgval);
211 } while (in32rb(bridge->address_registers) != cfgval);
213 return (1);
217 // #pragma mark -
219 status_t
220 ppc_openfirmware_probe_uninorth(int deviceNode,
221 const StringArrayPropertyValue &compatibleValue)
223 if (!compatibleValue.ContainsElement("uni-north"))
224 return B_ERROR;
226 uint32 reg[2];
227 if (of_getprop(deviceNode, "reg", reg, sizeof(reg)) < 8)
228 return B_ERROR;
230 uint32 busrange[2];
231 if (of_getprop(deviceNode, "bus-range", busrange, sizeof(busrange)) != 8)
232 return B_ERROR;
234 uninorth_host_bridge *bridge
235 = (uninorth_host_bridge*)malloc(sizeof(uninorth_host_bridge));
236 if (!bridge)
237 return B_NO_MEMORY;
239 bridge->device_node = deviceNode;
240 bridge->address_registers = reg[0] + 0x800000;
241 bridge->data_registers = reg[0] + 0xc00000;
242 bridge->bus = busrange[0];
243 // TODO: Check whether address and data registers have already been mapped by
244 // the Open Firmware. If not, map them ourselves.
246 memset(bridge->ranges, 0, sizeof(bridge->ranges));
247 int bytesRead = of_getprop(deviceNode, "ranges", bridge->ranges,
248 sizeof(bridge->ranges));
250 if (bytesRead < 0) {
251 dprintf("ppc_openfirmware_probe_uninorth: Could not get ranges.\n");
252 free(bridge);
253 return B_ERROR;
255 bridge->range_count = bytesRead / sizeof(uninorth_range);
257 uninorth_range *ioRange = NULL;
258 uninorth_range *memoryRanges[2];
259 int memoryRangeCount = 0;
261 for (int i = 0; i < bridge->range_count; i++) {
262 uninorth_range *range = bridge->ranges + i;
263 switch (range->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
264 case OFW_PCI_PHYS_HI_SPACE_CONFIG:
265 break;
266 case OFW_PCI_PHYS_HI_SPACE_IO:
267 ioRange = range;
268 break;
269 case OFW_PCI_PHYS_HI_SPACE_MEM32:
270 memoryRanges[memoryRangeCount++] = range;
271 break;
272 case OFW_PCI_PHYS_HI_SPACE_MEM64:
273 break;
277 if (ioRange == NULL) {
278 dprintf("ppc_openfirmware_probe_uninorth: Can't find io range.\n");
279 free(bridge);
280 return B_ERROR;
283 if (memoryRangeCount == 0) {
284 dprintf("ppc_openfirmware_probe_uninorth: Can't find mem ranges.\n");
285 free(bridge);
286 return B_ERROR;
289 status_t error = pci_controller_add(&sUniNorthPCIController, bridge);
290 if (error != B_OK)
291 free(bridge);
292 return error;