1/*
2 * Copyright (c) 2018, Damien Zammit
3 * Copyright (c) 2017, Joan Lledó
4 * Copyright (c) 2009, 2012 Samuel Thibault
5 * Heavily inspired from the freebsd, netbsd, and openbsd backends
6 * (C) Copyright Eric Anholt 2006
7 * (C) Copyright IBM Corporation 2006
8 * Copyright (c) 2008 Juan Romero Pardines
9 * Copyright (c) 2008 Mark Kettenis
10 *
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#define _GNU_SOURCE
25#include <unistd.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <fcntl.h>
32#include <dirent.h>
33#include <sys/mman.h>
34#include <string.h>
35#include <strings.h>
36#include <mach.h>
37#include <hurd.h>
38#include <hurd/pci.h>
39#include <hurd/paths.h>
40#include <hurd/fs.h>
41#include <device/device.h>
42
43#include "x86_pci.h"
44#include "pciaccess.h"
45#include "pciaccess_private.h"
46
47/*
48 * Hurd PCI access using RPCs.
49 *
50 * Some functions are shared with the x86 module to avoid repeating code.
51 */
52
53/* Server path */
54#define _SERVERS_BUS_PCI	_SERVERS_BUS "/pci"
55
56/* File names */
57#define FILE_CONFIG_NAME "config"
58#define FILE_REGION_NAME "region"
59#define FILE_ROM_NAME "rom"
60
61#define LEGACY_REGION -1
62
63/* Level in the fs tree */
64typedef enum {
65    LEVEL_NONE,
66    LEVEL_DOMAIN,
67    LEVEL_BUS,
68    LEVEL_DEV,
69    LEVEL_FUNC
70} tree_level;
71
72struct pci_system_hurd {
73    struct pci_system system;
74    mach_port_t root;
75};
76
77static int
78pci_device_hurd_probe(struct pci_device *dev)
79{
80    uint8_t irq;
81    int err, i;
82    struct pci_bar regions[6];
83    struct pci_xrom_bar rom;
84    struct pci_device_private *d;
85    mach_msg_type_number_t size;
86    char *buf;
87
88    /* Many of the fields were filled in during initial device enumeration.
89     * At this point, we need to fill in regions, rom_size, and irq.
90     */
91
92    err = pci_device_cfg_read_u8(dev, &irq, PCI_IRQ);
93    if (err)
94        return err;
95    dev->irq = irq;
96
97    /* Get regions */
98    buf = (char *)&regions;
99    size = sizeof(regions);
100    d = (struct pci_device_private *)dev;
101    err = pci_get_dev_regions(d->device_port, &buf, &size);
102    if(err)
103        return err;
104
105    if((char*)&regions != buf)
106    {
107        /* Sanity check for bogus server.  */
108        if(size > sizeof(regions))
109        {
110            vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
111            return EGRATUITOUS;
112        }
113
114        memcpy(&regions, buf, size);
115        vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
116    }
117
118    for(i=0; i<6; i++)
119    {
120        if(regions[i].size == 0)
121            continue;
122
123        dev->regions[i].base_addr = regions[i].base_addr;
124        dev->regions[i].size = regions[i].size;
125        dev->regions[i].is_IO = regions[i].is_IO;
126        dev->regions[i].is_prefetchable = regions[i].is_prefetchable;
127        dev->regions[i].is_64 = regions[i].is_64;
128    }
129
130    /* Get rom info */
131    buf = (char *)&rom;
132    size = sizeof(rom);
133    err = pci_get_dev_rom(d->device_port, &buf, &size);
134    if(err)
135        return err;
136
137    if((char*)&rom != buf)
138    {
139        /* Sanity check for bogus server.  */
140        if(size > sizeof(rom))
141        {
142            vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
143            return EGRATUITOUS;
144        }
145
146        memcpy(&rom, buf, size);
147        vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
148    }
149
150    d->rom_base = rom.base_addr;
151    dev->rom_size = rom.size;
152
153    return 0;
154}
155
156static void
157pci_system_hurd_destroy(void)
158{
159    struct pci_system_hurd *pci_sys_hurd = (struct pci_system_hurd *)pci_sys;
160
161    x86_disable_io();
162    mach_port_deallocate(mach_task_self(), pci_sys_hurd->root);
163}
164
165static int
166pci_device_hurd_map_range(struct pci_device *dev,
167    struct pci_device_mapping *map)
168{
169#if 0
170    struct pci_device_private *d = (struct pci_device_private *)dev;
171#endif
172    struct pci_system_hurd *pci_sys_hurd = (struct pci_system_hurd *)pci_sys;
173    int err = 0;
174    file_t file = MACH_PORT_NULL;
175    memory_object_t robj, wobj, pager;
176    vm_offset_t offset;
177    vm_prot_t prot = VM_PROT_READ;
178    const struct pci_mem_region *region;
179    const struct pci_mem_region rom_region = {
180#if 0
181    /* FIXME: We should be doing this: */
182        .base_addr = d->rom_base,
183    /* But currently pci-arbiter cannot get rom_base from libpciaccess, so we
184       are here assuming the caller is mapping from the rom base */
185#else
186        .base_addr = map->base,
187#endif
188        .size = dev->rom_size,
189    };
190    int flags = O_RDONLY;
191    char server[NAME_MAX];
192
193    if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE) {
194        prot |= VM_PROT_WRITE;
195        flags = O_RDWR;
196    }
197
198    if (map->region != LEGACY_REGION) {
199      region = &dev->regions[map->region];
200      snprintf(server, NAME_MAX, "%04x/%02x/%02x/%01u/%s%01u",
201	       dev->domain, dev->bus, dev->dev, dev->func,
202	       FILE_REGION_NAME, map->region);
203    } else {
204      region = &rom_region;
205      snprintf(server, NAME_MAX, "%04x/%02x/%02x/%01u/%s",
206	       dev->domain, dev->bus, dev->dev, dev->func,
207	       FILE_ROM_NAME);
208      if (map->base < region->base_addr ||
209	  map->base + map->size > region->base_addr + region->size)
210	return EINVAL;
211    }
212
213    file = file_name_lookup_under (pci_sys_hurd->root, server, flags, 0);
214    if (! MACH_PORT_VALID (file)) {
215        return errno;
216    }
217
218    err = io_map (file, &robj, &wobj);
219    mach_port_deallocate (mach_task_self(), file);
220    if (err)
221        return err;
222
223    switch (prot & (VM_PROT_READ|VM_PROT_WRITE)) {
224    case VM_PROT_READ:
225        pager = robj;
226        if (wobj != MACH_PORT_NULL)
227            mach_port_deallocate (mach_task_self(), wobj);
228        break;
229    case VM_PROT_READ|VM_PROT_WRITE:
230        if (robj == wobj) {
231            if (robj == MACH_PORT_NULL)
232                return EPERM;
233
234            pager = wobj;
235            /* Remove extra reference.  */
236            mach_port_deallocate (mach_task_self (), pager);
237        }
238        else {
239            if (robj != MACH_PORT_NULL)
240                mach_port_deallocate (mach_task_self (), robj);
241            if (wobj != MACH_PORT_NULL)
242                mach_port_deallocate (mach_task_self (), wobj);
243
244            return EPERM;
245        }
246        break;
247    default:
248        return EINVAL;
249    }
250
251    offset = map->base - region->base_addr;
252    err = vm_map (mach_task_self (), (vm_address_t *)&map->memory, map->size,
253                  0, 1,
254                  pager, /* a memory object proxy containing only the region */
255                  offset, /* offset from region start */
256                  0, prot, VM_PROT_ALL, VM_INHERIT_SHARE);
257    mach_port_deallocate (mach_task_self(), pager);
258
259    return err;
260}
261
262static int
263pci_device_hurd_unmap_range(struct pci_device *dev,
264    struct pci_device_mapping *map)
265{
266    int err;
267    err = pci_device_generic_unmap_range(dev, map);
268    map->memory = NULL;
269
270    return err;
271}
272
273static int
274pci_device_hurd_map_legacy(struct pci_device *dev, pciaddr_t base,
275    pciaddr_t size, unsigned map_flags, void **addr)
276{
277    struct pci_device_mapping map;
278    int err;
279
280    if (base >= 0xC0000 && base < 0x100000) {
281      /* FIXME: We would rather know for sure from d->rom_base whether this is
282         the ROM or not but currently pci-arbiter cannot get rom_base from
283         libpciaccess, so we are here assuming the caller is mapping from the
284         rom base */
285      map.base = base;
286      map.size = size;
287      map.flags = map_flags;
288      map.region = LEGACY_REGION;
289      err = pci_device_hurd_map_range(dev, &map);
290      *addr = map.memory;
291
292      if (!err)
293	return 0;
294    }
295
296    /* This is probably not the ROM, this is probably something like VRam or
297       the interrupt table, just map it by hand.  */
298    return pci_system_x86_map_dev_mem(addr, base, size, !!(map_flags & PCI_DEV_MAP_FLAG_WRITABLE));
299}
300
301static int
302pci_device_hurd_unmap_legacy(struct pci_device *dev, void *addr,
303    pciaddr_t size)
304{
305    struct pci_device_mapping map;
306
307    map.size = size;
308    map.flags = 0;
309    map.region = LEGACY_REGION;
310    map.memory = addr;
311
312    return pci_device_hurd_unmap_range(dev, &map);
313}
314
315/*
316 * Read `nbytes' bytes from `reg' in device's configuration space
317 * and store them in `buf'.
318 *
319 * It's assumed that `nbytes' bytes are allocated in `buf'
320 */
321static int
322pciclient_cfg_read(mach_port_t device_port, int reg, char *buf,
323                   size_t * nbytes)
324{
325    int err;
326    mach_msg_type_number_t nread;
327    char *data;
328
329    data = buf;
330    nread = *nbytes;
331    err = __pci_conf_read(device_port, reg, &data, &nread, *nbytes);
332    if (err)
333        return err;
334
335    if (data != buf) {
336        if (nread > *nbytes)	/* Sanity check for bogus server.  */ {
337                vm_deallocate(mach_task_self(), (vm_address_t) data, nread);
338                return EGRATUITOUS;
339        }
340
341        memcpy(buf, data, nread);
342        vm_deallocate(mach_task_self(), (vm_address_t)data, nread);
343    }
344
345    *nbytes = nread;
346
347    return 0;
348}
349
350/* Write `nbytes' bytes from `buf' to `reg' in device's configuration space */
351static int
352pciclient_cfg_write(mach_port_t device_port, int reg, char *buf,
353                    size_t * nbytes)
354{
355    int err;
356    size_t nwrote;
357
358    err = __pci_conf_write(device_port, reg, buf, *nbytes, &nwrote);
359
360    if (!err)
361        *nbytes = nwrote;
362
363    return err;
364}
365
366/*
367 * Read up to `size' bytes from `dev' configuration space to `data' starting
368 * at `offset'. Write the amount on read bytes in `bytes_read'.
369 */
370static int
371pci_device_hurd_read(struct pci_device *dev, void *data,
372    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
373{
374    int err;
375    struct pci_device_private *d;
376
377    *bytes_read = 0;
378    d = (struct pci_device_private *)dev;
379    while (size > 0) {
380        size_t toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1);
381        if (toread > size)
382            toread = size;
383
384        err = pciclient_cfg_read(d->device_port, offset, (char*)data,
385                                 &toread);
386        if (err)
387            return err;
388
389        offset += toread;
390        data = (char*)data + toread;
391        size -= toread;
392        *bytes_read += toread;
393    }
394    return 0;
395}
396
397/*
398 * Write up to `size' bytes from `data' to `dev' configuration space starting
399 * at `offset'. Write the amount on written bytes in `bytes_written'.
400 */
401static int
402pci_device_hurd_write(struct pci_device *dev, const void *data,
403    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
404{
405    int err;
406    struct pci_device_private *d;
407
408    *bytes_written = 0;
409    d = (struct pci_device_private *)dev;
410    while (size > 0) {
411        size_t towrite = 4;
412        if (towrite > size)
413            towrite = size;
414        if (towrite > 4 - (offset & 0x3))
415            towrite = 4 - (offset & 0x3);
416
417        err = pciclient_cfg_write(d->device_port, offset, (char*)data,
418                                  &towrite);
419        if (err)
420            return err;
421
422        offset += towrite;
423        data = (const char*)data + towrite;
424        size -= towrite;
425        *bytes_written += towrite;
426    }
427    return 0;
428}
429
430/*
431 * Copy the device's firmware in `buffer'
432 */
433static int
434pci_device_hurd_read_rom(struct pci_device * dev, void * buffer)
435{
436    ssize_t rd;
437    int romfd;
438    char server[NAME_MAX];
439
440    snprintf(server, NAME_MAX, "%s/%04x/%02x/%02x/%01u/%s", _SERVERS_BUS_PCI,
441             dev->domain, dev->bus, dev->dev, dev->func, FILE_ROM_NAME);
442
443    romfd = open(server, O_RDONLY | O_CLOEXEC);
444    if (romfd == -1)
445        return errno;
446
447    rd = read(romfd, buffer, dev->rom_size);
448    if (rd != dev->rom_size) {
449        close(romfd);
450        return errno;
451    }
452
453    close(romfd);
454
455    return 0;
456}
457
458/*
459 * Each device has its own server where send RPC's to.
460 *
461 * Deallocate the port before destroying the device.
462 */
463static void
464pci_device_hurd_destroy_device(struct pci_device *dev)
465{
466    struct pci_device_private *d = (struct pci_device_private*) dev;
467
468    mach_port_deallocate (mach_task_self (), d->device_port);
469}
470
471static struct dirent64 *
472simple_readdir(mach_port_t port, uint32_t *first_entry)
473{
474    char *data;
475    int nentries = 0;
476    mach_msg_type_number_t size;
477
478    dir_readdir (port, &data, &size, *first_entry, 1, 0, &nentries);
479
480    if (nentries == 0) {
481        return NULL;
482    }
483
484    *first_entry = *first_entry + 1;
485    return (struct dirent64 *)data;
486}
487
488/* Walk through the FS tree to see what is allowed for us */
489static int
490enum_devices(mach_port_t pci_port, const char *parent, int domain,
491             int bus, int dev, int func, tree_level lev)
492{
493    int err, ret;
494    struct dirent64 *entry = NULL;
495    char path[NAME_MAX];
496    char server[NAME_MAX];
497    uint32_t reg, count = 0;
498    size_t toread;
499    mach_port_t cwd_port, device_port;
500    struct pci_device_private *d, *devices;
501
502    if (lev > LEVEL_FUNC + 1) {
503        return 0;
504    }
505    cwd_port = file_name_lookup_under (pci_port, parent,
506                                       O_DIRECTORY | O_RDONLY | O_EXEC, 0);
507    if (cwd_port == MACH_PORT_NULL) {
508        return 0;
509    }
510
511    while ((entry = simple_readdir(cwd_port, &count)) != NULL) {
512        snprintf(path, NAME_MAX, "%s/%s", parent, entry->d_name);
513        if (entry->d_type == DT_DIR) {
514            if (!strncmp(entry->d_name, ".", NAME_MAX)
515                || !strncmp(entry->d_name, "..", NAME_MAX))
516                continue;
517
518            errno = 0;
519            ret = strtol(entry->d_name, 0, 16);
520            if (errno) {
521                return errno;
522            }
523
524            /*
525             * We found a valid directory.
526             * Update the address and switch to the next level.
527             */
528            switch (lev) {
529            case LEVEL_DOMAIN:
530                domain = ret;
531                break;
532            case LEVEL_BUS:
533                bus = ret;
534                break;
535            case LEVEL_DEV:
536                dev = ret;
537                break;
538            case LEVEL_FUNC:
539                func = ret;
540                break;
541            default:
542                return 0;
543            }
544
545            err = enum_devices(pci_port, path, domain, bus, dev, func, lev+1);
546            if (err && err != EPERM && err != EACCES) {
547                return 0;
548            }
549        } else {
550            if (strncmp(entry->d_name, FILE_CONFIG_NAME, NAME_MAX))
551                /* We are looking for the config file */
552                continue;
553
554            /* We found an available virtual device, add it to our list */
555            snprintf(server, NAME_MAX, "./%04x/%02x/%02x/%01u/%s",
556                     domain, bus, dev, func,
557                     entry->d_name);
558            device_port = file_name_lookup_under(pci_port, server, O_RDONLY, 0);
559            if (device_port == MACH_PORT_NULL) {
560                return 0;
561            }
562
563            toread = sizeof(reg);
564            err = pciclient_cfg_read(device_port, PCI_VENDOR_ID, (char*)&reg,
565                                     &toread);
566            if (err) {
567                mach_port_deallocate (mach_task_self (), device_port);
568                return err;
569            }
570            if (toread != sizeof(reg)) {
571                mach_port_deallocate (mach_task_self (), device_port);
572                return -1;
573            }
574
575            devices = realloc(pci_sys->devices, (pci_sys->num_devices + 1)
576                              * sizeof(struct pci_device_private));
577            if (!devices) {
578                mach_port_deallocate (mach_task_self (), device_port);
579                return ENOMEM;
580            }
581
582            d = devices + pci_sys->num_devices;
583            memset(d, 0, sizeof(struct pci_device_private));
584
585            d->base.domain = domain;
586            d->base.bus = bus;
587            d->base.dev = dev;
588            d->base.func = func;
589            d->base.vendor_id = PCI_VENDOR(reg);
590            d->base.device_id = PCI_DEVICE(reg);
591
592            toread = sizeof(reg);
593            err = pciclient_cfg_read(device_port, PCI_CLASS, (char*)&reg,
594                                     &toread);
595            if (err) {
596                mach_port_deallocate (mach_task_self (), device_port);
597                return err;
598            }
599            if (toread != sizeof(reg)) {
600                mach_port_deallocate (mach_task_self (), device_port);
601                return -1;
602            }
603
604            d->base.device_class = reg >> 8;
605            d->base.revision = reg & 0xFF;
606
607            toread = sizeof(reg);
608            err = pciclient_cfg_read(device_port, PCI_SUB_VENDOR_ID,
609                                     (char*)&reg, &toread);
610            if (err) {
611                mach_port_deallocate (mach_task_self (), device_port);
612                return err;
613            }
614            if (toread != sizeof(reg)) {
615                mach_port_deallocate (mach_task_self (), device_port);
616                return -1;
617            }
618
619            d->base.subvendor_id = PCI_VENDOR(reg);
620            d->base.subdevice_id = PCI_DEVICE(reg);
621
622            d->device_port = device_port;
623
624            pci_sys->devices = devices;
625            pci_sys->num_devices++;
626        }
627    }
628    mach_port_deallocate (mach_task_self (), cwd_port);
629
630    return 0;
631}
632
633static const struct pci_system_methods hurd_pci_methods = {
634    .destroy = pci_system_hurd_destroy,
635    .destroy_device = pci_device_hurd_destroy_device,
636    .read_rom = pci_device_hurd_read_rom,
637    .probe = pci_device_hurd_probe,
638    .map_range = pci_device_hurd_map_range,
639    .unmap_range = pci_device_hurd_unmap_range,
640    .read = pci_device_hurd_read,
641    .write = pci_device_hurd_write,
642    .fill_capabilities = pci_fill_capabilities_generic,
643    .open_legacy_io = pci_device_x86_open_legacy_io,
644    .close_io = pci_device_x86_close_io,
645    .read32 = pci_device_x86_read32,
646    .read16 = pci_device_x86_read16,
647    .read8 = pci_device_x86_read8,
648    .write32 = pci_device_x86_write32,
649    .write16 = pci_device_x86_write16,
650    .write8 = pci_device_x86_write8,
651    .map_legacy = pci_device_hurd_map_legacy,
652    .unmap_legacy = pci_device_hurd_unmap_legacy,
653};
654
655/* Get the name of the server using libpciaccess if any */
656extern char *netfs_server_name;
657#pragma weak netfs_server_name
658
659_pci_hidden int
660pci_system_hurd_create(void)
661{
662    int err;
663    struct pci_system_hurd *pci_sys_hurd;
664    mach_port_t device_master;
665    mach_port_t pci_port = MACH_PORT_NULL;
666    mach_port_t root = MACH_PORT_NULL;
667
668    if (&netfs_server_name && netfs_server_name
669        && !strcmp(netfs_server_name, "pci-arbiter")) {
670      /* We are a PCI arbiter, try the x86 way */
671      err = pci_system_x86_create();
672      if (!err)
673          return 0;
674    }
675
676    /*
677     * From this point on, we are either a client or a nested arbiter.
678     * Both will connect to a master arbiter.
679     */
680
681    pci_sys_hurd = calloc(1, sizeof(struct pci_system_hurd));
682    if (pci_sys_hurd == NULL) {
683        x86_disable_io();
684        return ENOMEM;
685    }
686    pci_sys = &pci_sys_hurd->system;
687
688    pci_sys->methods = &hurd_pci_methods;
689
690    pci_sys->num_devices = 0;
691
692    err = get_privileged_ports (NULL, &device_master);
693
694    if(!err && device_master != MACH_PORT_NULL) {
695        err = device_open (device_master, D_READ, "pci", &pci_port);
696	mach_port_deallocate (mach_task_self (), device_master);
697    }
698
699    if (!err && pci_port != MACH_PORT_NULL) {
700        root = file_name_lookup_under (pci_port, ".", O_DIRECTORY | O_RDONLY | O_EXEC, 0);
701        device_close (pci_port);
702        mach_port_deallocate (mach_task_self (), pci_port);
703    }
704
705    if (root == MACH_PORT_NULL) {
706        root = file_name_lookup (_SERVERS_BUS_PCI, O_RDONLY, 0);
707    }
708
709    if (root == MACH_PORT_NULL) {
710        pci_system_cleanup();
711        return errno;
712    }
713
714    pci_sys_hurd->root = root;
715    err = enum_devices (root, ".", -1, -1, -1, -1, LEVEL_DOMAIN);
716    if (err) {
717        pci_system_cleanup();
718        return err;
719    }
720
721    return 0;
722}
723