board: starfive: support Milk-V Mars board
[pandora-u-boot.git] / lib / semihosting.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
4  * Copyright 2014 Broadcom Corporation
5  */
6
7 #include <log.h>
8 #include <semihosting.h>
9 #include <linux/errno.h>
10 #include <linux/string.h>
11
12 #define SYSOPEN         0x01
13 #define SYSCLOSE        0x02
14 #define SYSWRITEC       0x03
15 #define SYSWRITE0       0x04
16 #define SYSWRITE        0x05
17 #define SYSREAD         0x06
18 #define SYSREADC        0x07
19 #define SYSISERROR      0x08
20 #define SYSSEEK         0x0A
21 #define SYSFLEN         0x0C
22 #define SYSERRNO        0x13
23
24 #if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
25 static bool _semihosting_enabled = true;
26 static bool try_semihosting = true;
27
28 bool semihosting_enabled(void)
29 {
30         if (try_semihosting) {
31                 smh_trap(SYSERRNO, NULL);
32                 try_semihosting = false;
33         }
34
35         return _semihosting_enabled;
36 }
37
38 void disable_semihosting(void)
39 {
40         _semihosting_enabled = false;
41 }
42 #endif
43
44 /**
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
52  */
53 static 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
62 long smh_open(const char *fname, enum smh_open_mode mode)
63 {
64         long fd;
65         struct smh_open_s {
66                 const char *fname;
67                 unsigned long mode;
68                 size_t len;
69         } open;
70
71         debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
72
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)
80                 return smh_errno();
81         return fd;
82 }
83
84 /**
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  */
90 struct smh_rdwr_s {
91         long fd;
92         void *memp;
93         size_t len;
94 };
95
96 long smh_read(long fd, void *memp, size_t len)
97 {
98         long ret;
99         struct smh_rdwr_s read;
100
101         debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
102
103         read.fd = fd;
104         read.memp = memp;
105         read.len = len;
106
107         ret = smh_trap(SYSREAD, &read);
108         if (ret < 0)
109                 return smh_errno();
110         return len - ret;
111 }
112
113 long 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
131 long smh_close(long fd)
132 {
133         long ret;
134
135         debug("%s: fd %ld\n", __func__, fd);
136
137         ret = smh_trap(SYSCLOSE, &fd);
138         if (ret == -1)
139                 return smh_errno();
140         return 0;
141 }
142
143 long smh_flen(long fd)
144 {
145         long ret;
146
147         debug("%s: fd %ld\n", __func__, fd);
148
149         ret = smh_trap(SYSFLEN, &fd);
150         if (ret == -1)
151                 return smh_errno();
152         return ret;
153 }
154
155 long 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 }
173
174 int smh_getc(void)
175 {
176         return smh_trap(SYSREADC, NULL);
177 }
178
179 void smh_putc(char ch)
180 {
181         smh_trap(SYSWRITEC, &ch);
182 }
183
184 void smh_puts(const char *s)
185 {
186         smh_trap(SYSWRITE0, (char *)s);
187 }