blob: 7595dbc4a93d11f222db33d93f42fc70fbc69d00 [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
7/*
Sean Anderson12a05b32022-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 Rambo261d2762014-06-09 11:12:59 -070011 */
12#include <common.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060013#include <log.h>
Sean Andersonb10f7242022-03-22 16:59:14 -040014#include <semihosting.h>
Darwin Rambo261d2762014-06-09 11:12:59 -070015
16#define SYSOPEN 0x01
17#define SYSCLOSE 0x02
Sean Anderson3ea744e2022-03-22 16:59:23 -040018#define SYSWRITEC 0x03
19#define SYSWRITE0 0x04
Sean Anderson12a05b32022-03-22 16:59:18 -040020#define SYSWRITE 0x05
Darwin Rambo261d2762014-06-09 11:12:59 -070021#define SYSREAD 0x06
Sean Anderson3ea744e2022-03-22 16:59:23 -040022#define SYSREADC 0x07
Sean Anderson12a05b32022-03-22 16:59:18 -040023#define SYSSEEK 0x0A
Darwin Rambo261d2762014-06-09 11:12:59 -070024#define SYSFLEN 0x0C
Sean Anderson80e62cc2022-03-22 16:59:16 -040025#define SYSERRNO 0x13
Darwin Rambo261d2762014-06-09 11:12:59 -070026
Darwin Rambo261d2762014-06-09 11:12:59 -070027/*
28 * Call the handler
29 */
Linus Walleije769f682015-03-23 11:06:10 +010030static noinline long smh_trap(unsigned int sysnum, void *addr)
Darwin Rambo261d2762014-06-09 11:12:59 -070031{
Linus Walleij4e1ef152014-12-15 11:05:56 +010032 register long result asm("r0");
Darwin Rambo261d2762014-06-09 11:12:59 -070033#if defined(CONFIG_ARM64)
34 asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr));
Vadzim Dambrouski432a6242015-10-19 19:40:14 +030035#elif defined(CONFIG_CPU_V7M)
36 asm volatile ("bkpt #0xAB" : "=r" (result) : "0"(sysnum), "r"(addr));
Darwin Rambo261d2762014-06-09 11:12:59 -070037#else
38 /* Note - untested placeholder */
39 asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr));
40#endif
41 return result;
42}
43
Sean Anderson80e62cc2022-03-22 16:59:16 -040044/**
45 * smh_errno() - Read the host's errno
46 *
47 * This gets the value of the host's errno and negates it. The host's errno may
48 * or may not be set, so only call this function if a previous semihosting call
49 * has failed.
50 *
51 * Return: a negative error value
Linus Walleij9be5c662014-12-15 11:06:05 +010052 */
Sean Anderson80e62cc2022-03-22 16:59:16 -040053static int smh_errno(void)
54{
55 long ret = smh_trap(SYSERRNO, NULL);
56
57 if (ret > 0 && ret < INT_MAX)
58 return -ret;
59 return -EIO;
60}
61
Sean Andersoneff77c32022-03-22 16:59:15 -040062long smh_open(const char *fname, enum smh_open_mode mode)
Linus Walleij9be5c662014-12-15 11:06:05 +010063{
64 long fd;
Linus Walleij9be5c662014-12-15 11:06:05 +010065 struct smh_open_s {
66 const char *fname;
67 unsigned long mode;
68 size_t len;
69 } open;
70
Sean Andersoneff77c32022-03-22 16:59:15 -040071 debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
Linus Walleij9be5c662014-12-15 11:06:05 +010072
73 open.fname = fname;
74 open.len = strlen(fname);
75 open.mode = mode;
76
77 /* Open the file on the host */
78 fd = smh_trap(SYSOPEN, &open);
79 if (fd == -1)
Sean Anderson80e62cc2022-03-22 16:59:16 -040080 return smh_errno();
Linus Walleij9be5c662014-12-15 11:06:05 +010081 return fd;
82}
83
Sean Anderson12a05b32022-03-22 16:59:18 -040084/**
85 * struct smg_rdwr_s - Arguments for read and write
86 * @fd: A file descriptor returned from smh_open()
87 * @memp: Pointer to a buffer of memory of at least @len bytes
88 * @len: The number of bytes to read or write
89 */
90struct smh_rdwr_s {
91 long fd;
92 void *memp;
93 size_t len;
94};
95
Sean Andersonb10f7242022-03-22 16:59:14 -040096long smh_read(long fd, void *memp, size_t len)
Linus Walleij9be5c662014-12-15 11:06:05 +010097{
98 long ret;
Sean Anderson12a05b32022-03-22 16:59:18 -040099 struct smh_rdwr_s read;
Linus Walleij9be5c662014-12-15 11:06:05 +0100100
Vadzim Dambrouski7bdf75c2015-10-19 19:40:15 +0300101 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
Linus Walleij9be5c662014-12-15 11:06:05 +0100102
103 read.fd = fd;
104 read.memp = memp;
105 read.len = len;
106
107 ret = smh_trap(SYSREAD, &read);
Sean Anderson80e62cc2022-03-22 16:59:16 -0400108 if (ret < 0)
109 return smh_errno();
110 return len - ret;
Linus Walleij9be5c662014-12-15 11:06:05 +0100111}
112
Sean Anderson12a05b32022-03-22 16:59:18 -0400113long smh_write(long fd, const void *memp, size_t len, ulong *written)
114{
115 long ret;
116 struct smh_rdwr_s write;
117
118 debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
119
120 write.fd = fd;
121 write.memp = (void *)memp;
122 write.len = len;
123
124 ret = smh_trap(SYSWRITE, &write);
125 *written = len - ret;
126 if (ret)
127 return smh_errno();
128 return 0;
129}
130
Sean Andersonb10f7242022-03-22 16:59:14 -0400131long smh_close(long fd)
Linus Walleij9be5c662014-12-15 11:06:05 +0100132{
133 long ret;
134
135 debug("%s: fd %ld\n", __func__, fd);
136
137 ret = smh_trap(SYSCLOSE, &fd);
138 if (ret == -1)
Sean Anderson80e62cc2022-03-22 16:59:16 -0400139 return smh_errno();
140 return 0;
Linus Walleij9be5c662014-12-15 11:06:05 +0100141}
142
Sean Andersonb10f7242022-03-22 16:59:14 -0400143long smh_flen(long fd)
Linus Walleij9be5c662014-12-15 11:06:05 +0100144{
145 long ret;
146
147 debug("%s: fd %ld\n", __func__, fd);
148
149 ret = smh_trap(SYSFLEN, &fd);
150 if (ret == -1)
Sean Anderson80e62cc2022-03-22 16:59:16 -0400151 return smh_errno();
Linus Walleij9be5c662014-12-15 11:06:05 +0100152 return ret;
153}
154
Sean Anderson12a05b32022-03-22 16:59:18 -0400155long smh_seek(long fd, long pos)
156{
157 long ret;
158 struct smh_seek_s {
159 long fd;
160 long pos;
161 } seek;
162
163 debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
164
165 seek.fd = fd;
166 seek.pos = pos;
167
168 ret = smh_trap(SYSSEEK, &seek);
169 if (ret)
170 return smh_errno();
171 return 0;
172}
Sean Anderson3ea744e2022-03-22 16:59:23 -0400173
174int smh_getc(void)
175{
176 return smh_trap(SYSREADC, NULL);
177}
178
179void smh_putc(char ch)
180{
181 smh_trap(SYSWRITEC, &ch);
182}
183
184void smh_puts(const char *s)
185{
186 smh_trap(SYSWRITE0, (char *)s);
187}