1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "dm/dmrpc.h"
4#include "known_devices.h"
5#include "pci_scan.h"
6
7#include <fcntl.h>
8#include <librpc/rpc_client.h>
9#include <mos/mm/mm_types.h>
10#include <mos/syscall/usermode.h>
11#include <mos/types.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/mman.h>
16#include <sys/stat.h>
17#include <unistd.h>
18
19#define DEBUG 0
20
21// clang-format off
22#define debug_printf(fmt, ...) do { if (DEBUG) printf(fmt __VA_OPT__(,) __VA_ARGS__); } while (0)
23// clang-format on
24
25ptr_t mmio_base;
26static rpc_server_stub_t *dm;
27
28#define PCI_RPC_SERVER_NAME "drivers.pci"
29
30RPC_DECLARE_CLIENT(dm, DEVICE_MANAGER_RPCS_X)
31
32static void scan_callback(u8 bus, u8 device, u8 function, u16 vendor_id, u16 device_id, u8 base_class, u8 sub_class, u8 prog_if)
33{
34 const char *class_name = get_known_class_name(base_class, sub_class, prog_if);
35 debug_printf("PCI: %02x:%02x.%01x: [%04x:%04x] %s (%02x:%02x:%02x)\n", bus, device, function, vendor_id, device_id, class_name, base_class, sub_class, prog_if);
36 free(pointer: (void *) class_name);
37
38 const u32 location = (bus << 16) | (device << 8) | function;
39 dm_register_device(server_stub: dm, vendor: vendor_id, devid: device_id, location, mmio_base);
40}
41
42typedef struct
43{
44 u64 base_address;
45 u16 segment_group_number;
46 u8 start_pci_bus_number;
47 u8 end_pci_bus_number;
48 u32 reserved;
49} __packed acpi_mcfg_base_addr_alloc_t;
50
51typedef struct
52{
53 char signature[4];
54 u32 length;
55 u8 revision;
56 u8 checksum;
57 char oem_id[6];
58 char oem_table_id[8];
59 u32 oem_revision;
60 u32 creator_id;
61 u32 creator_revision;
62 u8 reserved[8];
63 char content[];
64} acpi_mcfg_header_t;
65
66static const acpi_mcfg_header_t *mcfg_table;
67static const acpi_mcfg_base_addr_alloc_t *base_addr_alloc;
68static size_t n_base_addr_alloc;
69
70static bool read_mcfg_table(void)
71{
72 int fd = open(path: "/sys/acpi/MCFG", O_RDONLY);
73 if (fd < 0)
74 {
75 puts(string: "pci-daemon: failed to open /sys/acpi/MCFG");
76 return false;
77 }
78
79 mcfg_table = (acpi_mcfg_header_t *) mmap(NULL, 4 KB, PROT_READ, MAP_PRIVATE, fd, 0);
80 base_addr_alloc = (acpi_mcfg_base_addr_alloc_t *) &mcfg_table->content[0];
81 close(fd);
82
83 n_base_addr_alloc = (mcfg_table->length - sizeof(acpi_mcfg_header_t)) / sizeof(acpi_mcfg_base_addr_alloc_t);
84
85 for (size_t i = 0; i < n_base_addr_alloc; i++)
86 {
87 const acpi_mcfg_base_addr_alloc_t *alloc = &base_addr_alloc[i];
88 debug_printf("pci-daemon: MCFG table: base_address=%llx\n", alloc->base_address);
89 debug_printf("pci-daemon: MCFG table: segment_group_number=%x\n", alloc->segment_group_number);
90 debug_printf("pci-daemon: MCFG table: start_pci_bus_number=%x\n", alloc->start_pci_bus_number);
91 debug_printf("pci-daemon: MCFG table: end_pci_bus_number=%x\n", alloc->end_pci_bus_number);
92 debug_printf("pci-daemon: MCFG table: reserved=%x\n", alloc->reserved);
93 }
94
95 if (n_base_addr_alloc > 1)
96 {
97 fputs(string: "pci-daemon: MCFG table: multiple base address allocators are not supported", stream: stderr);
98 return false;
99 }
100
101 mmio_base = base_addr_alloc->base_address;
102
103 // memory range
104 const ptr_t start = base_addr_alloc->base_address;
105 const ptr_t end = start + ((u32) base_addr_alloc->end_pci_bus_number - base_addr_alloc->start_pci_bus_number + 1) * 4 KB;
106 debug_printf("pci-daemon: PCI memory range: " PTR_FMT "-" PTR_FMT "\n", start, end);
107
108 // map the PCI memory range
109 const u64 size = ALIGN_UP_TO_PAGE(end - start);
110
111 fd_t memfd = open(path: "/sys/mem", O_RDWR);
112 if (memfd < 0)
113 {
114 puts(string: "pci-daemon: failed to open /sys/mem");
115 return false;
116 }
117
118 void *addr = mmap((void *) start, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, memfd, start);
119 close(fd: memfd);
120
121 MOS_UNUSED(addr);
122
123 return true;
124}
125
126int main(int argc, char **argv)
127{
128 MOS_UNUSED(argc);
129 MOS_UNUSED(argv);
130
131 read_mcfg_table();
132
133 dm = rpc_client_create(MOS_DEVICE_MANAGER_SERVICE_NAME);
134 if (!dm)
135 {
136 printf(format: "pci-daemon: failed to connect to device manager\n");
137 return 1;
138 }
139
140 syscall_arch_syscall(nr: X86_SYSCALL_IOPL_ENABLE, arg1: 0, arg2: 0, arg3: 0, arg4: 0);
141 scan_pci(callback: scan_callback);
142
143 return 0;
144}
145