1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com> 4 * Copyright 2014 Broadcom Corporation 5 */ 6 7#include <log.h> 8#include <semihosting.h> 9#include <linux/errno.h> 10#include <linux/string.h> 11 12#define SYSOPEN 0x01 13#define SYSCLOSE 0x02 14#define SYSWRITEC 0x03 15#define SYSWRITE0 0x04 16#define SYSWRITE 0x05 17#define SYSREAD 0x06 18#define SYSREADC 0x07 19#define SYSISERROR 0x08 20#define SYSSEEK 0x0A 21#define SYSFLEN 0x0C 22#define SYSERRNO 0x13 23 24#if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK) 25static bool _semihosting_enabled = true; 26static bool try_semihosting = true; 27 28bool semihosting_enabled(void) 29{ 30 if (try_semihosting) { 31 smh_trap(SYSERRNO, NULL); 32 try_semihosting = false; 33 } 34 35 return _semihosting_enabled; 36} 37 38void disable_semihosting(void) 39{ 40 _semihosting_enabled = false; 41} 42#endif 43 44/** 45 * smh_errno() - Read the host's errno 46 * 47 * This gets the value of the host's errno and negates it. The host's errno may 48 * or may not be set, so only call this function if a previous semihosting call 49 * has failed. 50 * 51 * Return: a negative error value 52 */ 53static int smh_errno(void) 54{ 55 long ret = smh_trap(SYSERRNO, NULL); 56 57 if (ret > 0 && ret < INT_MAX) 58 return -ret; 59 return -EIO; 60} 61 62long smh_open(const char *fname, enum smh_open_mode mode) 63{ 64 long fd; 65 struct smh_open_s { 66 const char *fname; 67 unsigned long mode; 68 size_t len; 69 } open; 70 71 debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode); 72 73 open.fname = fname; 74 open.len = strlen(fname); 75 open.mode = mode; 76 77 /* Open the file on the host */ 78 fd = smh_trap(SYSOPEN, &open); 79 if (fd == -1) 80 return smh_errno(); 81 return fd; 82} 83 84/** 85 * struct smg_rdwr_s - Arguments for read and write 86 * @fd: A file descriptor returned from smh_open() 87 * @memp: Pointer to a buffer of memory of at least @len bytes 88 * @len: The number of bytes to read or write 89 */ 90struct smh_rdwr_s { 91 long fd; 92 void *memp; 93 size_t len; 94}; 95 96long smh_read(long fd, void *memp, size_t len) 97{ 98 long ret; 99 struct smh_rdwr_s read; 100 101 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len); 102 103 read.fd = fd; 104 read.memp = memp; 105 read.len = len; 106 107 ret = smh_trap(SYSREAD, &read); 108 if (ret < 0) 109 return smh_errno(); 110 return len - ret; 111} 112 113long smh_write(long fd, const void *memp, size_t len, ulong *written) 114{ 115 long ret; 116 struct smh_rdwr_s write; 117 118 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len); 119 120 write.fd = fd; 121 write.memp = (void *)memp; 122 write.len = len; 123 124 ret = smh_trap(SYSWRITE, &write); 125 *written = len - ret; 126 if (ret) 127 return smh_errno(); 128 return 0; 129} 130 131long smh_close(long fd) 132{ 133 long ret; 134 135 debug("%s: fd %ld\n", __func__, fd); 136 137 ret = smh_trap(SYSCLOSE, &fd); 138 if (ret == -1) 139 return smh_errno(); 140 return 0; 141} 142 143long smh_flen(long fd) 144{ 145 long ret; 146 147 debug("%s: fd %ld\n", __func__, fd); 148 149 ret = smh_trap(SYSFLEN, &fd); 150 if (ret == -1) 151 return smh_errno(); 152 return ret; 153} 154 155long smh_seek(long fd, long pos) 156{ 157 long ret; 158 struct smh_seek_s { 159 long fd; 160 long pos; 161 } seek; 162 163 debug("%s: fd %ld pos %ld\n", __func__, fd, pos); 164 165 seek.fd = fd; 166 seek.pos = pos; 167 168 ret = smh_trap(SYSSEEK, &seek); 169 if (ret) 170 return smh_errno(); 171 return 0; 172} 173 174int smh_getc(void) 175{ 176 return smh_trap(SYSREADC, NULL); 177} 178 179void smh_putc(char ch) 180{ 181 smh_trap(SYSWRITEC, &ch); 182} 183 184void smh_puts(const char *s) 185{ 186 smh_trap(SYSWRITE0, (char *)s); 187} 188