1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker * The PCI Library -- Hurd access via RPCs
3*c2e0c6b5SAndroid Build Coastguard Worker *
4*c2e0c6b5SAndroid Build Coastguard Worker * Copyright (c) 2017 Joan Lledó <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker *
6*c2e0c6b5SAndroid Build Coastguard Worker * Can be freely distributed and used under the terms of the GNU GPL v2+.
7*c2e0c6b5SAndroid Build Coastguard Worker *
8*c2e0c6b5SAndroid Build Coastguard Worker * SPDX-License-Identifier: GPL-2.0-or-later
9*c2e0c6b5SAndroid Build Coastguard Worker */
10*c2e0c6b5SAndroid Build Coastguard Worker
11*c2e0c6b5SAndroid Build Coastguard Worker #define _GNU_SOURCE
12*c2e0c6b5SAndroid Build Coastguard Worker
13*c2e0c6b5SAndroid Build Coastguard Worker #include "internal.h"
14*c2e0c6b5SAndroid Build Coastguard Worker
15*c2e0c6b5SAndroid Build Coastguard Worker #include <stdlib.h>
16*c2e0c6b5SAndroid Build Coastguard Worker #include <stdio.h>
17*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/types.h>
18*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/stat.h>
19*c2e0c6b5SAndroid Build Coastguard Worker #include <unistd.h>
20*c2e0c6b5SAndroid Build Coastguard Worker #include <dirent.h>
21*c2e0c6b5SAndroid Build Coastguard Worker #include <fcntl.h>
22*c2e0c6b5SAndroid Build Coastguard Worker #include <string.h>
23*c2e0c6b5SAndroid Build Coastguard Worker #include <hurd.h>
24*c2e0c6b5SAndroid Build Coastguard Worker #include <hurd/pci.h>
25*c2e0c6b5SAndroid Build Coastguard Worker #include <hurd/paths.h>
26*c2e0c6b5SAndroid Build Coastguard Worker
27*c2e0c6b5SAndroid Build Coastguard Worker /* Server path */
28*c2e0c6b5SAndroid Build Coastguard Worker #define _SERVERS_BUS_PCI _SERVERS_BUS "/pci"
29*c2e0c6b5SAndroid Build Coastguard Worker
30*c2e0c6b5SAndroid Build Coastguard Worker /* File names */
31*c2e0c6b5SAndroid Build Coastguard Worker #define FILE_CONFIG_NAME "config"
32*c2e0c6b5SAndroid Build Coastguard Worker #define FILE_ROM_NAME "rom"
33*c2e0c6b5SAndroid Build Coastguard Worker
34*c2e0c6b5SAndroid Build Coastguard Worker /* Level in the fs tree */
35*c2e0c6b5SAndroid Build Coastguard Worker typedef enum
36*c2e0c6b5SAndroid Build Coastguard Worker {
37*c2e0c6b5SAndroid Build Coastguard Worker LEVEL_NONE,
38*c2e0c6b5SAndroid Build Coastguard Worker LEVEL_DOMAIN,
39*c2e0c6b5SAndroid Build Coastguard Worker LEVEL_BUS,
40*c2e0c6b5SAndroid Build Coastguard Worker LEVEL_DEV,
41*c2e0c6b5SAndroid Build Coastguard Worker LEVEL_FUNC
42*c2e0c6b5SAndroid Build Coastguard Worker } tree_level;
43*c2e0c6b5SAndroid Build Coastguard Worker
44*c2e0c6b5SAndroid Build Coastguard Worker /* Check whether there's a pci server */
45*c2e0c6b5SAndroid Build Coastguard Worker static int
hurd_detect(struct pci_access * a)46*c2e0c6b5SAndroid Build Coastguard Worker hurd_detect(struct pci_access *a)
47*c2e0c6b5SAndroid Build Coastguard Worker {
48*c2e0c6b5SAndroid Build Coastguard Worker int err;
49*c2e0c6b5SAndroid Build Coastguard Worker struct stat st;
50*c2e0c6b5SAndroid Build Coastguard Worker
51*c2e0c6b5SAndroid Build Coastguard Worker err = stat(_SERVERS_BUS_PCI, &st);
52*c2e0c6b5SAndroid Build Coastguard Worker if (err)
53*c2e0c6b5SAndroid Build Coastguard Worker {
54*c2e0c6b5SAndroid Build Coastguard Worker a->error("Could not open file `%s'", _SERVERS_BUS_PCI);
55*c2e0c6b5SAndroid Build Coastguard Worker return 0;
56*c2e0c6b5SAndroid Build Coastguard Worker }
57*c2e0c6b5SAndroid Build Coastguard Worker
58*c2e0c6b5SAndroid Build Coastguard Worker /* The node must be a directory and a translator */
59*c2e0c6b5SAndroid Build Coastguard Worker return S_ISDIR(st.st_mode) && ((st.st_mode & S_ITRANS) == S_IROOT);
60*c2e0c6b5SAndroid Build Coastguard Worker }
61*c2e0c6b5SAndroid Build Coastguard Worker
62*c2e0c6b5SAndroid Build Coastguard Worker /* Empty callbacks, we don't need any special init or cleanup */
63*c2e0c6b5SAndroid Build Coastguard Worker static void
hurd_init(struct pci_access * a UNUSED)64*c2e0c6b5SAndroid Build Coastguard Worker hurd_init(struct pci_access *a UNUSED)
65*c2e0c6b5SAndroid Build Coastguard Worker {
66*c2e0c6b5SAndroid Build Coastguard Worker }
67*c2e0c6b5SAndroid Build Coastguard Worker
68*c2e0c6b5SAndroid Build Coastguard Worker static void
hurd_cleanup(struct pci_access * a UNUSED)69*c2e0c6b5SAndroid Build Coastguard Worker hurd_cleanup(struct pci_access *a UNUSED)
70*c2e0c6b5SAndroid Build Coastguard Worker {
71*c2e0c6b5SAndroid Build Coastguard Worker }
72*c2e0c6b5SAndroid Build Coastguard Worker
73*c2e0c6b5SAndroid Build Coastguard Worker /* Each device has its own server path. Allocate space for the port. */
74*c2e0c6b5SAndroid Build Coastguard Worker static void
hurd_init_dev(struct pci_dev * d)75*c2e0c6b5SAndroid Build Coastguard Worker hurd_init_dev(struct pci_dev *d)
76*c2e0c6b5SAndroid Build Coastguard Worker {
77*c2e0c6b5SAndroid Build Coastguard Worker d->backend_data = pci_malloc(d->access, sizeof(mach_port_t));
78*c2e0c6b5SAndroid Build Coastguard Worker *((mach_port_t *) d->backend_data) = MACH_PORT_NULL;
79*c2e0c6b5SAndroid Build Coastguard Worker }
80*c2e0c6b5SAndroid Build Coastguard Worker
81*c2e0c6b5SAndroid Build Coastguard Worker /* Deallocate the port and free its space */
82*c2e0c6b5SAndroid Build Coastguard Worker static void
hurd_cleanup_dev(struct pci_dev * d)83*c2e0c6b5SAndroid Build Coastguard Worker hurd_cleanup_dev(struct pci_dev *d)
84*c2e0c6b5SAndroid Build Coastguard Worker {
85*c2e0c6b5SAndroid Build Coastguard Worker mach_port_t device_port;
86*c2e0c6b5SAndroid Build Coastguard Worker
87*c2e0c6b5SAndroid Build Coastguard Worker device_port = *((mach_port_t *) d->backend_data);
88*c2e0c6b5SAndroid Build Coastguard Worker mach_port_deallocate(mach_task_self(), device_port);
89*c2e0c6b5SAndroid Build Coastguard Worker
90*c2e0c6b5SAndroid Build Coastguard Worker pci_mfree(d->backend_data);
91*c2e0c6b5SAndroid Build Coastguard Worker d->backend_data = NULL;
92*c2e0c6b5SAndroid Build Coastguard Worker }
93*c2e0c6b5SAndroid Build Coastguard Worker
94*c2e0c6b5SAndroid Build Coastguard Worker static mach_port_t
device_port_lookup(struct pci_dev * d)95*c2e0c6b5SAndroid Build Coastguard Worker device_port_lookup(struct pci_dev *d)
96*c2e0c6b5SAndroid Build Coastguard Worker {
97*c2e0c6b5SAndroid Build Coastguard Worker char server[NAME_MAX];
98*c2e0c6b5SAndroid Build Coastguard Worker mach_port_t device_port = *((mach_port_t *) d->backend_data);
99*c2e0c6b5SAndroid Build Coastguard Worker
100*c2e0c6b5SAndroid Build Coastguard Worker if (device_port != MACH_PORT_NULL)
101*c2e0c6b5SAndroid Build Coastguard Worker return device_port;
102*c2e0c6b5SAndroid Build Coastguard Worker
103*c2e0c6b5SAndroid Build Coastguard Worker snprintf(server, NAME_MAX, "%s/%04x/%02x/%02x/%01u/%s",
104*c2e0c6b5SAndroid Build Coastguard Worker _SERVERS_BUS_PCI, d->domain, d->bus, d->dev, d->func,
105*c2e0c6b5SAndroid Build Coastguard Worker FILE_CONFIG_NAME);
106*c2e0c6b5SAndroid Build Coastguard Worker device_port = file_name_lookup(server, 0, 0);
107*c2e0c6b5SAndroid Build Coastguard Worker
108*c2e0c6b5SAndroid Build Coastguard Worker if (device_port == MACH_PORT_NULL)
109*c2e0c6b5SAndroid Build Coastguard Worker d->access->error("Cannot find the PCI arbiter");
110*c2e0c6b5SAndroid Build Coastguard Worker
111*c2e0c6b5SAndroid Build Coastguard Worker *((mach_port_t *) d->backend_data) = device_port;
112*c2e0c6b5SAndroid Build Coastguard Worker return device_port;
113*c2e0c6b5SAndroid Build Coastguard Worker }
114*c2e0c6b5SAndroid Build Coastguard Worker
115*c2e0c6b5SAndroid Build Coastguard Worker /* Walk through the FS tree to see what is allowed for us */
116*c2e0c6b5SAndroid Build Coastguard Worker static void
enum_devices(const char * parent,struct pci_access * a,int domain,int bus,int dev,int func,tree_level lev)117*c2e0c6b5SAndroid Build Coastguard Worker enum_devices(const char *parent, struct pci_access *a, int domain, int bus,
118*c2e0c6b5SAndroid Build Coastguard Worker int dev, int func, tree_level lev)
119*c2e0c6b5SAndroid Build Coastguard Worker {
120*c2e0c6b5SAndroid Build Coastguard Worker int ret;
121*c2e0c6b5SAndroid Build Coastguard Worker DIR *dir;
122*c2e0c6b5SAndroid Build Coastguard Worker struct dirent *entry;
123*c2e0c6b5SAndroid Build Coastguard Worker char path[NAME_MAX];
124*c2e0c6b5SAndroid Build Coastguard Worker struct pci_dev *d;
125*c2e0c6b5SAndroid Build Coastguard Worker
126*c2e0c6b5SAndroid Build Coastguard Worker dir = opendir(parent);
127*c2e0c6b5SAndroid Build Coastguard Worker if (!dir)
128*c2e0c6b5SAndroid Build Coastguard Worker {
129*c2e0c6b5SAndroid Build Coastguard Worker if (errno == EPERM || errno == EACCES)
130*c2e0c6b5SAndroid Build Coastguard Worker /* The client lacks the permissions to access this function, skip */
131*c2e0c6b5SAndroid Build Coastguard Worker return;
132*c2e0c6b5SAndroid Build Coastguard Worker else
133*c2e0c6b5SAndroid Build Coastguard Worker a->error("Cannot open directory: %s (%s)", parent, strerror(errno));
134*c2e0c6b5SAndroid Build Coastguard Worker }
135*c2e0c6b5SAndroid Build Coastguard Worker
136*c2e0c6b5SAndroid Build Coastguard Worker while ((entry = readdir(dir)) != 0)
137*c2e0c6b5SAndroid Build Coastguard Worker {
138*c2e0c6b5SAndroid Build Coastguard Worker snprintf(path, NAME_MAX, "%s/%s", parent, entry->d_name);
139*c2e0c6b5SAndroid Build Coastguard Worker if (entry->d_type == DT_DIR)
140*c2e0c6b5SAndroid Build Coastguard Worker {
141*c2e0c6b5SAndroid Build Coastguard Worker if (!strncmp(entry->d_name, ".", NAME_MAX)
142*c2e0c6b5SAndroid Build Coastguard Worker || !strncmp(entry->d_name, "..", NAME_MAX))
143*c2e0c6b5SAndroid Build Coastguard Worker continue;
144*c2e0c6b5SAndroid Build Coastguard Worker
145*c2e0c6b5SAndroid Build Coastguard Worker errno = 0;
146*c2e0c6b5SAndroid Build Coastguard Worker ret = strtol(entry->d_name, 0, 16);
147*c2e0c6b5SAndroid Build Coastguard Worker if (errno)
148*c2e0c6b5SAndroid Build Coastguard Worker {
149*c2e0c6b5SAndroid Build Coastguard Worker if (closedir(dir) < 0)
150*c2e0c6b5SAndroid Build Coastguard Worker a->warning("Cannot close directory: %s (%s)", parent,
151*c2e0c6b5SAndroid Build Coastguard Worker strerror(errno));
152*c2e0c6b5SAndroid Build Coastguard Worker a->error("Wrong directory name: %s (number expected) probably "
153*c2e0c6b5SAndroid Build Coastguard Worker "not connected to an arbiter", entry->d_name);
154*c2e0c6b5SAndroid Build Coastguard Worker }
155*c2e0c6b5SAndroid Build Coastguard Worker
156*c2e0c6b5SAndroid Build Coastguard Worker /*
157*c2e0c6b5SAndroid Build Coastguard Worker * We found a valid directory.
158*c2e0c6b5SAndroid Build Coastguard Worker * Update the address and switch to the next level.
159*c2e0c6b5SAndroid Build Coastguard Worker */
160*c2e0c6b5SAndroid Build Coastguard Worker switch (lev)
161*c2e0c6b5SAndroid Build Coastguard Worker {
162*c2e0c6b5SAndroid Build Coastguard Worker case LEVEL_DOMAIN:
163*c2e0c6b5SAndroid Build Coastguard Worker domain = ret;
164*c2e0c6b5SAndroid Build Coastguard Worker break;
165*c2e0c6b5SAndroid Build Coastguard Worker case LEVEL_BUS:
166*c2e0c6b5SAndroid Build Coastguard Worker bus = ret;
167*c2e0c6b5SAndroid Build Coastguard Worker break;
168*c2e0c6b5SAndroid Build Coastguard Worker case LEVEL_DEV:
169*c2e0c6b5SAndroid Build Coastguard Worker dev = ret;
170*c2e0c6b5SAndroid Build Coastguard Worker break;
171*c2e0c6b5SAndroid Build Coastguard Worker case LEVEL_FUNC:
172*c2e0c6b5SAndroid Build Coastguard Worker func = ret;
173*c2e0c6b5SAndroid Build Coastguard Worker break;
174*c2e0c6b5SAndroid Build Coastguard Worker default:
175*c2e0c6b5SAndroid Build Coastguard Worker if (closedir(dir) < 0)
176*c2e0c6b5SAndroid Build Coastguard Worker a->warning("Cannot close directory: %s (%s)", parent,
177*c2e0c6b5SAndroid Build Coastguard Worker strerror(errno));
178*c2e0c6b5SAndroid Build Coastguard Worker a->error("Wrong directory tree, probably not connected to an arbiter");
179*c2e0c6b5SAndroid Build Coastguard Worker }
180*c2e0c6b5SAndroid Build Coastguard Worker
181*c2e0c6b5SAndroid Build Coastguard Worker enum_devices(path, a, domain, bus, dev, func, lev + 1);
182*c2e0c6b5SAndroid Build Coastguard Worker }
183*c2e0c6b5SAndroid Build Coastguard Worker else
184*c2e0c6b5SAndroid Build Coastguard Worker {
185*c2e0c6b5SAndroid Build Coastguard Worker if (strncmp(entry->d_name, FILE_CONFIG_NAME, NAME_MAX))
186*c2e0c6b5SAndroid Build Coastguard Worker /* We are looking for the config file */
187*c2e0c6b5SAndroid Build Coastguard Worker continue;
188*c2e0c6b5SAndroid Build Coastguard Worker
189*c2e0c6b5SAndroid Build Coastguard Worker /* We found an available virtual device, add it to our list */
190*c2e0c6b5SAndroid Build Coastguard Worker d = pci_alloc_dev(a);
191*c2e0c6b5SAndroid Build Coastguard Worker d->domain = domain;
192*c2e0c6b5SAndroid Build Coastguard Worker d->bus = bus;
193*c2e0c6b5SAndroid Build Coastguard Worker d->dev = dev;
194*c2e0c6b5SAndroid Build Coastguard Worker d->func = func;
195*c2e0c6b5SAndroid Build Coastguard Worker pci_link_dev(a, d);
196*c2e0c6b5SAndroid Build Coastguard Worker }
197*c2e0c6b5SAndroid Build Coastguard Worker }
198*c2e0c6b5SAndroid Build Coastguard Worker
199*c2e0c6b5SAndroid Build Coastguard Worker if (closedir(dir) < 0)
200*c2e0c6b5SAndroid Build Coastguard Worker a->error("Cannot close directory: %s (%s)", parent, strerror(errno));
201*c2e0c6b5SAndroid Build Coastguard Worker }
202*c2e0c6b5SAndroid Build Coastguard Worker
203*c2e0c6b5SAndroid Build Coastguard Worker /* Enumerate devices */
204*c2e0c6b5SAndroid Build Coastguard Worker static void
hurd_scan(struct pci_access * a)205*c2e0c6b5SAndroid Build Coastguard Worker hurd_scan(struct pci_access *a)
206*c2e0c6b5SAndroid Build Coastguard Worker {
207*c2e0c6b5SAndroid Build Coastguard Worker enum_devices(_SERVERS_BUS_PCI, a, -1, -1, -1, -1, LEVEL_DOMAIN);
208*c2e0c6b5SAndroid Build Coastguard Worker }
209*c2e0c6b5SAndroid Build Coastguard Worker
210*c2e0c6b5SAndroid Build Coastguard Worker /*
211*c2e0c6b5SAndroid Build Coastguard Worker * Read `len' bytes to `buf'.
212*c2e0c6b5SAndroid Build Coastguard Worker *
213*c2e0c6b5SAndroid Build Coastguard Worker * Returns error when the number of read bytes does not match `len'.
214*c2e0c6b5SAndroid Build Coastguard Worker */
215*c2e0c6b5SAndroid Build Coastguard Worker static int
hurd_read(struct pci_dev * d,int pos,byte * buf,int len)216*c2e0c6b5SAndroid Build Coastguard Worker hurd_read(struct pci_dev *d, int pos, byte * buf, int len)
217*c2e0c6b5SAndroid Build Coastguard Worker {
218*c2e0c6b5SAndroid Build Coastguard Worker int err;
219*c2e0c6b5SAndroid Build Coastguard Worker size_t nread;
220*c2e0c6b5SAndroid Build Coastguard Worker char *data;
221*c2e0c6b5SAndroid Build Coastguard Worker mach_port_t device_port = device_port_lookup(d);
222*c2e0c6b5SAndroid Build Coastguard Worker
223*c2e0c6b5SAndroid Build Coastguard Worker if (len > 4)
224*c2e0c6b5SAndroid Build Coastguard Worker return pci_generic_block_read(d, pos, buf, len);
225*c2e0c6b5SAndroid Build Coastguard Worker
226*c2e0c6b5SAndroid Build Coastguard Worker data = (char *) buf;
227*c2e0c6b5SAndroid Build Coastguard Worker err = pci_conf_read(device_port, pos, &data, &nread, len);
228*c2e0c6b5SAndroid Build Coastguard Worker
229*c2e0c6b5SAndroid Build Coastguard Worker if (data != (char *) buf)
230*c2e0c6b5SAndroid Build Coastguard Worker {
231*c2e0c6b5SAndroid Build Coastguard Worker if (nread > (size_t) len) /* Sanity check for bogus server. */
232*c2e0c6b5SAndroid Build Coastguard Worker {
233*c2e0c6b5SAndroid Build Coastguard Worker vm_deallocate(mach_task_self(), (vm_address_t) data, nread);
234*c2e0c6b5SAndroid Build Coastguard Worker return 0;
235*c2e0c6b5SAndroid Build Coastguard Worker }
236*c2e0c6b5SAndroid Build Coastguard Worker
237*c2e0c6b5SAndroid Build Coastguard Worker memcpy(buf, data, nread);
238*c2e0c6b5SAndroid Build Coastguard Worker vm_deallocate(mach_task_self(), (vm_address_t) data, nread);
239*c2e0c6b5SAndroid Build Coastguard Worker }
240*c2e0c6b5SAndroid Build Coastguard Worker
241*c2e0c6b5SAndroid Build Coastguard Worker return !err && nread == (size_t) len;
242*c2e0c6b5SAndroid Build Coastguard Worker }
243*c2e0c6b5SAndroid Build Coastguard Worker
244*c2e0c6b5SAndroid Build Coastguard Worker /*
245*c2e0c6b5SAndroid Build Coastguard Worker * Write `len' bytes from `buf'.
246*c2e0c6b5SAndroid Build Coastguard Worker *
247*c2e0c6b5SAndroid Build Coastguard Worker * Returns error when the number of written bytes does not match `len'.
248*c2e0c6b5SAndroid Build Coastguard Worker */
249*c2e0c6b5SAndroid Build Coastguard Worker static int
hurd_write(struct pci_dev * d,int pos,byte * buf,int len)250*c2e0c6b5SAndroid Build Coastguard Worker hurd_write(struct pci_dev *d, int pos, byte * buf, int len)
251*c2e0c6b5SAndroid Build Coastguard Worker {
252*c2e0c6b5SAndroid Build Coastguard Worker int err;
253*c2e0c6b5SAndroid Build Coastguard Worker size_t nwrote;
254*c2e0c6b5SAndroid Build Coastguard Worker mach_port_t device_port = device_port_lookup(d);
255*c2e0c6b5SAndroid Build Coastguard Worker
256*c2e0c6b5SAndroid Build Coastguard Worker if (len > 4)
257*c2e0c6b5SAndroid Build Coastguard Worker return pci_generic_block_write(d, pos, buf, len);
258*c2e0c6b5SAndroid Build Coastguard Worker
259*c2e0c6b5SAndroid Build Coastguard Worker err = pci_conf_write(device_port, pos, (char *) buf, len, &nwrote);
260*c2e0c6b5SAndroid Build Coastguard Worker
261*c2e0c6b5SAndroid Build Coastguard Worker return !err && nwrote == (size_t) len;
262*c2e0c6b5SAndroid Build Coastguard Worker }
263*c2e0c6b5SAndroid Build Coastguard Worker
264*c2e0c6b5SAndroid Build Coastguard Worker /* Get requested info from the server */
265*c2e0c6b5SAndroid Build Coastguard Worker
266*c2e0c6b5SAndroid Build Coastguard Worker static int
hurd_fill_regions(struct pci_dev * d)267*c2e0c6b5SAndroid Build Coastguard Worker hurd_fill_regions(struct pci_dev *d)
268*c2e0c6b5SAndroid Build Coastguard Worker {
269*c2e0c6b5SAndroid Build Coastguard Worker mach_port_t device_port = device_port_lookup(d);
270*c2e0c6b5SAndroid Build Coastguard Worker struct pci_bar regions[6];
271*c2e0c6b5SAndroid Build Coastguard Worker char *buf = (char *) ®ions;
272*c2e0c6b5SAndroid Build Coastguard Worker size_t size = sizeof(regions);
273*c2e0c6b5SAndroid Build Coastguard Worker
274*c2e0c6b5SAndroid Build Coastguard Worker int err = pci_get_dev_regions(device_port, &buf, &size);
275*c2e0c6b5SAndroid Build Coastguard Worker if (err)
276*c2e0c6b5SAndroid Build Coastguard Worker return 0;
277*c2e0c6b5SAndroid Build Coastguard Worker
278*c2e0c6b5SAndroid Build Coastguard Worker if ((char *) ®ions != buf)
279*c2e0c6b5SAndroid Build Coastguard Worker {
280*c2e0c6b5SAndroid Build Coastguard Worker /* Sanity check for bogus server. */
281*c2e0c6b5SAndroid Build Coastguard Worker if (size > sizeof(regions))
282*c2e0c6b5SAndroid Build Coastguard Worker {
283*c2e0c6b5SAndroid Build Coastguard Worker vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
284*c2e0c6b5SAndroid Build Coastguard Worker return 0;
285*c2e0c6b5SAndroid Build Coastguard Worker }
286*c2e0c6b5SAndroid Build Coastguard Worker
287*c2e0c6b5SAndroid Build Coastguard Worker memcpy(®ions, buf, size);
288*c2e0c6b5SAndroid Build Coastguard Worker vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
289*c2e0c6b5SAndroid Build Coastguard Worker }
290*c2e0c6b5SAndroid Build Coastguard Worker
291*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < 6; i++)
292*c2e0c6b5SAndroid Build Coastguard Worker {
293*c2e0c6b5SAndroid Build Coastguard Worker if (regions[i].size == 0)
294*c2e0c6b5SAndroid Build Coastguard Worker continue;
295*c2e0c6b5SAndroid Build Coastguard Worker
296*c2e0c6b5SAndroid Build Coastguard Worker d->base_addr[i] = regions[i].base_addr;
297*c2e0c6b5SAndroid Build Coastguard Worker d->base_addr[i] |= regions[i].is_IO;
298*c2e0c6b5SAndroid Build Coastguard Worker d->base_addr[i] |= regions[i].is_64 << 2;
299*c2e0c6b5SAndroid Build Coastguard Worker d->base_addr[i] |= regions[i].is_prefetchable << 3;
300*c2e0c6b5SAndroid Build Coastguard Worker
301*c2e0c6b5SAndroid Build Coastguard Worker d->size[i] = regions[i].size;
302*c2e0c6b5SAndroid Build Coastguard Worker }
303*c2e0c6b5SAndroid Build Coastguard Worker
304*c2e0c6b5SAndroid Build Coastguard Worker return 1;
305*c2e0c6b5SAndroid Build Coastguard Worker }
306*c2e0c6b5SAndroid Build Coastguard Worker
307*c2e0c6b5SAndroid Build Coastguard Worker static int
hurd_fill_rom(struct pci_dev * d)308*c2e0c6b5SAndroid Build Coastguard Worker hurd_fill_rom(struct pci_dev *d)
309*c2e0c6b5SAndroid Build Coastguard Worker {
310*c2e0c6b5SAndroid Build Coastguard Worker struct pci_xrom_bar rom;
311*c2e0c6b5SAndroid Build Coastguard Worker mach_port_t device_port = device_port_lookup(d);
312*c2e0c6b5SAndroid Build Coastguard Worker char *buf = (char *) &rom;
313*c2e0c6b5SAndroid Build Coastguard Worker size_t size = sizeof(rom);
314*c2e0c6b5SAndroid Build Coastguard Worker
315*c2e0c6b5SAndroid Build Coastguard Worker int err = pci_get_dev_rom(device_port, &buf, &size);
316*c2e0c6b5SAndroid Build Coastguard Worker if (err)
317*c2e0c6b5SAndroid Build Coastguard Worker return 0;
318*c2e0c6b5SAndroid Build Coastguard Worker
319*c2e0c6b5SAndroid Build Coastguard Worker if ((char *) &rom != buf)
320*c2e0c6b5SAndroid Build Coastguard Worker {
321*c2e0c6b5SAndroid Build Coastguard Worker /* Sanity check for bogus server. */
322*c2e0c6b5SAndroid Build Coastguard Worker if (size > sizeof(rom))
323*c2e0c6b5SAndroid Build Coastguard Worker {
324*c2e0c6b5SAndroid Build Coastguard Worker vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
325*c2e0c6b5SAndroid Build Coastguard Worker return 0;
326*c2e0c6b5SAndroid Build Coastguard Worker }
327*c2e0c6b5SAndroid Build Coastguard Worker
328*c2e0c6b5SAndroid Build Coastguard Worker memcpy(&rom, buf, size);
329*c2e0c6b5SAndroid Build Coastguard Worker vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
330*c2e0c6b5SAndroid Build Coastguard Worker }
331*c2e0c6b5SAndroid Build Coastguard Worker
332*c2e0c6b5SAndroid Build Coastguard Worker d->rom_base_addr = rom.base_addr;
333*c2e0c6b5SAndroid Build Coastguard Worker d->rom_size = rom.size;
334*c2e0c6b5SAndroid Build Coastguard Worker
335*c2e0c6b5SAndroid Build Coastguard Worker return 1;
336*c2e0c6b5SAndroid Build Coastguard Worker }
337*c2e0c6b5SAndroid Build Coastguard Worker
338*c2e0c6b5SAndroid Build Coastguard Worker static void
hurd_fill_info(struct pci_dev * d,unsigned int flags)339*c2e0c6b5SAndroid Build Coastguard Worker hurd_fill_info(struct pci_dev *d, unsigned int flags)
340*c2e0c6b5SAndroid Build Coastguard Worker {
341*c2e0c6b5SAndroid Build Coastguard Worker if (!d->access->buscentric)
342*c2e0c6b5SAndroid Build Coastguard Worker {
343*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_BASES | PCI_FILL_SIZES))
344*c2e0c6b5SAndroid Build Coastguard Worker {
345*c2e0c6b5SAndroid Build Coastguard Worker if (hurd_fill_regions(d))
346*c2e0c6b5SAndroid Build Coastguard Worker clear_fill(d, PCI_FILL_BASES | PCI_FILL_SIZES);
347*c2e0c6b5SAndroid Build Coastguard Worker }
348*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_ROM_BASE))
349*c2e0c6b5SAndroid Build Coastguard Worker {
350*c2e0c6b5SAndroid Build Coastguard Worker if (hurd_fill_rom(d))
351*c2e0c6b5SAndroid Build Coastguard Worker clear_fill(d, PCI_FILL_ROM_BASE);
352*c2e0c6b5SAndroid Build Coastguard Worker }
353*c2e0c6b5SAndroid Build Coastguard Worker }
354*c2e0c6b5SAndroid Build Coastguard Worker
355*c2e0c6b5SAndroid Build Coastguard Worker pci_generic_fill_info(d, flags);
356*c2e0c6b5SAndroid Build Coastguard Worker }
357*c2e0c6b5SAndroid Build Coastguard Worker
358*c2e0c6b5SAndroid Build Coastguard Worker struct pci_methods pm_hurd = {
359*c2e0c6b5SAndroid Build Coastguard Worker .name = "hurd",
360*c2e0c6b5SAndroid Build Coastguard Worker .help = "Hurd access using RPCs",
361*c2e0c6b5SAndroid Build Coastguard Worker .detect = hurd_detect,
362*c2e0c6b5SAndroid Build Coastguard Worker .init = hurd_init,
363*c2e0c6b5SAndroid Build Coastguard Worker .cleanup = hurd_cleanup,
364*c2e0c6b5SAndroid Build Coastguard Worker .scan = hurd_scan,
365*c2e0c6b5SAndroid Build Coastguard Worker .fill_info = hurd_fill_info,
366*c2e0c6b5SAndroid Build Coastguard Worker .read = hurd_read,
367*c2e0c6b5SAndroid Build Coastguard Worker .write = hurd_write,
368*c2e0c6b5SAndroid Build Coastguard Worker .init_dev = hurd_init_dev,
369*c2e0c6b5SAndroid Build Coastguard Worker .cleanup_dev = hurd_cleanup_dev
370*c2e0c6b5SAndroid Build Coastguard Worker };
371