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#include <sel4/sel4.h>
14#include <platsupport/io.h>
15#include <sel4platsupport/io.h>
16#include <sel4platsupport/arch/io.h>
17#include <assert.h>
18#include <stdint.h>
19#include <utils/util.h>
20#include <vka/capops.h>
21
22typedef struct io_cookie {
23    simple_t *simple;
24    vka_t *vka;
25} io_cookie_t;
26
27static int
28sel4platsupport_io_port_in(void *cookie, uint32_t port, int io_size, uint32_t *result)
29{
30    io_cookie_t *io_cookie = cookie;
31    uint32_t last_port = port + io_size - 1;
32    cspacepath_t path;
33    int error;
34    error = vka_cspace_alloc_path(io_cookie->vka, &path);
35    if (error) {
36        ZF_LOGE("Failed to allocate slot");
37        return error;
38    }
39    error = simple_get_IOPort_cap(io_cookie->simple, port, last_port, path.root, path.capPtr, path.capDepth);
40    if (error) {
41        ZF_LOGE("Failed to get capability for IOPort range 0x%x-0x%x", port, last_port);
42        return -1;
43    }
44
45    switch (io_size) {
46    case 1: {
47        seL4_X86_IOPort_In8_t x = seL4_X86_IOPort_In8(path.capPtr, port);
48        *result = x.result;
49        error = x.error;
50        break;
51    }
52    case 2: {
53        seL4_X86_IOPort_In16_t x = seL4_X86_IOPort_In16(path.capPtr, port);
54        *result = x.result;
55        error = x.error;
56        break;
57    }
58    case 4: {
59        seL4_X86_IOPort_In32_t x = seL4_X86_IOPort_In32(path.capPtr, port);
60        *result = x.result;
61        error = x.error;
62        break;
63    }
64    default:
65        ZF_LOGE("Invalid io_size %d, expected 1, 2 or 4", io_size);
66        error = -1;
67        break;
68    }
69
70    vka_cnode_delete(&path);
71    vka_cspace_free_path(io_cookie->vka, path);
72    return error;
73}
74
75static int
76sel4platsupport_io_port_out(void *cookie, uint32_t port, int io_size, uint32_t val)
77{
78    io_cookie_t *io_cookie = cookie;
79    uint32_t last_port = port + io_size - 1;
80    cspacepath_t path;
81    int error;
82    error = vka_cspace_alloc_path(io_cookie->vka, &path);
83    if (error) {
84        ZF_LOGE("Failed to allocate slot");
85        return error;
86    }
87    error = simple_get_IOPort_cap(io_cookie->simple, port, last_port, path.root, path.capPtr, path.capDepth);
88    if (error) {
89        ZF_LOGE("Failed to get capability for IOPort range 0x%x-0x%x", port, last_port);
90        return -1;
91    }
92
93    int result;
94    switch (io_size) {
95    case 1:
96        result = seL4_X86_IOPort_Out8(path.capPtr, port, val);
97        break;
98    case 2:
99        result = seL4_X86_IOPort_Out16(path.capPtr, port, val);
100        break;
101    case 4:
102        result = seL4_X86_IOPort_Out32(path.capPtr, port, val);
103        break;
104    default:
105        ZF_LOGE("Invalid io_size %d, expected 1, 2 or 4", io_size);
106        result = -1;
107        break;
108    }
109    vka_cnode_delete(&path);
110    vka_cspace_free_path(io_cookie->vka, path);
111    return result;
112}
113
114int
115sel4platsupport_get_io_port_ops(ps_io_port_ops_t *ops, simple_t *simple, vka_t *vka)
116{
117    assert(ops != NULL);
118    assert(simple != NULL);
119    assert(vka != NULL);
120    io_cookie_t *cookie = malloc(sizeof(*cookie));
121    if (!cookie) {
122        return -1;
123    }
124    cookie->simple = simple;
125    cookie->vka = vka;
126    ops->io_port_in_fn = sel4platsupport_io_port_in;
127    ops->io_port_out_fn = sel4platsupport_io_port_out;
128    ops->cookie = (void *) cookie;
129
130    return 0;
131}
132
133int sel4platsupport_new_arch_ops(ps_io_ops_t *ops, simple_t *simple, vka_t *vka)
134{
135    if (!ops || !simple) {
136        return EINVAL;
137    }
138
139    return sel4platsupport_get_io_port_ops(&ops->io_port_ops, simple, vka);
140}
141