1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
4 * Copyright 2014 Broadcom Corporation
9 #include <semihosting.h>
13 #define SYSWRITEC 0x03
14 #define SYSWRITE0 0x04
18 #define SYSISERROR 0x08
24 * Macro to force the compiler to *populate* memory (for an array or struct)
25 * before passing the pointer to an inline assembly call.
27 #define USE_PTR(ptr) *(const char (*)[]) (ptr)
29 #if defined(CONFIG_ARM64)
30 #define SMH_TRAP "hlt #0xf000"
31 #elif defined(CONFIG_CPU_V7M)
32 #define SMH_TRAP "bkpt #0xAB"
33 #elif defined(CONFIG_SYS_THUMB_BUILD)
34 #define SMH_TRAP "svc #0xab"
36 #define SMH_TRAP "svc #0x123456"
42 static noinline long smh_trap(unsigned int sysnum, void *addr)
44 register long result asm("r0");
47 * We need a memory clobber (aka compiler barrier) for two reasons:
48 * - The compiler needs to populate any data structures pointed to
49 * by "addr" *before* the trap instruction is called.
50 * - At least the SYSREAD function puts the result into memory pointed
51 * to by "addr", so the compiler must not use a cached version of
52 * the previous content, after the call has finished.
54 asm volatile (SMH_TRAP
56 : "0"(sysnum), "r"(USE_PTR(addr))
62 #if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
63 static bool _semihosting_enabled = true;
64 static bool try_semihosting = true;
66 bool semihosting_enabled(void)
68 if (try_semihosting) {
69 smh_trap(SYSERRNO, NULL);
70 try_semihosting = false;
73 return _semihosting_enabled;
76 void disable_semihosting(void)
78 _semihosting_enabled = false;
83 * smh_errno() - Read the host's errno
85 * This gets the value of the host's errno and negates it. The host's errno may
86 * or may not be set, so only call this function if a previous semihosting call
89 * Return: a negative error value
91 static int smh_errno(void)
93 long ret = smh_trap(SYSERRNO, NULL);
95 if (ret > 0 && ret < INT_MAX)
100 long smh_open(const char *fname, enum smh_open_mode mode)
109 debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
112 open.len = strlen(fname);
115 /* Open the file on the host */
116 fd = smh_trap(SYSOPEN, &open);
123 * struct smg_rdwr_s - Arguments for read and write
124 * @fd: A file descriptor returned from smh_open()
125 * @memp: Pointer to a buffer of memory of at least @len bytes
126 * @len: The number of bytes to read or write
134 long smh_read(long fd, void *memp, size_t len)
137 struct smh_rdwr_s read;
139 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
145 ret = smh_trap(SYSREAD, &read);
151 long smh_write(long fd, const void *memp, size_t len, ulong *written)
154 struct smh_rdwr_s write;
156 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
159 write.memp = (void *)memp;
162 ret = smh_trap(SYSWRITE, &write);
163 *written = len - ret;
169 long smh_close(long fd)
173 debug("%s: fd %ld\n", __func__, fd);
175 ret = smh_trap(SYSCLOSE, &fd);
181 long smh_flen(long fd)
185 debug("%s: fd %ld\n", __func__, fd);
187 ret = smh_trap(SYSFLEN, &fd);
193 long smh_seek(long fd, long pos)
201 debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
206 ret = smh_trap(SYSSEEK, &seek);
214 return smh_trap(SYSREADC, NULL);
217 void smh_putc(char ch)
219 smh_trap(SYSWRITEC, &ch);
222 void smh_puts(const char *s)
224 smh_trap(SYSWRITE0, (char *)s);