blob: acc6b1be4f37dfb76098ac0f9dd490aa6c3b7fed [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Darwin Rambo261d2762014-06-09 11:12:59 -07002/*
Sean Anderson12a05b32022-03-22 16:59:18 -04003 * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
Darwin Rambo261d2762014-06-09 11:12:59 -07004 * Copyright 2014 Broadcom Corporation
Darwin Rambo261d2762014-06-09 11:12:59 -07005 */
6
Darwin Rambo261d2762014-06-09 11:12:59 -07007#include <common.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -06008#include <log.h>
Sean Andersonb10f7242022-03-22 16:59:14 -04009#include <semihosting.h>
Darwin Rambo261d2762014-06-09 11:12:59 -070010
11#define SYSOPEN 0x01
12#define SYSCLOSE 0x02
Sean Anderson3ea744e2022-03-22 16:59:23 -040013#define SYSWRITEC 0x03
14#define SYSWRITE0 0x04
Sean Anderson12a05b32022-03-22 16:59:18 -040015#define SYSWRITE 0x05
Darwin Rambo261d2762014-06-09 11:12:59 -070016#define SYSREAD 0x06
Sean Anderson3ea744e2022-03-22 16:59:23 -040017#define SYSREADC 0x07
Sean Anderson385d69d2022-03-22 16:59:30 -040018#define SYSISERROR 0x08
Sean Anderson12a05b32022-03-22 16:59:18 -040019#define SYSSEEK 0x0A
Darwin Rambo261d2762014-06-09 11:12:59 -070020#define SYSFLEN 0x0C
Sean Anderson80e62cc2022-03-22 16:59:16 -040021#define SYSERRNO 0x13
Darwin Rambo261d2762014-06-09 11:12:59 -070022
Andre Przywara30b315b2022-10-05 17:38:47 +010023#if defined(CONFIG_ARM64)
24 #define SMH_TRAP "hlt #0xf000"
25#elif defined(CONFIG_CPU_V7M)
26 #define SMH_TRAP "bkpt #0xAB"
27#elif defined(CONFIG_SYS_THUMB_BUILD)
28 #define SMH_TRAP "svc #0xab"
29#else
30 #define SMH_TRAP "svc #0x123456"
31#endif
32
Darwin Rambo261d2762014-06-09 11:12:59 -070033/*
34 * Call the handler
35 */
Linus Walleije769f682015-03-23 11:06:10 +010036static noinline long smh_trap(unsigned int sysnum, void *addr)
Darwin Rambo261d2762014-06-09 11:12:59 -070037{
Linus Walleij4e1ef152014-12-15 11:05:56 +010038 register long result asm("r0");
Andre Przywara30b315b2022-10-05 17:38:47 +010039
40 asm volatile (SMH_TRAP
41 : "=r" (result)
42 : "0"(sysnum), "r"(addr)
43 : "memory");
44
Darwin Rambo261d2762014-06-09 11:12:59 -070045 return result;
46}
47
Sean Anderson385d69d2022-03-22 16:59:30 -040048#if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
49static bool _semihosting_enabled = true;
50static bool try_semihosting = true;
51
52bool semihosting_enabled(void)
53{
54 if (try_semihosting) {
55 smh_trap(SYSERRNO, NULL);
56 try_semihosting = false;
57 }
58
59 return _semihosting_enabled;
60}
61
62void disable_semihosting(void)
63{
64 _semihosting_enabled = false;
65}
66#endif
67
Sean Anderson80e62cc2022-03-22 16:59:16 -040068/**
69 * smh_errno() - Read the host's errno
70 *
71 * This gets the value of the host's errno and negates it. The host's errno may
72 * or may not be set, so only call this function if a previous semihosting call
73 * has failed.
74 *
75 * Return: a negative error value
Linus Walleij9be5c662014-12-15 11:06:05 +010076 */
Sean Anderson80e62cc2022-03-22 16:59:16 -040077static int smh_errno(void)
78{
79 long ret = smh_trap(SYSERRNO, NULL);
80
81 if (ret > 0 && ret < INT_MAX)
82 return -ret;
83 return -EIO;
84}
85
Sean Andersoneff77c32022-03-22 16:59:15 -040086long smh_open(const char *fname, enum smh_open_mode mode)
Linus Walleij9be5c662014-12-15 11:06:05 +010087{
88 long fd;
Linus Walleij9be5c662014-12-15 11:06:05 +010089 struct smh_open_s {
90 const char *fname;
91 unsigned long mode;
92 size_t len;
93 } open;
94
Sean Andersoneff77c32022-03-22 16:59:15 -040095 debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
Linus Walleij9be5c662014-12-15 11:06:05 +010096
97 open.fname = fname;
98 open.len = strlen(fname);
99 open.mode = mode;
100
101 /* Open the file on the host */
102 fd = smh_trap(SYSOPEN, &open);
103 if (fd == -1)
Sean Anderson80e62cc2022-03-22 16:59:16 -0400104 return smh_errno();
Linus Walleij9be5c662014-12-15 11:06:05 +0100105 return fd;
106}
107
Sean Anderson12a05b32022-03-22 16:59:18 -0400108/**
109 * struct smg_rdwr_s - Arguments for read and write
110 * @fd: A file descriptor returned from smh_open()
111 * @memp: Pointer to a buffer of memory of at least @len bytes
112 * @len: The number of bytes to read or write
113 */
114struct smh_rdwr_s {
115 long fd;
116 void *memp;
117 size_t len;
118};
119
Sean Andersonb10f7242022-03-22 16:59:14 -0400120long smh_read(long fd, void *memp, size_t len)
Linus Walleij9be5c662014-12-15 11:06:05 +0100121{
122 long ret;
Sean Anderson12a05b32022-03-22 16:59:18 -0400123 struct smh_rdwr_s read;
Linus Walleij9be5c662014-12-15 11:06:05 +0100124
Vadzim Dambrouski7bdf75c2015-10-19 19:40:15 +0300125 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
Linus Walleij9be5c662014-12-15 11:06:05 +0100126
127 read.fd = fd;
128 read.memp = memp;
129 read.len = len;
130
131 ret = smh_trap(SYSREAD, &read);
Sean Anderson80e62cc2022-03-22 16:59:16 -0400132 if (ret < 0)
133 return smh_errno();
134 return len - ret;
Linus Walleij9be5c662014-12-15 11:06:05 +0100135}
136
Sean Anderson12a05b32022-03-22 16:59:18 -0400137long smh_write(long fd, const void *memp, size_t len, ulong *written)
138{
139 long ret;
140 struct smh_rdwr_s write;
141
142 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
143
144 write.fd = fd;
145 write.memp = (void *)memp;
146 write.len = len;
147
148 ret = smh_trap(SYSWRITE, &write);
149 *written = len - ret;
150 if (ret)
151 return smh_errno();
152 return 0;
153}
154
Sean Andersonb10f7242022-03-22 16:59:14 -0400155long smh_close(long fd)
Linus Walleij9be5c662014-12-15 11:06:05 +0100156{
157 long ret;
158
159 debug("%s: fd %ld\n", __func__, fd);
160
161 ret = smh_trap(SYSCLOSE, &fd);
162 if (ret == -1)
Sean Anderson80e62cc2022-03-22 16:59:16 -0400163 return smh_errno();
164 return 0;
Linus Walleij9be5c662014-12-15 11:06:05 +0100165}
166
Sean Andersonb10f7242022-03-22 16:59:14 -0400167long smh_flen(long fd)
Linus Walleij9be5c662014-12-15 11:06:05 +0100168{
169 long ret;
170
171 debug("%s: fd %ld\n", __func__, fd);
172
173 ret = smh_trap(SYSFLEN, &fd);
174 if (ret == -1)
Sean Anderson80e62cc2022-03-22 16:59:16 -0400175 return smh_errno();
Linus Walleij9be5c662014-12-15 11:06:05 +0100176 return ret;
177}
178
Sean Anderson12a05b32022-03-22 16:59:18 -0400179long smh_seek(long fd, long pos)
180{
181 long ret;
182 struct smh_seek_s {
183 long fd;
184 long pos;
185 } seek;
186
187 debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
188
189 seek.fd = fd;
190 seek.pos = pos;
191
192 ret = smh_trap(SYSSEEK, &seek);
193 if (ret)
194 return smh_errno();
195 return 0;
196}
Sean Anderson3ea744e2022-03-22 16:59:23 -0400197
198int smh_getc(void)
199{
200 return smh_trap(SYSREADC, NULL);
201}
202
203void smh_putc(char ch)
204{
205 smh_trap(SYSWRITEC, &ch);
206}
207
208void smh_puts(const char *s)
209{
210 smh_trap(SYSWRITE0, (char *)s);
211}