1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
4 * Copyright 2014 Broadcom Corporation
8 * This code has been tested on arm64/aarch64 fastmodel only. An untested
9 * placeholder exists for armv7 architectures, but since they are commonly
10 * available in silicon now, fastmodel usage makes less sense for them.
14 #include <semihosting.h>
18 #define SYSWRITEC 0x03
19 #define SYSWRITE0 0x04
23 #define SYSISERROR 0x08
31 static noinline long smh_trap(unsigned int sysnum, void *addr)
33 register long result asm("r0");
34 #if defined(CONFIG_ARM64)
35 asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr) : "memory");
36 #elif defined(CONFIG_CPU_V7M)
37 asm volatile ("bkpt #0xAB" : "=r" (result) : "0"(sysnum), "r"(addr) : "memory");
39 /* Note - untested placeholder */
40 asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr) : "memory");
45 #if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
46 static bool _semihosting_enabled = true;
47 static bool try_semihosting = true;
49 bool semihosting_enabled(void)
51 if (try_semihosting) {
52 smh_trap(SYSERRNO, NULL);
53 try_semihosting = false;
56 return _semihosting_enabled;
59 void disable_semihosting(void)
61 _semihosting_enabled = false;
66 * smh_errno() - Read the host's errno
68 * This gets the value of the host's errno and negates it. The host's errno may
69 * or may not be set, so only call this function if a previous semihosting call
72 * Return: a negative error value
74 static int smh_errno(void)
76 long ret = smh_trap(SYSERRNO, NULL);
78 if (ret > 0 && ret < INT_MAX)
83 long smh_open(const char *fname, enum smh_open_mode mode)
92 debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
95 open.len = strlen(fname);
98 /* Open the file on the host */
99 fd = smh_trap(SYSOPEN, &open);
106 * struct smg_rdwr_s - Arguments for read and write
107 * @fd: A file descriptor returned from smh_open()
108 * @memp: Pointer to a buffer of memory of at least @len bytes
109 * @len: The number of bytes to read or write
117 long smh_read(long fd, void *memp, size_t len)
120 struct smh_rdwr_s read;
122 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
128 ret = smh_trap(SYSREAD, &read);
134 long smh_write(long fd, const void *memp, size_t len, ulong *written)
137 struct smh_rdwr_s write;
139 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
142 write.memp = (void *)memp;
145 ret = smh_trap(SYSWRITE, &write);
146 *written = len - ret;
152 long smh_close(long fd)
156 debug("%s: fd %ld\n", __func__, fd);
158 ret = smh_trap(SYSCLOSE, &fd);
164 long smh_flen(long fd)
168 debug("%s: fd %ld\n", __func__, fd);
170 ret = smh_trap(SYSFLEN, &fd);
176 long smh_seek(long fd, long pos)
184 debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
189 ret = smh_trap(SYSSEEK, &seek);
197 return smh_trap(SYSREADC, NULL);
200 void smh_putc(char ch)
202 smh_trap(SYSWRITEC, &ch);
205 void smh_puts(const char *s)
207 smh_trap(SYSWRITE0, (char *)s);