Merge tag 'u-boot-imx-20230923' of https://source.denx.de/u-boot/custodians/u-boot-imx
[platform/kernel/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 <common.h>
8 #include <log.h>
9 #include <semihosting.h>
10
11 #define SYSOPEN         0x01
12 #define SYSCLOSE        0x02
13 #define SYSWRITEC       0x03
14 #define SYSWRITE0       0x04
15 #define SYSWRITE        0x05
16 #define SYSREAD         0x06
17 #define SYSREADC        0x07
18 #define SYSISERROR      0x08
19 #define SYSSEEK         0x0A
20 #define SYSFLEN         0x0C
21 #define SYSERRNO        0x13
22
23 #if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
24 static bool _semihosting_enabled = true;
25 static bool try_semihosting = true;
26
27 bool semihosting_enabled(void)
28 {
29         if (try_semihosting) {
30                 smh_trap(SYSERRNO, NULL);
31                 try_semihosting = false;
32         }
33
34         return _semihosting_enabled;
35 }
36
37 void disable_semihosting(void)
38 {
39         _semihosting_enabled = false;
40 }
41 #endif
42
43 /**
44  * smh_errno() - Read the host's errno
45  *
46  * This gets the value of the host's errno and negates it. The host's errno may
47  * or may not be set, so only call this function if a previous semihosting call
48  * has failed.
49  *
50  * Return: a negative error value
51  */
52 static int smh_errno(void)
53 {
54         long ret = smh_trap(SYSERRNO, NULL);
55
56         if (ret > 0 && ret < INT_MAX)
57                 return -ret;
58         return -EIO;
59 }
60
61 long smh_open(const char *fname, enum smh_open_mode mode)
62 {
63         long fd;
64         struct smh_open_s {
65                 const char *fname;
66                 unsigned long mode;
67                 size_t len;
68         } open;
69
70         debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
71
72         open.fname = fname;
73         open.len = strlen(fname);
74         open.mode = mode;
75
76         /* Open the file on the host */
77         fd = smh_trap(SYSOPEN, &open);
78         if (fd == -1)
79                 return smh_errno();
80         return fd;
81 }
82
83 /**
84  * struct smg_rdwr_s - Arguments for read and write
85  * @fd: A file descriptor returned from smh_open()
86  * @memp: Pointer to a buffer of memory of at least @len bytes
87  * @len: The number of bytes to read or write
88  */
89 struct smh_rdwr_s {
90         long fd;
91         void *memp;
92         size_t len;
93 };
94
95 long smh_read(long fd, void *memp, size_t len)
96 {
97         long ret;
98         struct smh_rdwr_s read;
99
100         debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
101
102         read.fd = fd;
103         read.memp = memp;
104         read.len = len;
105
106         ret = smh_trap(SYSREAD, &read);
107         if (ret < 0)
108                 return smh_errno();
109         return len - ret;
110 }
111
112 long smh_write(long fd, const void *memp, size_t len, ulong *written)
113 {
114         long ret;
115         struct smh_rdwr_s write;
116
117         debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
118
119         write.fd = fd;
120         write.memp = (void *)memp;
121         write.len = len;
122
123         ret = smh_trap(SYSWRITE, &write);
124         *written = len - ret;
125         if (ret)
126                 return smh_errno();
127         return 0;
128 }
129
130 long smh_close(long fd)
131 {
132         long ret;
133
134         debug("%s: fd %ld\n", __func__, fd);
135
136         ret = smh_trap(SYSCLOSE, &fd);
137         if (ret == -1)
138                 return smh_errno();
139         return 0;
140 }
141
142 long smh_flen(long fd)
143 {
144         long ret;
145
146         debug("%s: fd %ld\n", __func__, fd);
147
148         ret = smh_trap(SYSFLEN, &fd);
149         if (ret == -1)
150                 return smh_errno();
151         return ret;
152 }
153
154 long smh_seek(long fd, long pos)
155 {
156         long ret;
157         struct smh_seek_s {
158                 long fd;
159                 long pos;
160         } seek;
161
162         debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
163
164         seek.fd = fd;
165         seek.pos = pos;
166
167         ret = smh_trap(SYSSEEK, &seek);
168         if (ret)
169                 return smh_errno();
170         return 0;
171 }
172
173 int smh_getc(void)
174 {
175         return smh_trap(SYSREADC, NULL);
176 }
177
178 void smh_putc(char ch)
179 {
180         smh_trap(SYSWRITEC, &ch);
181 }
182
183 void smh_puts(const char *s)
184 {
185         smh_trap(SYSWRITE0, (char *)s);
186 }