1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <platform_def.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <drivers/io/io_driver.h> 12*91f16700Schasinglulu #include <drivers/io/io_semihosting.h> 13*91f16700Schasinglulu #include <drivers/io/io_storage.h> 14*91f16700Schasinglulu #include <lib/semihosting.h> 15*91f16700Schasinglulu 16*91f16700Schasinglulu /* Identify the device type as semihosting */ 17*91f16700Schasinglulu static io_type_t device_type_sh(void) 18*91f16700Schasinglulu { 19*91f16700Schasinglulu return IO_TYPE_SEMIHOSTING; 20*91f16700Schasinglulu } 21*91f16700Schasinglulu 22*91f16700Schasinglulu 23*91f16700Schasinglulu /* Semi-hosting functions, device info and handle */ 24*91f16700Schasinglulu 25*91f16700Schasinglulu static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 26*91f16700Schasinglulu static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec, 27*91f16700Schasinglulu io_entity_t *entity); 28*91f16700Schasinglulu static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset); 29*91f16700Schasinglulu static int sh_file_len(io_entity_t *entity, size_t *length); 30*91f16700Schasinglulu static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 31*91f16700Schasinglulu size_t *length_read); 32*91f16700Schasinglulu static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 33*91f16700Schasinglulu size_t length, size_t *length_written); 34*91f16700Schasinglulu static int sh_file_close(io_entity_t *entity); 35*91f16700Schasinglulu 36*91f16700Schasinglulu static const io_dev_connector_t sh_dev_connector = { 37*91f16700Schasinglulu .dev_open = sh_dev_open 38*91f16700Schasinglulu }; 39*91f16700Schasinglulu 40*91f16700Schasinglulu 41*91f16700Schasinglulu static const io_dev_funcs_t sh_dev_funcs = { 42*91f16700Schasinglulu .type = device_type_sh, 43*91f16700Schasinglulu .open = sh_file_open, 44*91f16700Schasinglulu .seek = sh_file_seek, 45*91f16700Schasinglulu .size = sh_file_len, 46*91f16700Schasinglulu .read = sh_file_read, 47*91f16700Schasinglulu .write = sh_file_write, 48*91f16700Schasinglulu .close = sh_file_close, 49*91f16700Schasinglulu .dev_init = NULL, /* NOP */ 50*91f16700Schasinglulu .dev_close = NULL, /* NOP */ 51*91f16700Schasinglulu }; 52*91f16700Schasinglulu 53*91f16700Schasinglulu 54*91f16700Schasinglulu static io_dev_info_t sh_dev_info = { 55*91f16700Schasinglulu .funcs = &sh_dev_funcs, 56*91f16700Schasinglulu .info = (uintptr_t)NULL 57*91f16700Schasinglulu }; 58*91f16700Schasinglulu 59*91f16700Schasinglulu 60*91f16700Schasinglulu /* Open a connection to the semi-hosting device */ 61*91f16700Schasinglulu static int sh_dev_open(const uintptr_t dev_spec __unused, 62*91f16700Schasinglulu io_dev_info_t **dev_info) 63*91f16700Schasinglulu { 64*91f16700Schasinglulu assert(dev_info != NULL); 65*91f16700Schasinglulu *dev_info = &sh_dev_info; 66*91f16700Schasinglulu return 0; 67*91f16700Schasinglulu } 68*91f16700Schasinglulu 69*91f16700Schasinglulu 70*91f16700Schasinglulu /* Open a file on the semi-hosting device */ 71*91f16700Schasinglulu static int sh_file_open(io_dev_info_t *dev_info __unused, 72*91f16700Schasinglulu const uintptr_t spec, io_entity_t *entity) 73*91f16700Schasinglulu { 74*91f16700Schasinglulu int result = -ENOENT; 75*91f16700Schasinglulu long sh_result; 76*91f16700Schasinglulu const io_file_spec_t *file_spec = (const io_file_spec_t *)spec; 77*91f16700Schasinglulu 78*91f16700Schasinglulu assert(file_spec != NULL); 79*91f16700Schasinglulu assert(entity != NULL); 80*91f16700Schasinglulu 81*91f16700Schasinglulu sh_result = semihosting_file_open(file_spec->path, file_spec->mode); 82*91f16700Schasinglulu 83*91f16700Schasinglulu if (sh_result > 0) { 84*91f16700Schasinglulu entity->info = (uintptr_t)sh_result; 85*91f16700Schasinglulu result = 0; 86*91f16700Schasinglulu } 87*91f16700Schasinglulu return result; 88*91f16700Schasinglulu } 89*91f16700Schasinglulu 90*91f16700Schasinglulu 91*91f16700Schasinglulu /* Seek to a particular file offset on the semi-hosting device */ 92*91f16700Schasinglulu static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset) 93*91f16700Schasinglulu { 94*91f16700Schasinglulu long file_handle, sh_result; 95*91f16700Schasinglulu 96*91f16700Schasinglulu assert(entity != NULL); 97*91f16700Schasinglulu 98*91f16700Schasinglulu file_handle = (long)entity->info; 99*91f16700Schasinglulu 100*91f16700Schasinglulu sh_result = semihosting_file_seek(file_handle, (ssize_t)offset); 101*91f16700Schasinglulu 102*91f16700Schasinglulu return (sh_result == 0) ? 0 : -ENOENT; 103*91f16700Schasinglulu } 104*91f16700Schasinglulu 105*91f16700Schasinglulu 106*91f16700Schasinglulu /* Return the size of a file on the semi-hosting device */ 107*91f16700Schasinglulu static int sh_file_len(io_entity_t *entity, size_t *length) 108*91f16700Schasinglulu { 109*91f16700Schasinglulu int result = -ENOENT; 110*91f16700Schasinglulu 111*91f16700Schasinglulu assert(entity != NULL); 112*91f16700Schasinglulu assert(length != NULL); 113*91f16700Schasinglulu 114*91f16700Schasinglulu long sh_handle = (long)entity->info; 115*91f16700Schasinglulu long sh_result = semihosting_file_length(sh_handle); 116*91f16700Schasinglulu 117*91f16700Schasinglulu if (sh_result >= 0) { 118*91f16700Schasinglulu result = 0; 119*91f16700Schasinglulu *length = (size_t)sh_result; 120*91f16700Schasinglulu } 121*91f16700Schasinglulu 122*91f16700Schasinglulu return result; 123*91f16700Schasinglulu } 124*91f16700Schasinglulu 125*91f16700Schasinglulu 126*91f16700Schasinglulu /* Read data from a file on the semi-hosting device */ 127*91f16700Schasinglulu static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 128*91f16700Schasinglulu size_t *length_read) 129*91f16700Schasinglulu { 130*91f16700Schasinglulu int result = -ENOENT; 131*91f16700Schasinglulu long sh_result; 132*91f16700Schasinglulu size_t bytes = length; 133*91f16700Schasinglulu long file_handle; 134*91f16700Schasinglulu 135*91f16700Schasinglulu assert(entity != NULL); 136*91f16700Schasinglulu assert(length_read != NULL); 137*91f16700Schasinglulu 138*91f16700Schasinglulu file_handle = (long)entity->info; 139*91f16700Schasinglulu 140*91f16700Schasinglulu sh_result = semihosting_file_read(file_handle, &bytes, buffer); 141*91f16700Schasinglulu 142*91f16700Schasinglulu if (sh_result >= 0) { 143*91f16700Schasinglulu *length_read = (bytes != length) ? bytes : length; 144*91f16700Schasinglulu result = 0; 145*91f16700Schasinglulu } 146*91f16700Schasinglulu 147*91f16700Schasinglulu return result; 148*91f16700Schasinglulu } 149*91f16700Schasinglulu 150*91f16700Schasinglulu 151*91f16700Schasinglulu /* Write data to a file on the semi-hosting device */ 152*91f16700Schasinglulu static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 153*91f16700Schasinglulu size_t length, size_t *length_written) 154*91f16700Schasinglulu { 155*91f16700Schasinglulu long sh_result; 156*91f16700Schasinglulu long file_handle; 157*91f16700Schasinglulu size_t bytes = length; 158*91f16700Schasinglulu 159*91f16700Schasinglulu assert(entity != NULL); 160*91f16700Schasinglulu assert(length_written != NULL); 161*91f16700Schasinglulu 162*91f16700Schasinglulu file_handle = (long)entity->info; 163*91f16700Schasinglulu 164*91f16700Schasinglulu sh_result = semihosting_file_write(file_handle, &bytes, buffer); 165*91f16700Schasinglulu 166*91f16700Schasinglulu *length_written = length - bytes; 167*91f16700Schasinglulu 168*91f16700Schasinglulu return (sh_result == 0) ? 0 : -ENOENT; 169*91f16700Schasinglulu } 170*91f16700Schasinglulu 171*91f16700Schasinglulu 172*91f16700Schasinglulu /* Close a file on the semi-hosting device */ 173*91f16700Schasinglulu static int sh_file_close(io_entity_t *entity) 174*91f16700Schasinglulu { 175*91f16700Schasinglulu long sh_result; 176*91f16700Schasinglulu long file_handle; 177*91f16700Schasinglulu 178*91f16700Schasinglulu assert(entity != NULL); 179*91f16700Schasinglulu 180*91f16700Schasinglulu file_handle = (long)entity->info; 181*91f16700Schasinglulu 182*91f16700Schasinglulu sh_result = semihosting_file_close(file_handle); 183*91f16700Schasinglulu 184*91f16700Schasinglulu return (sh_result >= 0) ? 0 : -ENOENT; 185*91f16700Schasinglulu } 186*91f16700Schasinglulu 187*91f16700Schasinglulu 188*91f16700Schasinglulu /* Exported functions */ 189*91f16700Schasinglulu 190*91f16700Schasinglulu /* Register the semi-hosting driver with the IO abstraction */ 191*91f16700Schasinglulu int register_io_dev_sh(const io_dev_connector_t **dev_con) 192*91f16700Schasinglulu { 193*91f16700Schasinglulu int result; 194*91f16700Schasinglulu assert(dev_con != NULL); 195*91f16700Schasinglulu 196*91f16700Schasinglulu result = io_register_device(&sh_dev_info); 197*91f16700Schasinglulu if (result == 0) 198*91f16700Schasinglulu *dev_con = &sh_dev_connector; 199*91f16700Schasinglulu 200*91f16700Schasinglulu return result; 201*91f16700Schasinglulu } 202