1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright © 2023 Keith Packard
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials provided
16  *    with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #ifndef _M68K_SEMIHOST_H_
37 #define _M68K_SEMIHOST_H_
38 
39 #include <stdio.h>
40 #include <errno.h>
41 #include <endian.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 
45 #define HOSTED_EXIT  0
46 #define HOSTED_INIT_SIM 1
47 #define HOSTED_OPEN 2
48 #define HOSTED_CLOSE 3
49 #define HOSTED_READ 4
50 #define HOSTED_WRITE 5
51 #define HOSTED_LSEEK 6
52 #define HOSTED_RENAME 7
53 #define HOSTED_UNLINK 8
54 #define HOSTED_STAT 9
55 #define HOSTED_FSTAT 10
56 #define HOSTED_GETTIMEOFDAY 11
57 #define HOSTED_ISATTY 12
58 #define HOSTED_SYSTEM 13
59 
60 #define GDB_O_RDONLY  0
61 #define GDB_O_WRONLY  1
62 #define GDB_O_RDWR    2
63 #define GDB_O_APPEND  8
64 #define GDB_O_CREAT   0x200
65 #define GDB_O_TRUNC   0x400
66 #define GDB_O_EXCL    0x800
67 
68 typedef uint32_t my_mode_t;
69 typedef uint32_t my_time_t;
70 
71 struct m68k_stat
72 {
73     uint32_t   my_dev;     /* device */
74     uint32_t   my_ino;     /* inode */
75     my_mode_t  my_mode;    /* protection */
76     uint32_t   my_nlink;   /* number of hard links */
77     uint32_t   my_uid;     /* user ID of owner */
78     uint32_t   my_gid;     /* group ID of owner */
79     uint32_t   my_rdev;    /* device type (if inode device) */
80     uint64_t   my_size;    /* total size, in bytes */
81     uint64_t   my_blksize; /* blocksize for filesystem I/O */
82     uint64_t   my_blocks;  /* number of blocks allocated */
83     my_time_t  my_atime;   /* time of last access */
84     my_time_t  my_mtime;   /* time of last modification */
85     my_time_t  my_ctime;   /* time of last change */
86 };
87 
88 static inline
copy_stat(struct stat * restrict statbuf,struct m68k_stat * m68k_stat)89 copy_stat(struct stat *restrict statbuf, struct m68k_stat *m68k_stat)
90 {
91         statbuf->st_dev = be32toh(m68k_stat->my_dev);
92         statbuf->st_ino = be32toh(m68k_stat->my_ino);
93         statbuf->st_mode = be32toh(m68k_stat->my_mode);
94         statbuf->st_nlink = be32toh(m68k_stat->my_nlink);
95         statbuf->st_uid = be32toh(m68k_stat->my_uid);
96         statbuf->st_gid = be32toh(m68k_stat->my_gid);
97         statbuf->st_rdev = be32toh(m68k_stat->my_rdev);
98         statbuf->st_size = be32toh(m68k_stat->my_size);
99         statbuf->st_blksize = be32toh(m68k_stat->my_blksize);
100         statbuf->st_blocks = be32toh(m68k_stat->my_blocks);
101         statbuf->st_atime = be32toh(m68k_stat->my_atime);
102         statbuf->st_mtime = be32toh(m68k_stat->my_mtime);
103         statbuf->st_ctime = be32toh(m68k_stat->my_ctime);
104 }
105 
106 struct m68k_semihost {
107     uintptr_t   args[4];
108 };
109 
110 intptr_t
111 m68k_semihost(int func, struct m68k_semihost *args);
112 
m68k_semihost1_immediate(int func,uintptr_t arg0)113 static inline intptr_t m68k_semihost1_immediate(int func, uintptr_t arg0) {
114     return m68k_semihost(func, (struct m68k_semihost *) arg0);
115 };
116 
m68k_semihost1(int func,uintptr_t arg0)117 static inline intptr_t m68k_semihost1(int func, uintptr_t arg0) {
118     struct m68k_semihost args;
119     intptr_t ret;
120 
121     args.args[0] = arg0;
122     m68k_semihost(func, &args);
123     ret = args.args[0];
124     if (ret < 0)
125         errno = args.args[1];
126     return ret;
127 };
128 
m68k_semihost2(int func,uintptr_t arg0,uintptr_t arg1)129 static inline intptr_t m68k_semihost2(int func, uintptr_t arg0, uintptr_t arg1) {
130     struct m68k_semihost args;
131     intptr_t ret;
132 
133     args.args[0] = arg0;
134     args.args[1] = arg1;
135     m68k_semihost(func, &args);
136     ret = args.args[0];
137     if (ret < 0)
138         errno = args.args[1];
139     return ret;
140 };
141 
m68k_semihost3(int func,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2)142 static inline intptr_t m68k_semihost3(int func, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2) {
143     struct m68k_semihost args;
144     intptr_t ret;
145 
146     args.args[0] = arg0;
147     args.args[1] = arg1;
148     args.args[2] = arg2;
149     m68k_semihost(func, &args);
150     ret = args.args[0];
151     if (ret < 0)
152         errno = args.args[1];
153     return ret;
154 };
155 
m68k_semihost4_64(int func,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3)156 static inline uint64_t m68k_semihost4_64(int func, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) {
157     struct m68k_semihost args;
158     uint64_t ret;
159 
160     args.args[0] = arg0;
161     args.args[1] = arg1;
162     args.args[2] = arg2;
163     args.args[3] = arg3;
164     m68k_semihost(func, &args);
165     ret = ((uint64_t) args.args[0] << 32) | args.args[1];
166     if ((int64_t) ret < 0)
167         errno = args.args[2];
168     return ret;
169 };
170 
m68k_semihost4(int func,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3)171 static inline intptr_t m68k_semihost4(int func, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) {
172     struct m68k_semihost args;
173     intptr_t ret;
174 
175     args.args[0] = arg0;
176     args.args[1] = arg1;
177     args.args[2] = arg2;
178     args.args[3] = arg3;
179     m68k_semihost(func, &args);
180     ret = args.args[0];
181     if (ret < 0)
182         errno = args.args[1];
183     return ret;
184 };
185 
186 #endif /* _M68K_SEMIHOST_H_ */
187