1*9d72b4eaSJames Morrissey /* 2*9d72b4eaSJames Morrissey * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. 3*9d72b4eaSJames Morrissey * 4*9d72b4eaSJames Morrissey * Redistribution and use in source and binary forms, with or without 5*9d72b4eaSJames Morrissey * modification, are permitted provided that the following conditions are met: 6*9d72b4eaSJames Morrissey * 7*9d72b4eaSJames Morrissey * Redistributions of source code must retain the above copyright notice, this 8*9d72b4eaSJames Morrissey * list of conditions and the following disclaimer. 9*9d72b4eaSJames Morrissey * 10*9d72b4eaSJames Morrissey * Redistributions in binary form must reproduce the above copyright notice, 11*9d72b4eaSJames Morrissey * this list of conditions and the following disclaimer in the documentation 12*9d72b4eaSJames Morrissey * and/or other materials provided with the distribution. 13*9d72b4eaSJames Morrissey * 14*9d72b4eaSJames Morrissey * Neither the name of ARM nor the names of its contributors may be used 15*9d72b4eaSJames Morrissey * to endorse or promote products derived from this software without specific 16*9d72b4eaSJames Morrissey * prior written permission. 17*9d72b4eaSJames Morrissey * 18*9d72b4eaSJames Morrissey * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*9d72b4eaSJames Morrissey * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*9d72b4eaSJames Morrissey * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*9d72b4eaSJames Morrissey * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*9d72b4eaSJames Morrissey * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*9d72b4eaSJames Morrissey * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*9d72b4eaSJames Morrissey * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*9d72b4eaSJames Morrissey * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*9d72b4eaSJames Morrissey * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*9d72b4eaSJames Morrissey * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*9d72b4eaSJames Morrissey * POSSIBILITY OF SUCH DAMAGE. 29*9d72b4eaSJames Morrissey */ 30*9d72b4eaSJames Morrissey 31*9d72b4eaSJames Morrissey #include <assert.h> 32*9d72b4eaSJames Morrissey #include "io_storage.h" 33*9d72b4eaSJames Morrissey #include "io_driver.h" 34*9d72b4eaSJames Morrissey #include "semihosting.h" 35*9d72b4eaSJames Morrissey 36*9d72b4eaSJames Morrissey 37*9d72b4eaSJames Morrissey 38*9d72b4eaSJames Morrissey /* Identify the device type as semihosting */ 39*9d72b4eaSJames Morrissey static io_type device_type_sh(void) 40*9d72b4eaSJames Morrissey { 41*9d72b4eaSJames Morrissey return IO_TYPE_SEMIHOSTING; 42*9d72b4eaSJames Morrissey } 43*9d72b4eaSJames Morrissey 44*9d72b4eaSJames Morrissey 45*9d72b4eaSJames Morrissey /* Semi-hosting functions, device info and handle */ 46*9d72b4eaSJames Morrissey 47*9d72b4eaSJames Morrissey static int sh_dev_open(void *spec, struct io_dev_info **dev_info); 48*9d72b4eaSJames Morrissey static int sh_file_open(struct io_dev_info *dev_info, const void *spec, 49*9d72b4eaSJames Morrissey struct io_entity *entity); 50*9d72b4eaSJames Morrissey static int sh_file_seek(struct io_entity *entity, int mode, ssize_t offset); 51*9d72b4eaSJames Morrissey static int sh_file_len(struct io_entity *entity, size_t *length); 52*9d72b4eaSJames Morrissey static int sh_file_read(struct io_entity *entity, void *buffer, size_t length, 53*9d72b4eaSJames Morrissey size_t *length_read); 54*9d72b4eaSJames Morrissey static int sh_file_write(struct io_entity *entity, const void *buffer, 55*9d72b4eaSJames Morrissey size_t length, size_t *length_written); 56*9d72b4eaSJames Morrissey static int sh_file_close(struct io_entity *entity); 57*9d72b4eaSJames Morrissey 58*9d72b4eaSJames Morrissey static struct io_dev_connector sh_dev_connector = { 59*9d72b4eaSJames Morrissey .dev_open = sh_dev_open 60*9d72b4eaSJames Morrissey }; 61*9d72b4eaSJames Morrissey 62*9d72b4eaSJames Morrissey 63*9d72b4eaSJames Morrissey static struct io_dev_funcs sh_dev_funcs = { 64*9d72b4eaSJames Morrissey .type = device_type_sh, 65*9d72b4eaSJames Morrissey .open = sh_file_open, 66*9d72b4eaSJames Morrissey .seek = sh_file_seek, 67*9d72b4eaSJames Morrissey .size = sh_file_len, 68*9d72b4eaSJames Morrissey .read = sh_file_read, 69*9d72b4eaSJames Morrissey .write = sh_file_write, 70*9d72b4eaSJames Morrissey .close = sh_file_close, 71*9d72b4eaSJames Morrissey .dev_init = NULL, /* NOP */ 72*9d72b4eaSJames Morrissey .dev_close = NULL, /* NOP */ 73*9d72b4eaSJames Morrissey }; 74*9d72b4eaSJames Morrissey 75*9d72b4eaSJames Morrissey 76*9d72b4eaSJames Morrissey static struct io_dev_info sh_dev_info = { 77*9d72b4eaSJames Morrissey .funcs = &sh_dev_funcs, 78*9d72b4eaSJames Morrissey .info = (uintptr_t)NULL 79*9d72b4eaSJames Morrissey }; 80*9d72b4eaSJames Morrissey 81*9d72b4eaSJames Morrissey 82*9d72b4eaSJames Morrissey /* Open a connection to the semi-hosting device */ 83*9d72b4eaSJames Morrissey static int sh_dev_open(void *spec __unused, struct io_dev_info **dev_info) 84*9d72b4eaSJames Morrissey { 85*9d72b4eaSJames Morrissey int result = IO_SUCCESS; 86*9d72b4eaSJames Morrissey assert(dev_info != NULL); 87*9d72b4eaSJames Morrissey *dev_info = &sh_dev_info; 88*9d72b4eaSJames Morrissey return result; 89*9d72b4eaSJames Morrissey } 90*9d72b4eaSJames Morrissey 91*9d72b4eaSJames Morrissey 92*9d72b4eaSJames Morrissey /* Open a file on the semi-hosting device */ 93*9d72b4eaSJames Morrissey static int sh_file_open(struct io_dev_info *dev_info __attribute__((unused)), 94*9d72b4eaSJames Morrissey const void *spec, struct io_entity *entity) 95*9d72b4eaSJames Morrissey { 96*9d72b4eaSJames Morrissey int result = IO_FAIL; 97*9d72b4eaSJames Morrissey int sh_result = -1; 98*9d72b4eaSJames Morrissey const io_file_spec *file_spec = (io_file_spec *)spec; 99*9d72b4eaSJames Morrissey 100*9d72b4eaSJames Morrissey assert(file_spec != NULL); 101*9d72b4eaSJames Morrissey assert(entity != NULL); 102*9d72b4eaSJames Morrissey 103*9d72b4eaSJames Morrissey sh_result = semihosting_file_open(file_spec->path, file_spec->mode); 104*9d72b4eaSJames Morrissey 105*9d72b4eaSJames Morrissey if (sh_result > 0) { 106*9d72b4eaSJames Morrissey entity->info = sh_result; 107*9d72b4eaSJames Morrissey result = IO_SUCCESS; 108*9d72b4eaSJames Morrissey } else { 109*9d72b4eaSJames Morrissey result = IO_FAIL; 110*9d72b4eaSJames Morrissey } 111*9d72b4eaSJames Morrissey return result; 112*9d72b4eaSJames Morrissey } 113*9d72b4eaSJames Morrissey 114*9d72b4eaSJames Morrissey 115*9d72b4eaSJames Morrissey /* Seek to a particular file offset on the semi-hosting device */ 116*9d72b4eaSJames Morrissey static int sh_file_seek(struct io_entity *entity, int mode, ssize_t offset) 117*9d72b4eaSJames Morrissey { 118*9d72b4eaSJames Morrissey int result = IO_FAIL; 119*9d72b4eaSJames Morrissey int file_handle, sh_result; 120*9d72b4eaSJames Morrissey 121*9d72b4eaSJames Morrissey assert(entity != NULL); 122*9d72b4eaSJames Morrissey 123*9d72b4eaSJames Morrissey file_handle = (int)entity->info; 124*9d72b4eaSJames Morrissey 125*9d72b4eaSJames Morrissey sh_result = semihosting_file_seek(file_handle, offset); 126*9d72b4eaSJames Morrissey 127*9d72b4eaSJames Morrissey result = (sh_result == 0) ? IO_SUCCESS : IO_FAIL; 128*9d72b4eaSJames Morrissey 129*9d72b4eaSJames Morrissey return result; 130*9d72b4eaSJames Morrissey } 131*9d72b4eaSJames Morrissey 132*9d72b4eaSJames Morrissey 133*9d72b4eaSJames Morrissey /* Return the size of a file on the semi-hosting device */ 134*9d72b4eaSJames Morrissey static int sh_file_len(struct io_entity *entity, size_t *length) 135*9d72b4eaSJames Morrissey { 136*9d72b4eaSJames Morrissey int result = IO_FAIL; 137*9d72b4eaSJames Morrissey 138*9d72b4eaSJames Morrissey assert(entity != NULL); 139*9d72b4eaSJames Morrissey assert(length != NULL); 140*9d72b4eaSJames Morrissey 141*9d72b4eaSJames Morrissey int sh_handle = entity->info; 142*9d72b4eaSJames Morrissey int sh_result = semihosting_file_length(sh_handle); 143*9d72b4eaSJames Morrissey 144*9d72b4eaSJames Morrissey if (sh_result >= 0) { 145*9d72b4eaSJames Morrissey result = IO_SUCCESS; 146*9d72b4eaSJames Morrissey *length = (size_t)sh_result; 147*9d72b4eaSJames Morrissey } 148*9d72b4eaSJames Morrissey 149*9d72b4eaSJames Morrissey return result; 150*9d72b4eaSJames Morrissey } 151*9d72b4eaSJames Morrissey 152*9d72b4eaSJames Morrissey 153*9d72b4eaSJames Morrissey /* Read data from a file on the semi-hosting device */ 154*9d72b4eaSJames Morrissey static int sh_file_read(struct io_entity *entity, void *buffer, size_t length, 155*9d72b4eaSJames Morrissey size_t *length_read) 156*9d72b4eaSJames Morrissey { 157*9d72b4eaSJames Morrissey int result = IO_FAIL; 158*9d72b4eaSJames Morrissey int sh_result = -1; 159*9d72b4eaSJames Morrissey int bytes = length; 160*9d72b4eaSJames Morrissey int file_handle; 161*9d72b4eaSJames Morrissey 162*9d72b4eaSJames Morrissey assert(entity != NULL); 163*9d72b4eaSJames Morrissey assert(buffer != NULL); 164*9d72b4eaSJames Morrissey assert(length_read != NULL); 165*9d72b4eaSJames Morrissey 166*9d72b4eaSJames Morrissey file_handle = (int)entity->info; 167*9d72b4eaSJames Morrissey 168*9d72b4eaSJames Morrissey sh_result = semihosting_file_read(file_handle, &bytes, buffer); 169*9d72b4eaSJames Morrissey 170*9d72b4eaSJames Morrissey if (sh_result >= 0) { 171*9d72b4eaSJames Morrissey *length_read = (bytes != length) ? bytes : length; 172*9d72b4eaSJames Morrissey result = IO_SUCCESS; 173*9d72b4eaSJames Morrissey } else 174*9d72b4eaSJames Morrissey result = IO_FAIL; 175*9d72b4eaSJames Morrissey 176*9d72b4eaSJames Morrissey return result; 177*9d72b4eaSJames Morrissey } 178*9d72b4eaSJames Morrissey 179*9d72b4eaSJames Morrissey 180*9d72b4eaSJames Morrissey /* Write data to a file on the semi-hosting device */ 181*9d72b4eaSJames Morrissey static int sh_file_write(struct io_entity *entity, const void *buffer, 182*9d72b4eaSJames Morrissey size_t length, size_t *length_written) 183*9d72b4eaSJames Morrissey { 184*9d72b4eaSJames Morrissey int result = IO_FAIL; 185*9d72b4eaSJames Morrissey int sh_result = -1; 186*9d72b4eaSJames Morrissey int file_handle; 187*9d72b4eaSJames Morrissey int bytes = length; 188*9d72b4eaSJames Morrissey 189*9d72b4eaSJames Morrissey assert(entity != NULL); 190*9d72b4eaSJames Morrissey assert(buffer != NULL); 191*9d72b4eaSJames Morrissey assert(length_written != NULL); 192*9d72b4eaSJames Morrissey 193*9d72b4eaSJames Morrissey file_handle = (int)entity->info; 194*9d72b4eaSJames Morrissey 195*9d72b4eaSJames Morrissey sh_result = semihosting_file_write(file_handle, &bytes, buffer); 196*9d72b4eaSJames Morrissey 197*9d72b4eaSJames Morrissey if (sh_result >= 0) { 198*9d72b4eaSJames Morrissey *length_written = sh_result; 199*9d72b4eaSJames Morrissey result = IO_SUCCESS; 200*9d72b4eaSJames Morrissey } else 201*9d72b4eaSJames Morrissey result = IO_FAIL; 202*9d72b4eaSJames Morrissey 203*9d72b4eaSJames Morrissey return result; 204*9d72b4eaSJames Morrissey } 205*9d72b4eaSJames Morrissey 206*9d72b4eaSJames Morrissey 207*9d72b4eaSJames Morrissey /* Close a file on the semi-hosting device */ 208*9d72b4eaSJames Morrissey static int sh_file_close(struct io_entity *entity) 209*9d72b4eaSJames Morrissey { 210*9d72b4eaSJames Morrissey int result = IO_FAIL; 211*9d72b4eaSJames Morrissey int sh_result = -1; 212*9d72b4eaSJames Morrissey int file_handle; 213*9d72b4eaSJames Morrissey 214*9d72b4eaSJames Morrissey assert(entity != NULL); 215*9d72b4eaSJames Morrissey 216*9d72b4eaSJames Morrissey file_handle = (int)entity->info; 217*9d72b4eaSJames Morrissey 218*9d72b4eaSJames Morrissey sh_result = semihosting_file_close(file_handle); 219*9d72b4eaSJames Morrissey 220*9d72b4eaSJames Morrissey result = (sh_result >= 0) ? IO_SUCCESS : IO_FAIL; 221*9d72b4eaSJames Morrissey 222*9d72b4eaSJames Morrissey return result; 223*9d72b4eaSJames Morrissey } 224*9d72b4eaSJames Morrissey 225*9d72b4eaSJames Morrissey 226*9d72b4eaSJames Morrissey /* Exported functions */ 227*9d72b4eaSJames Morrissey 228*9d72b4eaSJames Morrissey /* Register the semi-hosting driver with the IO abstraction */ 229*9d72b4eaSJames Morrissey int register_io_dev_sh(struct io_dev_connector **dev_con) 230*9d72b4eaSJames Morrissey { 231*9d72b4eaSJames Morrissey int result = IO_FAIL; 232*9d72b4eaSJames Morrissey assert(dev_con != NULL); 233*9d72b4eaSJames Morrissey 234*9d72b4eaSJames Morrissey result = io_register_device(&sh_dev_info); 235*9d72b4eaSJames Morrissey if (result == IO_SUCCESS) 236*9d72b4eaSJames Morrissey *dev_con = &sh_dev_connector; 237*9d72b4eaSJames Morrissey 238*9d72b4eaSJames Morrissey return result; 239*9d72b4eaSJames Morrissey } 240