[444] | 1 | /* Copyright (c) 2010 CodeSourcery, Inc. |
---|
| 2 | All rights reserved. |
---|
| 3 | |
---|
| 4 | Redistribution and use in source and binary forms, with or without |
---|
| 5 | modification, are permitted provided that the following conditions are met: |
---|
| 6 | * Redistributions of source code must retain the above copyright |
---|
| 7 | notice, this list of conditions and the following disclaimer. |
---|
| 8 | * Redistributions in binary form must reproduce the above copyright |
---|
| 9 | notice, this list of conditions and the following disclaimer in the |
---|
| 10 | documentation and/or other materials provided with the distribution. |
---|
| 11 | * Neither the name of CodeSourcery nor the |
---|
| 12 | names of its contributors may be used to endorse or promote products |
---|
| 13 | derived from this software without specific prior written permission. |
---|
| 14 | |
---|
| 15 | THIS SOFTWARE IS PROVIDED BY CODESOURCERY, INC. ``AS IS'' AND ANY |
---|
| 16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
---|
| 18 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CODESOURCERY BE LIABLE |
---|
| 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
| 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
---|
| 21 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
---|
| 22 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
---|
| 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
| 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
---|
| 25 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
---|
| 26 | DAMAGE. */ |
---|
| 27 | |
---|
| 28 | #include <stdio.h> |
---|
| 29 | #include <string.h> |
---|
| 30 | #include <time.h> |
---|
| 31 | #include <sys/time.h> |
---|
| 32 | #include <sys/stat.h> |
---|
| 33 | #include <errno.h> |
---|
| 34 | |
---|
| 35 | #define _DTOPEN 0xf0 |
---|
| 36 | #define _DTCLOSE 0xf1 |
---|
| 37 | #define _DTREAD 0xf2 |
---|
| 38 | #define _DTWRITE 0xf3 |
---|
| 39 | #define _DTLSEEK 0xf4 |
---|
| 40 | #define _DTUNLINK 0xf5 |
---|
| 41 | #define _DTGETENV 0xf6 |
---|
| 42 | #define _DTRENAME 0xf7 |
---|
| 43 | #define _DTGETTIME 0xf8 |
---|
| 44 | #define _DTGETCLK 0xf9 |
---|
| 45 | #define _DTSYNC 0xff |
---|
| 46 | |
---|
| 47 | #define CIOBUFSIZ (BUFSIZ + 32) |
---|
| 48 | |
---|
| 49 | struct __attribute__((packed)) cio_open_to_host |
---|
| 50 | { |
---|
| 51 | /* Suggested file descriptor (little endian). */ |
---|
| 52 | short fd; |
---|
| 53 | /* Flags (little endian). */ |
---|
| 54 | short flags; |
---|
| 55 | }; |
---|
| 56 | |
---|
| 57 | struct __attribute__((packed)) cio_open_from_host |
---|
| 58 | { |
---|
| 59 | /* File descriptor (little endian). */ |
---|
| 60 | short fd; |
---|
| 61 | }; |
---|
| 62 | |
---|
| 63 | struct __attribute__((packed)) cio_close_to_host |
---|
| 64 | { |
---|
| 65 | /* File descriptor (little endian). */ |
---|
| 66 | short fd; |
---|
| 67 | }; |
---|
| 68 | |
---|
| 69 | struct __attribute__((packed)) cio_close_from_host |
---|
| 70 | { |
---|
| 71 | /* Result (little endian). */ |
---|
| 72 | short result; |
---|
| 73 | }; |
---|
| 74 | |
---|
| 75 | struct __attribute__((packed)) cio_read_to_host |
---|
| 76 | { |
---|
| 77 | /* File descriptor (little endian). */ |
---|
| 78 | short fd; |
---|
| 79 | /* Length (little endian). */ |
---|
| 80 | short length; |
---|
| 81 | }; |
---|
| 82 | |
---|
| 83 | struct __attribute__((packed)) cio_read_from_host |
---|
| 84 | { |
---|
| 85 | /* Result (little endian). */ |
---|
| 86 | short result; |
---|
| 87 | }; |
---|
| 88 | |
---|
| 89 | struct __attribute__((packed)) cio_write_to_host |
---|
| 90 | { |
---|
| 91 | /* File descriptor (little endian). */ |
---|
| 92 | short fd; |
---|
| 93 | /* Length (little endian). */ |
---|
| 94 | short length; |
---|
| 95 | }; |
---|
| 96 | |
---|
| 97 | struct __attribute__((packed)) cio_write_from_host |
---|
| 98 | { |
---|
| 99 | /* Result (little endian). */ |
---|
| 100 | short result; |
---|
| 101 | }; |
---|
| 102 | |
---|
| 103 | struct __attribute__((packed)) cio_lseek_to_host |
---|
| 104 | { |
---|
| 105 | /* File descriptor (little endian). */ |
---|
| 106 | short fd; |
---|
| 107 | /* Offset (little endian). */ |
---|
| 108 | int offset; |
---|
| 109 | /* Whence (little endian). */ |
---|
| 110 | short whence; |
---|
| 111 | }; |
---|
| 112 | |
---|
| 113 | struct __attribute__((packed)) cio_lseek_from_host |
---|
| 114 | { |
---|
| 115 | /* Result (little endian). */ |
---|
| 116 | int result; |
---|
| 117 | }; |
---|
| 118 | |
---|
| 119 | struct __attribute__((packed)) cio_unlink_to_host |
---|
| 120 | { |
---|
| 121 | /* Empty. */ |
---|
| 122 | }; |
---|
| 123 | |
---|
| 124 | struct __attribute__((packed)) cio_unlink_from_host |
---|
| 125 | { |
---|
| 126 | /* Result (little endian). */ |
---|
| 127 | short result; |
---|
| 128 | }; |
---|
| 129 | |
---|
| 130 | struct __attribute__((packed)) cio_rename_to_host |
---|
| 131 | { |
---|
| 132 | /* Empty. */ |
---|
| 133 | }; |
---|
| 134 | |
---|
| 135 | struct __attribute__((packed)) cio_rename_from_host |
---|
| 136 | { |
---|
| 137 | /* Result (little endian). */ |
---|
| 138 | short result; |
---|
| 139 | }; |
---|
| 140 | |
---|
| 141 | struct __attribute__((packed)) cio_gettime_to_host |
---|
| 142 | { |
---|
| 143 | /* Empty. */ |
---|
| 144 | }; |
---|
| 145 | |
---|
| 146 | struct __attribute__((packed)) cio_gettime_from_host |
---|
| 147 | { |
---|
| 148 | /* Time (little endian). */ |
---|
| 149 | int time; |
---|
| 150 | }; |
---|
| 151 | |
---|
| 152 | struct __attribute__((packed)) cio_getclk_to_host |
---|
| 153 | { |
---|
| 154 | /* Empty. */ |
---|
| 155 | }; |
---|
| 156 | |
---|
| 157 | struct __attribute__((packed)) cio_getclk_from_host |
---|
| 158 | { |
---|
| 159 | /* Clock cycles (little endian). */ |
---|
| 160 | int result; |
---|
| 161 | }; |
---|
| 162 | |
---|
| 163 | struct __attribute__((packed)) cio_to_host |
---|
| 164 | { |
---|
| 165 | /* Data length (target endian). */ |
---|
| 166 | unsigned int length; |
---|
| 167 | /* Command. */ |
---|
| 168 | unsigned char command; |
---|
| 169 | /* Parameters. */ |
---|
| 170 | union |
---|
| 171 | { |
---|
| 172 | unsigned char buf[8]; |
---|
| 173 | struct cio_open_to_host open; |
---|
| 174 | struct cio_close_to_host close; |
---|
| 175 | struct cio_read_to_host read; |
---|
| 176 | struct cio_write_to_host write; |
---|
| 177 | struct cio_lseek_to_host lseek; |
---|
| 178 | struct cio_unlink_to_host unlink; |
---|
| 179 | struct cio_rename_to_host rename; |
---|
| 180 | struct cio_gettime_to_host gettime; |
---|
| 181 | struct cio_getclk_to_host getclk; |
---|
| 182 | } parms; |
---|
| 183 | /* Variable-length data. */ |
---|
| 184 | unsigned char data[]; |
---|
| 185 | }; |
---|
| 186 | |
---|
| 187 | struct __attribute__((packed)) cio_from_host |
---|
| 188 | { |
---|
| 189 | /* Length (target endian). */ |
---|
| 190 | unsigned int length; |
---|
| 191 | /* Parameters. */ |
---|
| 192 | union |
---|
| 193 | { |
---|
| 194 | unsigned char buf[8]; |
---|
| 195 | struct cio_open_from_host open; |
---|
| 196 | struct cio_close_from_host close; |
---|
| 197 | struct cio_read_from_host read; |
---|
| 198 | struct cio_write_from_host write; |
---|
| 199 | struct cio_lseek_from_host lseek; |
---|
| 200 | struct cio_unlink_from_host unlink; |
---|
| 201 | struct cio_rename_from_host rename; |
---|
| 202 | struct cio_gettime_from_host gettime; |
---|
| 203 | struct cio_getclk_from_host getclk; |
---|
| 204 | } parms; |
---|
| 205 | /* Data. */ |
---|
| 206 | unsigned char data[]; |
---|
| 207 | }; |
---|
| 208 | |
---|
| 209 | union |
---|
| 210 | { |
---|
| 211 | unsigned char buf[CIOBUFSIZ]; |
---|
| 212 | int align; |
---|
| 213 | union |
---|
| 214 | { |
---|
| 215 | struct cio_to_host to_host; |
---|
| 216 | struct cio_from_host from_host; |
---|
| 217 | } u; |
---|
| 218 | } _CIOBUF_ __attribute__((section(".cio"))); |
---|
| 219 | |
---|
| 220 | #ifdef _BIG_ENDIAN |
---|
| 221 | #define SWAPSHORT(s) ((short)((((s) & 0xff) << 8) | (((s) & 0xff00) >> 8))) |
---|
| 222 | #define SWAPINT(i) (__builtin_bswap32 (i)) |
---|
| 223 | #else |
---|
| 224 | #define SWAPSHORT(s) (s) |
---|
| 225 | #define SWAPINT(i) (i) |
---|
| 226 | #endif |
---|
| 227 | |
---|
| 228 | static void __attribute__((noinline)) |
---|
| 229 | do_semi_call (void) |
---|
| 230 | { |
---|
| 231 | asm volatile (".globl C$$IO$$\nnop\nC$$IO$$:nop" : "+m" (_CIOBUF_)); |
---|
| 232 | } |
---|
| 233 | |
---|
| 234 | static inline void |
---|
| 235 | semi_call_wrapper (unsigned char command, const char *data, |
---|
| 236 | unsigned int length) |
---|
| 237 | { |
---|
| 238 | _CIOBUF_.u.to_host.length = length; |
---|
| 239 | _CIOBUF_.u.to_host.command = command; |
---|
| 240 | if (data != NULL) |
---|
| 241 | memcpy (_CIOBUF_.u.to_host.data, data, length); |
---|
| 242 | do_semi_call (); |
---|
| 243 | } |
---|
| 244 | |
---|
| 245 | static inline void |
---|
| 246 | semi_call_wrapper2 (unsigned char command, const char *data1, |
---|
| 247 | unsigned int length1, const char *data2, |
---|
| 248 | unsigned int length2) |
---|
| 249 | { |
---|
| 250 | _CIOBUF_.u.to_host.length = length1 + length2; |
---|
| 251 | _CIOBUF_.u.to_host.command = command; |
---|
| 252 | if (data1 != NULL) |
---|
| 253 | memcpy (_CIOBUF_.u.to_host.data, data1, length1); |
---|
| 254 | if (data2 != NULL) |
---|
| 255 | memcpy (_CIOBUF_.u.to_host.data + length1, data2, length2); |
---|
| 256 | do_semi_call (); |
---|
| 257 | } |
---|
| 258 | |
---|
| 259 | void |
---|
| 260 | _exit (int status) |
---|
| 261 | { |
---|
| 262 | /* The semihosting interface appears to provide no way to return an |
---|
| 263 | exit status. */ |
---|
| 264 | asm volatile (".globl C$$EXIT\nnop\nC$$EXIT:nop"); |
---|
| 265 | } |
---|
| 266 | |
---|
| 267 | int |
---|
| 268 | open (const char *path, int flags, ...) |
---|
| 269 | { |
---|
| 270 | /* ??? It's not clear what the suggested fd is for. */ |
---|
| 271 | static short suggest_fd = 3; |
---|
| 272 | short ret_fd; |
---|
| 273 | ++suggest_fd; |
---|
| 274 | _CIOBUF_.u.to_host.parms.open.fd = SWAPSHORT (suggest_fd); |
---|
| 275 | _CIOBUF_.u.to_host.parms.open.flags = SWAPSHORT (flags); |
---|
| 276 | semi_call_wrapper (_DTOPEN, path, strlen (path) + 1); |
---|
| 277 | ret_fd = SWAPSHORT (_CIOBUF_.u.from_host.parms.open.fd); |
---|
| 278 | if (ret_fd == -1) |
---|
| 279 | return -1; |
---|
| 280 | return suggest_fd; |
---|
| 281 | } |
---|
| 282 | |
---|
| 283 | int |
---|
| 284 | close (int fd) |
---|
| 285 | { |
---|
| 286 | _CIOBUF_.u.to_host.parms.close.fd = SWAPSHORT (fd); |
---|
| 287 | semi_call_wrapper (_DTCLOSE, NULL, 0); |
---|
| 288 | return SWAPSHORT (_CIOBUF_.u.from_host.parms.close.result); |
---|
| 289 | } |
---|
| 290 | |
---|
| 291 | int |
---|
| 292 | read (int fd, char *ptr, int len) |
---|
| 293 | { |
---|
| 294 | if (len > BUFSIZ) |
---|
| 295 | len = BUFSIZ; |
---|
| 296 | _CIOBUF_.u.to_host.parms.read.fd = SWAPSHORT (fd); |
---|
| 297 | _CIOBUF_.u.to_host.parms.read.length = SWAPSHORT (len); |
---|
| 298 | semi_call_wrapper (_DTREAD, NULL, 0); |
---|
| 299 | memcpy (ptr, _CIOBUF_.u.from_host.data, _CIOBUF_.u.from_host.length); |
---|
| 300 | return SWAPSHORT (_CIOBUF_.u.from_host.parms.read.result); |
---|
| 301 | } |
---|
| 302 | |
---|
| 303 | int |
---|
| 304 | write (int fd, char *ptr, int len) |
---|
| 305 | { |
---|
| 306 | if (len > BUFSIZ) |
---|
| 307 | len = BUFSIZ; |
---|
| 308 | _CIOBUF_.u.to_host.parms.write.fd = SWAPSHORT (fd); |
---|
| 309 | _CIOBUF_.u.to_host.parms.write.length = SWAPSHORT (len); |
---|
| 310 | semi_call_wrapper (_DTWRITE, ptr, len); |
---|
| 311 | return SWAPSHORT (_CIOBUF_.u.from_host.parms.write.result); |
---|
| 312 | } |
---|
| 313 | |
---|
| 314 | int |
---|
| 315 | lseek (int fd, int offset, int whence) |
---|
| 316 | { |
---|
| 317 | _CIOBUF_.u.to_host.parms.lseek.fd = SWAPSHORT (fd); |
---|
| 318 | _CIOBUF_.u.to_host.parms.lseek.offset = SWAPINT (offset); |
---|
| 319 | _CIOBUF_.u.to_host.parms.lseek.whence = SWAPSHORT (whence); |
---|
| 320 | semi_call_wrapper (_DTLSEEK, NULL, 0); |
---|
| 321 | return SWAPINT (_CIOBUF_.u.from_host.parms.lseek.result); |
---|
| 322 | } |
---|
| 323 | |
---|
| 324 | int |
---|
| 325 | unlink (const char *path) |
---|
| 326 | { |
---|
| 327 | semi_call_wrapper (_DTUNLINK, path, strlen (path) + 1); |
---|
| 328 | return SWAPSHORT (_CIOBUF_.u.from_host.parms.unlink.result); |
---|
| 329 | } |
---|
| 330 | |
---|
| 331 | int |
---|
| 332 | rename (const char *oldpath, const char *newpath) |
---|
| 333 | { |
---|
| 334 | semi_call_wrapper2 (_DTRENAME, oldpath, strlen (oldpath) + 1, |
---|
| 335 | newpath, strlen (newpath) + 1); |
---|
| 336 | return SWAPSHORT (_CIOBUF_.u.from_host.parms.rename.result); |
---|
| 337 | } |
---|
| 338 | |
---|
| 339 | int |
---|
| 340 | gettimeofday (struct timeval *tp, void *tzvp) |
---|
| 341 | { |
---|
| 342 | struct timezone *tzp = tzvp; |
---|
| 343 | |
---|
| 344 | if (tp) |
---|
| 345 | { |
---|
| 346 | semi_call_wrapper (_DTGETTIME, NULL, 0); |
---|
| 347 | tp->tv_sec = SWAPINT (_CIOBUF_.u.from_host.parms.gettime.time); |
---|
| 348 | tp->tv_usec = 0; |
---|
| 349 | } |
---|
| 350 | |
---|
| 351 | if (tzp) |
---|
| 352 | { |
---|
| 353 | tzp->tz_minuteswest = 0; |
---|
| 354 | tzp->tz_dsttime = 0; |
---|
| 355 | } |
---|
| 356 | |
---|
| 357 | return 0; |
---|
| 358 | } |
---|
| 359 | |
---|
| 360 | clock_t |
---|
| 361 | clock (void) |
---|
| 362 | { |
---|
| 363 | semi_call_wrapper (_DTGETCLK, NULL, 0); |
---|
| 364 | return SWAPINT (_CIOBUF_.u.from_host.parms.getclk.result); |
---|
| 365 | } |
---|
| 366 | |
---|
| 367 | |
---|
| 368 | int |
---|
| 369 | isatty (int file __attribute__((unused))) |
---|
| 370 | { |
---|
| 371 | errno = ENOSYS; |
---|
| 372 | return 0; |
---|
| 373 | } |
---|
| 374 | |
---|
| 375 | int |
---|
| 376 | fstat (int fd, struct stat *buf) |
---|
| 377 | { |
---|
| 378 | buf->st_mode = S_IFCHR; /* Always pretend to be a tty */ |
---|
| 379 | buf->st_blksize = 0; |
---|
| 380 | |
---|
| 381 | return (0); |
---|
| 382 | } |
---|