blob: 01d652a6b83c2d0950da6c982cb0b54273d9fb4b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Darwin Rambod32d4112014-06-09 11:12:59 -07002/*
Sean Anderson56e3fe82022-03-22 16:59:18 -04003 * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
Darwin Rambod32d4112014-06-09 11:12:59 -07004 * Copyright 2014 Broadcom Corporation
Darwin Rambod32d4112014-06-09 11:12:59 -07005 */
6
7/*
Sean Anderson56e3fe82022-03-22 16:59:18 -04008 * 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.
Darwin Rambod32d4112014-06-09 11:12:59 -070011 */
12#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Sean Andersonadf073a2022-03-22 16:59:14 -040014#include <semihosting.h>
Darwin Rambod32d4112014-06-09 11:12:59 -070015
16#define SYSOPEN 0x01
17#define SYSCLOSE 0x02
Sean Anderson1e9f4432022-03-22 16:59:23 -040018#define SYSWRITEC 0x03
19#define SYSWRITE0 0x04
Sean Anderson56e3fe82022-03-22 16:59:18 -040020#define SYSWRITE 0x05
Darwin Rambod32d4112014-06-09 11:12:59 -070021#define SYSREAD 0x06
Sean Anderson1e9f4432022-03-22 16:59:23 -040022#define SYSREADC 0x07
Sean Anderson52cf0f02022-03-22 16:59:30 -040023#define SYSISERROR 0x08
Sean Anderson56e3fe82022-03-22 16:59:18 -040024#define SYSSEEK 0x0A
Darwin Rambod32d4112014-06-09 11:12:59 -070025#define SYSFLEN 0x0C
Sean Anderson003eaa82022-03-22 16:59:16 -040026#define SYSERRNO 0x13
Darwin Rambod32d4112014-06-09 11:12:59 -070027
Darwin Rambod32d4112014-06-09 11:12:59 -070028/*
29 * Call the handler
30 */
Linus Walleij1c2e27e2015-03-23 11:06:10 +010031static noinline long smh_trap(unsigned int sysnum, void *addr)
Darwin Rambod32d4112014-06-09 11:12:59 -070032{
Linus Walleij6fda2652014-12-15 11:05:56 +010033 register long result asm("r0");
Darwin Rambod32d4112014-06-09 11:12:59 -070034#if defined(CONFIG_ARM64)
Sean Anderson97611c92022-08-30 16:32:27 -040035 asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr) : "memory");
Vadzim Dambrouski98d38942015-10-19 19:40:14 +030036#elif defined(CONFIG_CPU_V7M)
Sean Anderson97611c92022-08-30 16:32:27 -040037 asm volatile ("bkpt #0xAB" : "=r" (result) : "0"(sysnum), "r"(addr) : "memory");
Darwin Rambod32d4112014-06-09 11:12:59 -070038#else
39 /* Note - untested placeholder */
Sean Anderson97611c92022-08-30 16:32:27 -040040 asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr) : "memory");
Darwin Rambod32d4112014-06-09 11:12:59 -070041#endif
42 return result;
43}
44
Sean Anderson52cf0f02022-03-22 16:59:30 -040045#if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
46static bool _semihosting_enabled = true;
47static bool try_semihosting = true;
48
49bool semihosting_enabled(void)
50{
51 if (try_semihosting) {
52 smh_trap(SYSERRNO, NULL);
53 try_semihosting = false;
54 }
55
56 return _semihosting_enabled;
57}
58
59void disable_semihosting(void)
60{
61 _semihosting_enabled = false;
62}
63#endif
64
Sean Anderson003eaa82022-03-22 16:59:16 -040065/**
66 * smh_errno() - Read the host's errno
67 *
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
70 * has failed.
71 *
72 * Return: a negative error value
Darwin Rambod32d4112014-06-09 11:12:59 -070073 */
Sean Anderson003eaa82022-03-22 16:59:16 -040074static int smh_errno(void)
75{
76 long ret = smh_trap(SYSERRNO, NULL);
77
78 if (ret > 0 && ret < INT_MAX)
79 return -ret;
80 return -EIO;
81}
82
Sean Andersona3a6c692022-03-22 16:59:15 -040083long smh_open(const char *fname, enum smh_open_mode mode)
Darwin Rambod32d4112014-06-09 11:12:59 -070084{
Linus Walleij6fda2652014-12-15 11:05:56 +010085 long fd;
Linus Walleij7cc8ca82014-12-15 11:06:05 +010086 struct smh_open_s {
87 const char *fname;
88 unsigned long mode;
89 size_t len;
90 } open;
Darwin Rambod32d4112014-06-09 11:12:59 -070091
Sean Andersona3a6c692022-03-22 16:59:15 -040092 debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
Darwin Rambod32d4112014-06-09 11:12:59 -070093
Linus Walleij7cc8ca82014-12-15 11:06:05 +010094 open.fname = fname;
95 open.len = strlen(fname);
96 open.mode = mode;
Darwin Rambod32d4112014-06-09 11:12:59 -070097
Linus Walleij7cc8ca82014-12-15 11:06:05 +010098 /* Open the file on the host */
99 fd = smh_trap(SYSOPEN, &open);
100 if (fd == -1)
Sean Anderson003eaa82022-03-22 16:59:16 -0400101 return smh_errno();
Linus Walleij7cc8ca82014-12-15 11:06:05 +0100102 return fd;
Darwin Rambod32d4112014-06-09 11:12:59 -0700103}
104
Sean Anderson56e3fe82022-03-22 16:59:18 -0400105/**
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
110 */
111struct smh_rdwr_s {
112 long fd;
113 void *memp;
114 size_t len;
115};
116
Sean Andersonadf073a2022-03-22 16:59:14 -0400117long smh_read(long fd, void *memp, size_t len)
Darwin Rambod32d4112014-06-09 11:12:59 -0700118{
Linus Walleij6fda2652014-12-15 11:05:56 +0100119 long ret;
Sean Anderson56e3fe82022-03-22 16:59:18 -0400120 struct smh_rdwr_s read;
Darwin Rambod32d4112014-06-09 11:12:59 -0700121
Vadzim Dambrouski27382152015-10-19 19:40:15 +0300122 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
Darwin Rambod32d4112014-06-09 11:12:59 -0700123
124 read.fd = fd;
125 read.memp = memp;
126 read.len = len;
127
128 ret = smh_trap(SYSREAD, &read);
Sean Anderson003eaa82022-03-22 16:59:16 -0400129 if (ret < 0)
130 return smh_errno();
131 return len - ret;
Darwin Rambod32d4112014-06-09 11:12:59 -0700132}
133
Sean Anderson56e3fe82022-03-22 16:59:18 -0400134long smh_write(long fd, const void *memp, size_t len, ulong *written)
135{
136 long ret;
137 struct smh_rdwr_s write;
138
139 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
140
141 write.fd = fd;
142 write.memp = (void *)memp;
143 write.len = len;
144
145 ret = smh_trap(SYSWRITE, &write);
146 *written = len - ret;
147 if (ret)
148 return smh_errno();
149 return 0;
150}
151
Sean Andersonadf073a2022-03-22 16:59:14 -0400152long smh_close(long fd)
Darwin Rambod32d4112014-06-09 11:12:59 -0700153{
Linus Walleij6fda2652014-12-15 11:05:56 +0100154 long ret;
Darwin Rambod32d4112014-06-09 11:12:59 -0700155
Linus Walleij6fda2652014-12-15 11:05:56 +0100156 debug("%s: fd %ld\n", __func__, fd);
Darwin Rambod32d4112014-06-09 11:12:59 -0700157
Linus Walleij6fda2652014-12-15 11:05:56 +0100158 ret = smh_trap(SYSCLOSE, &fd);
Darwin Rambod32d4112014-06-09 11:12:59 -0700159 if (ret == -1)
Sean Anderson003eaa82022-03-22 16:59:16 -0400160 return smh_errno();
161 return 0;
Darwin Rambod32d4112014-06-09 11:12:59 -0700162}
163
Sean Andersonadf073a2022-03-22 16:59:14 -0400164long smh_flen(long fd)
Darwin Rambod32d4112014-06-09 11:12:59 -0700165{
Linus Walleij6fda2652014-12-15 11:05:56 +0100166 long ret;
Darwin Rambod32d4112014-06-09 11:12:59 -0700167
Linus Walleij6fda2652014-12-15 11:05:56 +0100168 debug("%s: fd %ld\n", __func__, fd);
Darwin Rambod32d4112014-06-09 11:12:59 -0700169
Linus Walleij6fda2652014-12-15 11:05:56 +0100170 ret = smh_trap(SYSFLEN, &fd);
Darwin Rambod32d4112014-06-09 11:12:59 -0700171 if (ret == -1)
Sean Anderson003eaa82022-03-22 16:59:16 -0400172 return smh_errno();
Darwin Rambod32d4112014-06-09 11:12:59 -0700173 return ret;
174}
175
Sean Anderson56e3fe82022-03-22 16:59:18 -0400176long smh_seek(long fd, long pos)
177{
178 long ret;
179 struct smh_seek_s {
180 long fd;
181 long pos;
182 } seek;
183
184 debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
185
186 seek.fd = fd;
187 seek.pos = pos;
188
189 ret = smh_trap(SYSSEEK, &seek);
190 if (ret)
191 return smh_errno();
192 return 0;
193}
Sean Anderson1e9f4432022-03-22 16:59:23 -0400194
195int smh_getc(void)
196{
197 return smh_trap(SYSREADC, NULL);
198}
199
200void smh_putc(char ch)
201{
202 smh_trap(SYSWRITEC, &ch);
203}
204
205void smh_puts(const char *s)
206{
207 smh_trap(SYSWRITE0, (char *)s);
208}