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