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