1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#pragma once
14
15#include <autoconf.h>
16
17#include <assert.h>
18#include <sel4/sel4.h>
19#include <stdlib.h>
20#include <utils/util.h>
21#include <vka/cspacepath_t.h>
22
23/* Simple does not address initial null caps, including seL4_CapNull */
24#ifdef CONFIG_IOMMU
25#define SIMPLE_SKIPPED_INIT_CAPS 1
26#else
27/* seL4_CapIOSpace is null if IOMMU isn't supported */
28#define SIMPLE_SKIPPED_INIT_CAPS 2
29#endif
30
31/**
32 * Request a cap to the IOPorts
33 *
34 * @param data cookie for the underlying implementation
35 * @param start port number that a cap is needed to
36 * @param end port number that a cap is needed to
37 * @param root The CNode in which to put this cap
38 * @param dest The index within the CNode to put the cap
39 * @param depth of index
40 */
41typedef seL4_Error (*arch_simple_get_IOPort_cap_fn)(void *data, uint16_t start_port, uint16_t end_port, seL4_Word root, seL4_Word dest, seL4_Word depth);
42
43/**
44 * Request a cap to a specific MSI IRQ number on the system
45 *
46 * @param irq the msi irq number to get the cap for
47 * @param data cookie for the underlying implementation
48 * @param the CNode in which to put this cap
49 * @param the index within the CNode to put cap
50 * @param Depth of index
51 */
52typedef seL4_Error (*arch_simple_get_msi_fn)(void *data, seL4_CNode root, seL4_Word index,
53                                             uint8_t depth, seL4_Word pci_bus, seL4_Word pci_dev,
54                                             seL4_Word pci_func, seL4_Word handle,
55                                             seL4_Word vector);
56
57typedef seL4_Error (*arch_simple_get_ioapic_fn)(void *data, seL4_CNode root, seL4_Word index,
58                                               uint8_t depth, seL4_Word ioapic, seL4_Word pin,
59                                               seL4_Word level, seL4_Word polarity,
60                                               seL4_Word vector);
61
62/**
63 * Request a cap to a specific IRQ number on the system
64 *
65 * @param irq the irq number to get the cap for
66 * @param data cookie for the underlying implementation
67 * @param the CNode in which to put this cap
68 * @param the index within the CNode to put cap
69 * @param Depth of index
70 */
71typedef seL4_Error (*arch_simple_get_IRQ_handler_fn)(void *data, int irq, seL4_CNode cnode, seL4_Word index,
72                                                     uint8_t depth);
73
74#ifdef CONFIG_IOMMU
75/**
76 * Get the IO space capability for the specified PCI device and domain ID
77 *
78 * @param data cookie for the underlying implementation
79 * @param domainID domain ID to request
80 * @param deviceID PCI device ID
81 * @param path Path to where to put this cap
82 *
83*/
84typedef seL4_Error (*arch_simple_get_iospace_fn)(void *data, uint16_t domainID, uint16_t deviceID,
85                                                 cspacepath_t *path);
86
87#endif
88
89typedef struct arch_simple {
90    void *data;
91    arch_simple_get_IOPort_cap_fn IOPort_cap;
92#ifdef CONFIG_IOMMU
93    arch_simple_get_iospace_fn iospace;
94#endif
95    arch_simple_get_msi_fn msi;
96    arch_simple_get_IRQ_handler_fn irq;
97    arch_simple_get_ioapic_fn ioapic;
98} arch_simple_t;
99
100static inline seL4_Error
101arch_simple_get_IOPort_cap(arch_simple_t *arch_simple, uint16_t start_port, uint16_t end_port, seL4_Word root, seL4_Word dest, seL4_Word depth)
102{
103    if (!arch_simple) {
104        ZF_LOGE("Arch-simple is NULL");
105        return seL4_InvalidArgument;
106    }
107
108    if (!arch_simple->IOPort_cap) {
109        ZF_LOGE("%s not implemented", __FUNCTION__);
110        return seL4_InvalidArgument;
111    }
112
113    return arch_simple->IOPort_cap(arch_simple->data, start_port, end_port, root, dest, depth);
114}
115
116static inline seL4_Error
117arch_simple_get_msi(arch_simple_t *arch_simple, cspacepath_t path, seL4_Word pci_bus,
118                    seL4_Word pci_dev, seL4_Word pci_func, seL4_Word handle,
119                    seL4_Word vector)
120{
121    if (!arch_simple) {
122        ZF_LOGE("Arch-simple is NULL");
123        return seL4_InvalidArgument;
124    }
125
126    if (!arch_simple->msi) {
127        ZF_LOGE("%s not implemented", __FUNCTION__);
128    }
129
130    return arch_simple->msi(arch_simple->data, path.root, path.capPtr, path.capDepth, pci_bus,
131                            pci_dev, pci_func, handle, vector);
132}
133
134static inline seL4_Error
135arch_simple_get_ioapic(arch_simple_t *arch_simple, cspacepath_t path, seL4_Word ioapic,
136                       seL4_Word pin, seL4_Word level, seL4_Word polarity,
137                       seL4_Word vector)
138{
139    if (!arch_simple) {
140        ZF_LOGE("Arch-simple is NULL");
141        return seL4_InvalidArgument;
142    }
143
144    if (!arch_simple->ioapic) {
145        ZF_LOGE("%s not implemented", __FUNCTION__);
146    }
147
148    return arch_simple->ioapic(arch_simple->data, path.root, path.capPtr, path.capDepth, ioapic,
149                               pin, level, polarity, vector);
150}
151
152#ifdef CONFIG_IOMMU
153static inline seL4_CPtr
154arch_simple_get_iospace(arch_simple_t *arch_simple, uint16_t domainID, uint16_t deviceID, cspacepath_t *path)
155{
156    if (!arch_simple) {
157        ZF_LOGE("Arch-simple is NULL");
158        return seL4_CapNull;
159    }
160    if (!arch_simple->iospace) {
161        ZF_LOGE("%s not implemented", __FUNCTION__);
162        return seL4_CapNull;
163    }
164
165    return arch_simple->iospace(arch_simple->data, domainID, deviceID, path);
166}
167#endif
168
169