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 long smh_trap(unsigned int sysnum, void *addr)
44 register long result asm("r0");
45 register void *_addr asm("r1") = addr;
48 * We need a memory clobber (aka compiler barrier) for two reasons:
49 * - The compiler needs to populate any data structures pointed to
50 * by "addr" *before* the trap instruction is called.
51 * - At least the SYSREAD function puts the result into memory pointed
52 * to by "addr", so the compiler must not use a cached version of
53 * the previous content, after the call has finished.
55 asm volatile (SMH_TRAP
57 : "0"(sysnum), "r"(USE_PTR(_addr))
63 #if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
64 static bool _semihosting_enabled = true;
65 static bool try_semihosting = true;
67 bool semihosting_enabled(void)
69 if (try_semihosting) {
70 smh_trap(SYSERRNO, NULL);
71 try_semihosting = false;
74 return _semihosting_enabled;
77 void disable_semihosting(void)
79 _semihosting_enabled = false;
84 * smh_errno() - Read the host's errno
86 * This gets the value of the host's errno and negates it. The host's errno may
87 * or may not be set, so only call this function if a previous semihosting call
90 * Return: a negative error value
92 static int smh_errno(void)
94 long ret = smh_trap(SYSERRNO, NULL);
96 if (ret > 0 && ret < INT_MAX)
101 long smh_open(const char *fname, enum smh_open_mode mode)
110 debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
113 open.len = strlen(fname);
116 /* Open the file on the host */
117 fd = smh_trap(SYSOPEN, &open);
124 * struct smg_rdwr_s - Arguments for read and write
125 * @fd: A file descriptor returned from smh_open()
126 * @memp: Pointer to a buffer of memory of at least @len bytes
127 * @len: The number of bytes to read or write
135 long smh_read(long fd, void *memp, size_t len)
138 struct smh_rdwr_s read;
140 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
146 ret = smh_trap(SYSREAD, &read);
152 long smh_write(long fd, const void *memp, size_t len, ulong *written)
155 struct smh_rdwr_s write;
157 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
160 write.memp = (void *)memp;
163 ret = smh_trap(SYSWRITE, &write);
164 *written = len - ret;
170 long smh_close(long fd)
174 debug("%s: fd %ld\n", __func__, fd);
176 ret = smh_trap(SYSCLOSE, &fd);
182 long smh_flen(long fd)
186 debug("%s: fd %ld\n", __func__, fd);
188 ret = smh_trap(SYSFLEN, &fd);
194 long smh_seek(long fd, long pos)
202 debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
207 ret = smh_trap(SYSSEEK, &seek);
215 return smh_trap(SYSREADC, NULL);
218 void smh_putc(char ch)
220 smh_trap(SYSWRITEC, &ch);
223 void smh_puts(const char *s)
225 smh_trap(SYSWRITE0, (char *)s);