| /* |
| * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) |
| * |
| * SPDX-License-Identifier: BSD-2-Clause |
| */ |
| |
| #include <sel4/sel4.h> |
| #include <platsupport/io.h> |
| #include <sel4platsupport/io.h> |
| #include <sel4platsupport/arch/io.h> |
| #include <assert.h> |
| #include <stdint.h> |
| #include <utils/util.h> |
| #include <vka/capops.h> |
| |
| typedef struct io_cookie { |
| simple_t *simple; |
| vka_t *vka; |
| } io_cookie_t; |
| |
| static int |
| sel4platsupport_io_port_in(void *cookie, uint32_t port, int io_size, uint32_t *result) |
| { |
| io_cookie_t *io_cookie = cookie; |
| uint32_t last_port = port + io_size - 1; |
| cspacepath_t path; |
| int error; |
| error = vka_cspace_alloc_path(io_cookie->vka, &path); |
| if (error) { |
| ZF_LOGE("Failed to allocate slot"); |
| return error; |
| } |
| error = simple_get_IOPort_cap(io_cookie->simple, port, last_port, path.root, path.capPtr, path.capDepth); |
| if (error) { |
| ZF_LOGE("Failed to get capability for IOPort range 0x%x-0x%x", port, last_port); |
| return -1; |
| } |
| |
| switch (io_size) { |
| case 1: { |
| seL4_X86_IOPort_In8_t x = seL4_X86_IOPort_In8(path.capPtr, port); |
| *result = x.result; |
| error = x.error; |
| break; |
| } |
| case 2: { |
| seL4_X86_IOPort_In16_t x = seL4_X86_IOPort_In16(path.capPtr, port); |
| *result = x.result; |
| error = x.error; |
| break; |
| } |
| case 4: { |
| seL4_X86_IOPort_In32_t x = seL4_X86_IOPort_In32(path.capPtr, port); |
| *result = x.result; |
| error = x.error; |
| break; |
| } |
| default: |
| ZF_LOGE("Invalid io_size %d, expected 1, 2 or 4", io_size); |
| error = -1; |
| break; |
| } |
| |
| vka_cnode_delete(&path); |
| vka_cspace_free_path(io_cookie->vka, path); |
| return error; |
| } |
| |
| static int |
| sel4platsupport_io_port_out(void *cookie, uint32_t port, int io_size, uint32_t val) |
| { |
| io_cookie_t *io_cookie = cookie; |
| uint32_t last_port = port + io_size - 1; |
| cspacepath_t path; |
| int error; |
| error = vka_cspace_alloc_path(io_cookie->vka, &path); |
| if (error) { |
| ZF_LOGE("Failed to allocate slot"); |
| return error; |
| } |
| error = simple_get_IOPort_cap(io_cookie->simple, port, last_port, path.root, path.capPtr, path.capDepth); |
| if (error) { |
| ZF_LOGE("Failed to get capability for IOPort range 0x%x-0x%x", port, last_port); |
| return -1; |
| } |
| |
| int result; |
| switch (io_size) { |
| case 1: |
| result = seL4_X86_IOPort_Out8(path.capPtr, port, val); |
| break; |
| case 2: |
| result = seL4_X86_IOPort_Out16(path.capPtr, port, val); |
| break; |
| case 4: |
| result = seL4_X86_IOPort_Out32(path.capPtr, port, val); |
| break; |
| default: |
| ZF_LOGE("Invalid io_size %d, expected 1, 2 or 4", io_size); |
| result = -1; |
| break; |
| } |
| vka_cnode_delete(&path); |
| vka_cspace_free_path(io_cookie->vka, path); |
| return result; |
| } |
| |
| int |
| sel4platsupport_get_io_port_ops(ps_io_port_ops_t *ops, simple_t *simple, vka_t *vka) |
| { |
| assert(ops != NULL); |
| assert(simple != NULL); |
| assert(vka != NULL); |
| io_cookie_t *cookie = malloc(sizeof(*cookie)); |
| if (!cookie) { |
| return -1; |
| } |
| cookie->simple = simple; |
| cookie->vka = vka; |
| ops->io_port_in_fn = sel4platsupport_io_port_in; |
| ops->io_port_out_fn = sel4platsupport_io_port_out; |
| ops->cookie = (void *) cookie; |
| |
| return 0; |
| } |
| |
| int sel4platsupport_new_arch_ops(ps_io_ops_t *ops, simple_t *simple, vka_t *vka) |
| { |
| if (!ops || !simple) { |
| return EINVAL; |
| } |
| |
| return sel4platsupport_get_io_port_ops(&ops->io_port_ops, simple, vka); |
| } |