| 1 | /* Simulator for Analog Devices Blackfin processors. |
| 2 | |
| 3 | Copyright (C) 2005-2021 Free Software Foundation, Inc. |
| 4 | Contributed by Analog Devices, Inc. |
| 5 | |
| 6 | This file is part of simulators. |
| 7 | |
| 8 | This program is free software; you can redistribute it and/or modify |
| 9 | it under the terms of the GNU General Public License as published by |
| 10 | the Free Software Foundation; either version 3 of the License, or |
| 11 | (at your option) any later version. |
| 12 | |
| 13 | This program is distributed in the hope that it will be useful, |
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | GNU General Public License for more details. |
| 17 | |
| 18 | You should have received a copy of the GNU General Public License |
| 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| 20 | |
| 21 | /* This must come before any other includes. */ |
| 22 | #include "defs.h" |
| 23 | |
| 24 | #include <stdio.h> |
| 25 | #include <stdlib.h> |
| 26 | #include <string.h> |
| 27 | #include <signal.h> |
| 28 | #include <errno.h> |
| 29 | #include <fcntl.h> |
| 30 | #include <unistd.h> |
| 31 | #include <sys/time.h> |
| 32 | |
| 33 | #include "sim/callback.h" |
| 34 | #include "gdb/signals.h" |
| 35 | #include "sim-main.h" |
| 36 | #include "sim-syscall.h" |
| 37 | #include "sim-hw.h" |
| 38 | |
| 39 | #include "targ-vals.h" |
| 40 | |
| 41 | /* The numbers here do not matter. They just need to be unique. They also |
| 42 | need not be static across releases -- they're used internally only. The |
| 43 | mapping from the Linux ABI to the CB values is in linux-targ-map.h. */ |
| 44 | #define CB_SYS_ioctl 201 |
| 45 | #define CB_SYS_mmap2 202 |
| 46 | #define CB_SYS_munmap 203 |
| 47 | #define CB_SYS_dup2 204 |
| 48 | #define CB_SYS_getuid 205 |
| 49 | #define CB_SYS_getuid32 206 |
| 50 | #define CB_SYS_getgid 207 |
| 51 | #define CB_SYS_getgid32 208 |
| 52 | #define CB_SYS_setuid 209 |
| 53 | #define CB_SYS_setuid32 210 |
| 54 | #define CB_SYS_setgid 211 |
| 55 | #define CB_SYS_setgid32 212 |
| 56 | #define CB_SYS_pread 213 |
| 57 | #define CB_SYS__llseek 214 |
| 58 | #define CB_SYS_getcwd 215 |
| 59 | #define CB_SYS_stat64 216 |
| 60 | #define CB_SYS_lstat64 217 |
| 61 | #define CB_SYS_fstat64 218 |
| 62 | #define CB_SYS_ftruncate64 219 |
| 63 | #define CB_SYS_gettimeofday 220 |
| 64 | #define CB_SYS_access 221 |
| 65 | #include "linux-targ-map.h" |
| 66 | #include "linux-fixed-code.h" |
| 67 | |
| 68 | #include "elf/common.h" |
| 69 | #include "elf/external.h" |
| 70 | #include "elf/internal.h" |
| 71 | #include "elf/bfin.h" |
| 72 | #include "elf-bfd.h" |
| 73 | |
| 74 | #include "dv-bfin_cec.h" |
| 75 | #include "dv-bfin_mmu.h" |
| 76 | |
| 77 | #ifndef HAVE_GETUID |
| 78 | # define getuid() 0 |
| 79 | #endif |
| 80 | #ifndef HAVE_GETGID |
| 81 | # define getgid() 0 |
| 82 | #endif |
| 83 | #ifndef HAVE_GETEUID |
| 84 | # define geteuid() 0 |
| 85 | #endif |
| 86 | #ifndef HAVE_GETEGID |
| 87 | # define getegid() 0 |
| 88 | #endif |
| 89 | #ifndef HAVE_SETUID |
| 90 | # define setuid(uid) -1 |
| 91 | #endif |
| 92 | #ifndef HAVE_SETGID |
| 93 | # define setgid(gid) -1 |
| 94 | #endif |
| 95 | |
| 96 | static const char cb_linux_stat_map_32[] = |
| 97 | /* Linux kernel 32bit layout: */ |
| 98 | "st_dev,2:space,2:st_ino,4:st_mode,2:st_nlink,2:st_uid,2:st_gid,2:st_rdev,2:" |
| 99 | "space,2:st_size,4:st_blksize,4:st_blocks,4:st_atime,4:st_atimensec,4:" |
| 100 | "st_mtime,4:st_mtimensec,4:st_ctime,4:st_ctimensec,4:space,4:space,4"; |
| 101 | /* uClibc public ABI 32bit layout: |
| 102 | "st_dev,8:space,2:space,2:st_ino,4:st_mode,4:st_nlink,4:st_uid,4:st_gid,4:" |
| 103 | "st_rdev,8:space,2:space,2:st_size,4:st_blksiez,4:st_blocks,4:st_atime,4:" |
| 104 | "st_atimensec,4:st_mtime,4:st_mtimensec,4:st_ctime,4:st_ctimensec,4:space,4:" |
| 105 | "space,4"; */ |
| 106 | static const char cb_linux_stat_map_64[] = |
| 107 | "st_dev,8:space,4:space,4:st_mode,4:st_nlink,4:st_uid,4:st_gid,4:st_rdev,8:" |
| 108 | "space,4:st_size,8:st_blksize,4:st_blocks,8:st_atime,4:st_atimensec,4:" |
| 109 | "st_mtime,4:st_mtimensec,4:st_ctime,4:st_ctimensec,4:st_ino,8"; |
| 110 | static const char cb_libgloss_stat_map_32[] = |
| 111 | "st_dev,2:st_ino,2:st_mode,4:st_nlink,2:st_uid,2:st_gid,2:st_rdev,2:" |
| 112 | "st_size,4:st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:" |
| 113 | "space,4:st_blksize,4:st_blocks,4:space,8"; |
| 114 | static const char *stat_map_32, *stat_map_64; |
| 115 | |
| 116 | /* Simulate a monitor trap, put the result into r0 and errno into r1 |
| 117 | return offset by which to adjust pc. */ |
| 118 | |
| 119 | void |
| 120 | bfin_syscall (SIM_CPU *cpu) |
| 121 | { |
| 122 | SIM_DESC sd = CPU_STATE (cpu); |
| 123 | char * const *argv = (void *)STATE_PROG_ARGV (sd); |
| 124 | host_callback *cb = STATE_CALLBACK (sd); |
| 125 | bu32 args[6]; |
| 126 | CB_SYSCALL sc; |
| 127 | char *p; |
| 128 | char _tbuf[1024 * 3], *tbuf = _tbuf, tstr[1024]; |
| 129 | int fmt_ret_hex = 0; |
| 130 | |
| 131 | CB_SYSCALL_INIT (&sc); |
| 132 | |
| 133 | if (STATE_ENVIRONMENT (sd) == USER_ENVIRONMENT) |
| 134 | { |
| 135 | /* Linux syscall. */ |
| 136 | sc.func = PREG (0); |
| 137 | sc.arg1 = args[0] = DREG (0); |
| 138 | sc.arg2 = args[1] = DREG (1); |
| 139 | sc.arg3 = args[2] = DREG (2); |
| 140 | sc.arg4 = args[3] = DREG (3); |
| 141 | /*sc.arg5 =*/ args[4] = DREG (4); |
| 142 | /*sc.arg6 =*/ args[5] = DREG (5); |
| 143 | } |
| 144 | else |
| 145 | { |
| 146 | /* libgloss syscall. */ |
| 147 | sc.func = PREG (0); |
| 148 | sc.arg1 = args[0] = GET_LONG (DREG (0)); |
| 149 | sc.arg2 = args[1] = GET_LONG (DREG (0) + 4); |
| 150 | sc.arg3 = args[2] = GET_LONG (DREG (0) + 8); |
| 151 | sc.arg4 = args[3] = GET_LONG (DREG (0) + 12); |
| 152 | /*sc.arg5 =*/ args[4] = GET_LONG (DREG (0) + 16); |
| 153 | /*sc.arg6 =*/ args[5] = GET_LONG (DREG (0) + 20); |
| 154 | } |
| 155 | sc.p1 = (PTR) sd; |
| 156 | sc.p2 = (PTR) cpu; |
| 157 | sc.read_mem = sim_syscall_read_mem; |
| 158 | sc.write_mem = sim_syscall_write_mem; |
| 159 | |
| 160 | /* Common cb_syscall() handles most functions. */ |
| 161 | switch (cb_target_to_host_syscall (cb, sc.func)) |
| 162 | { |
| 163 | case CB_SYS_exit: |
| 164 | tbuf += sprintf (tbuf, "exit(%i)", args[0]); |
| 165 | sim_engine_halt (sd, cpu, NULL, PCREG, sim_exited, sc.arg1); |
| 166 | |
| 167 | #ifdef CB_SYS_argc |
| 168 | case CB_SYS_argc: |
| 169 | tbuf += sprintf (tbuf, "argc()"); |
| 170 | sc.result = countargv ((char **)argv); |
| 171 | break; |
| 172 | case CB_SYS_argnlen: |
| 173 | { |
| 174 | tbuf += sprintf (tbuf, "argnlen(%u)", args[0]); |
| 175 | if (sc.arg1 < countargv ((char **)argv)) |
| 176 | sc.result = strlen (argv[sc.arg1]); |
| 177 | else |
| 178 | sc.result = -1; |
| 179 | } |
| 180 | break; |
| 181 | case CB_SYS_argn: |
| 182 | { |
| 183 | tbuf += sprintf (tbuf, "argn(%u)", args[0]); |
| 184 | if (sc.arg1 < countargv ((char **)argv)) |
| 185 | { |
| 186 | const char *argn = argv[sc.arg1]; |
| 187 | int len = strlen (argn); |
| 188 | int written = sc.write_mem (cb, &sc, sc.arg2, argn, len + 1); |
| 189 | if (written == len + 1) |
| 190 | sc.result = sc.arg2; |
| 191 | else |
| 192 | sc.result = -1; |
| 193 | } |
| 194 | else |
| 195 | sc.result = -1; |
| 196 | } |
| 197 | break; |
| 198 | #endif |
| 199 | |
| 200 | case CB_SYS_gettimeofday: |
| 201 | { |
| 202 | struct timeval _tv, *tv = &_tv; |
| 203 | struct timezone _tz, *tz = &_tz; |
| 204 | |
| 205 | tbuf += sprintf (tbuf, "gettimeofday(%#x, %#x)", args[0], args[1]); |
| 206 | |
| 207 | if (sc.arg1 == 0) |
| 208 | tv = NULL; |
| 209 | if (sc.arg2 == 0) |
| 210 | tz = NULL; |
| 211 | sc.result = gettimeofday (tv, tz); |
| 212 | |
| 213 | if (sc.result == 0) |
| 214 | { |
| 215 | bu32 t; |
| 216 | |
| 217 | if (tv) |
| 218 | { |
| 219 | t = tv->tv_sec; |
| 220 | sc.write_mem (cb, &sc, sc.arg1, (void *)&t, 4); |
| 221 | t = tv->tv_usec; |
| 222 | sc.write_mem (cb, &sc, sc.arg1 + 4, (void *)&t, 4); |
| 223 | } |
| 224 | |
| 225 | if (sc.arg2) |
| 226 | { |
| 227 | t = tz->tz_minuteswest; |
| 228 | sc.write_mem (cb, &sc, sc.arg1, (void *)&t, 4); |
| 229 | t = tz->tz_dsttime; |
| 230 | sc.write_mem (cb, &sc, sc.arg1 + 4, (void *)&t, 4); |
| 231 | } |
| 232 | } |
| 233 | else |
| 234 | goto sys_finish; |
| 235 | } |
| 236 | break; |
| 237 | |
| 238 | case CB_SYS_ioctl: |
| 239 | /* XXX: hack just enough to get basic stdio w/uClibc ... */ |
| 240 | tbuf += sprintf (tbuf, "ioctl(%i, %#x, %u)", args[0], args[1], args[2]); |
| 241 | if (sc.arg2 == 0x5401) |
| 242 | { |
| 243 | sc.result = !isatty (sc.arg1); |
| 244 | sc.errcode = 0; |
| 245 | } |
| 246 | else |
| 247 | { |
| 248 | sc.result = -1; |
| 249 | sc.errcode = TARGET_EINVAL; |
| 250 | } |
| 251 | break; |
| 252 | |
| 253 | case CB_SYS_mmap2: |
| 254 | { |
| 255 | static bu32 heap = BFIN_DEFAULT_MEM_SIZE / 2; |
| 256 | |
| 257 | fmt_ret_hex = 1; |
| 258 | tbuf += sprintf (tbuf, "mmap2(%#x, %u, %#x, %#x, %i, %u)", |
| 259 | args[0], args[1], args[2], args[3], args[4], args[5]); |
| 260 | |
| 261 | sc.errcode = 0; |
| 262 | |
| 263 | if (sc.arg4 & 0x20 /*MAP_ANONYMOUS*/) |
| 264 | /* XXX: We don't handle zeroing, but default is all zeros. */; |
| 265 | else if (args[4] >= MAX_CALLBACK_FDS) |
| 266 | sc.errcode = TARGET_ENOSYS; |
| 267 | else |
| 268 | { |
| 269 | #ifdef HAVE_PREAD |
| 270 | char *data = xmalloc (sc.arg2); |
| 271 | |
| 272 | /* XXX: Should add a cb->pread. */ |
| 273 | if (pread (cb->fdmap[args[4]], data, sc.arg2, args[5] << 12) == sc.arg2) |
| 274 | sc.write_mem (cb, &sc, heap, data, sc.arg2); |
| 275 | else |
| 276 | sc.errcode = TARGET_EINVAL; |
| 277 | |
| 278 | free (data); |
| 279 | #else |
| 280 | sc.errcode = TARGET_ENOSYS; |
| 281 | #endif |
| 282 | } |
| 283 | |
| 284 | if (sc.errcode) |
| 285 | { |
| 286 | sc.result = -1; |
| 287 | break; |
| 288 | } |
| 289 | |
| 290 | sc.result = heap; |
| 291 | heap += sc.arg2; |
| 292 | /* Keep it page aligned. */ |
| 293 | heap = align_up (heap, 4096); |
| 294 | |
| 295 | break; |
| 296 | } |
| 297 | |
| 298 | case CB_SYS_munmap: |
| 299 | /* XXX: meh, just lie for mmap(). */ |
| 300 | tbuf += sprintf (tbuf, "munmap(%#x, %u)", args[0], args[1]); |
| 301 | sc.result = 0; |
| 302 | break; |
| 303 | |
| 304 | case CB_SYS_dup2: |
| 305 | tbuf += sprintf (tbuf, "dup2(%i, %i)", args[0], args[1]); |
| 306 | if (sc.arg1 >= MAX_CALLBACK_FDS || sc.arg2 >= MAX_CALLBACK_FDS) |
| 307 | { |
| 308 | sc.result = -1; |
| 309 | sc.errcode = TARGET_EINVAL; |
| 310 | } |
| 311 | else |
| 312 | { |
| 313 | sc.result = dup2 (cb->fdmap[sc.arg1], cb->fdmap[sc.arg2]); |
| 314 | goto sys_finish; |
| 315 | } |
| 316 | break; |
| 317 | |
| 318 | case CB_SYS__llseek: |
| 319 | tbuf += sprintf (tbuf, "llseek(%i, %u, %u, %#x, %u)", |
| 320 | args[0], args[1], args[2], args[3], args[4]); |
| 321 | sc.func = TARGET_LINUX_SYS_lseek; |
| 322 | if (sc.arg2) |
| 323 | { |
| 324 | sc.result = -1; |
| 325 | sc.errcode = TARGET_EINVAL; |
| 326 | } |
| 327 | else |
| 328 | { |
| 329 | sc.arg2 = sc.arg3; |
| 330 | sc.arg3 = args[4]; |
| 331 | cb_syscall (cb, &sc); |
| 332 | if (sc.result != -1) |
| 333 | { |
| 334 | bu32 z = 0; |
| 335 | sc.write_mem (cb, &sc, args[3], (void *)&sc.result, 4); |
| 336 | sc.write_mem (cb, &sc, args[3] + 4, (void *)&z, 4); |
| 337 | } |
| 338 | } |
| 339 | break; |
| 340 | |
| 341 | /* XXX: Should add a cb->pread. */ |
| 342 | case CB_SYS_pread: |
| 343 | tbuf += sprintf (tbuf, "pread(%i, %#x, %u, %i)", |
| 344 | args[0], args[1], args[2], args[3]); |
| 345 | if (sc.arg1 >= MAX_CALLBACK_FDS) |
| 346 | { |
| 347 | sc.result = -1; |
| 348 | sc.errcode = TARGET_EINVAL; |
| 349 | } |
| 350 | else |
| 351 | { |
| 352 | long old_pos, read_result, read_errcode; |
| 353 | |
| 354 | /* Get current filepos. */ |
| 355 | sc.func = TARGET_LINUX_SYS_lseek; |
| 356 | sc.arg2 = 0; |
| 357 | sc.arg3 = SEEK_CUR; |
| 358 | cb_syscall (cb, &sc); |
| 359 | if (sc.result == -1) |
| 360 | break; |
| 361 | old_pos = sc.result; |
| 362 | |
| 363 | /* Move to the new pos. */ |
| 364 | sc.func = TARGET_LINUX_SYS_lseek; |
| 365 | sc.arg2 = args[3]; |
| 366 | sc.arg3 = SEEK_SET; |
| 367 | cb_syscall (cb, &sc); |
| 368 | if (sc.result == -1) |
| 369 | break; |
| 370 | |
| 371 | /* Read the data. */ |
| 372 | sc.func = TARGET_LINUX_SYS_read; |
| 373 | sc.arg2 = args[1]; |
| 374 | sc.arg3 = args[2]; |
| 375 | cb_syscall (cb, &sc); |
| 376 | read_result = sc.result; |
| 377 | read_errcode = sc.errcode; |
| 378 | |
| 379 | /* Move back to the old pos. */ |
| 380 | sc.func = TARGET_LINUX_SYS_lseek; |
| 381 | sc.arg2 = old_pos; |
| 382 | sc.arg3 = SEEK_SET; |
| 383 | cb_syscall (cb, &sc); |
| 384 | |
| 385 | sc.result = read_result; |
| 386 | sc.errcode = read_errcode; |
| 387 | } |
| 388 | break; |
| 389 | |
| 390 | case CB_SYS_getcwd: |
| 391 | tbuf += sprintf (tbuf, "getcwd(%#x, %u)", args[0], args[1]); |
| 392 | |
| 393 | p = alloca (sc.arg2); |
| 394 | if (getcwd (p, sc.arg2) == NULL) |
| 395 | { |
| 396 | sc.result = -1; |
| 397 | sc.errcode = TARGET_EINVAL; |
| 398 | } |
| 399 | else |
| 400 | { |
| 401 | sc.write_mem (cb, &sc, sc.arg1, p, sc.arg2); |
| 402 | sc.result = sc.arg1; |
| 403 | } |
| 404 | break; |
| 405 | |
| 406 | case CB_SYS_stat64: |
| 407 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) |
| 408 | strcpy (tstr, "???"); |
| 409 | tbuf += sprintf (tbuf, "stat64(%#x:\"%s\", %u)", args[0], tstr, args[1]); |
| 410 | cb->stat_map = stat_map_64; |
| 411 | sc.func = TARGET_LINUX_SYS_stat; |
| 412 | cb_syscall (cb, &sc); |
| 413 | cb->stat_map = stat_map_32; |
| 414 | break; |
| 415 | case CB_SYS_lstat64: |
| 416 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) |
| 417 | strcpy (tstr, "???"); |
| 418 | tbuf += sprintf (tbuf, "lstat64(%#x:\"%s\", %u)", args[0], tstr, args[1]); |
| 419 | cb->stat_map = stat_map_64; |
| 420 | sc.func = TARGET_LINUX_SYS_lstat; |
| 421 | cb_syscall (cb, &sc); |
| 422 | cb->stat_map = stat_map_32; |
| 423 | break; |
| 424 | case CB_SYS_fstat64: |
| 425 | tbuf += sprintf (tbuf, "fstat64(%#x, %u)", args[0], args[1]); |
| 426 | cb->stat_map = stat_map_64; |
| 427 | sc.func = TARGET_LINUX_SYS_fstat; |
| 428 | cb_syscall (cb, &sc); |
| 429 | cb->stat_map = stat_map_32; |
| 430 | break; |
| 431 | |
| 432 | case CB_SYS_ftruncate64: |
| 433 | tbuf += sprintf (tbuf, "ftruncate64(%u, %u)", args[0], args[1]); |
| 434 | sc.func = TARGET_LINUX_SYS_ftruncate; |
| 435 | cb_syscall (cb, &sc); |
| 436 | break; |
| 437 | |
| 438 | case CB_SYS_getuid: |
| 439 | case CB_SYS_getuid32: |
| 440 | tbuf += sprintf (tbuf, "getuid()"); |
| 441 | sc.result = getuid (); |
| 442 | goto sys_finish; |
| 443 | case CB_SYS_getgid: |
| 444 | case CB_SYS_getgid32: |
| 445 | tbuf += sprintf (tbuf, "getgid()"); |
| 446 | sc.result = getgid (); |
| 447 | goto sys_finish; |
| 448 | case CB_SYS_setuid: |
| 449 | sc.arg1 &= 0xffff; |
| 450 | case CB_SYS_setuid32: |
| 451 | tbuf += sprintf (tbuf, "setuid(%u)", args[0]); |
| 452 | sc.result = setuid (sc.arg1); |
| 453 | goto sys_finish; |
| 454 | case CB_SYS_setgid: |
| 455 | sc.arg1 &= 0xffff; |
| 456 | case CB_SYS_setgid32: |
| 457 | tbuf += sprintf (tbuf, "setgid(%u)", args[0]); |
| 458 | sc.result = setgid (sc.arg1); |
| 459 | goto sys_finish; |
| 460 | |
| 461 | case CB_SYS_kill: |
| 462 | tbuf += sprintf (tbuf, "kill(%u, %i)", args[0], args[1]); |
| 463 | /* Only let the app kill itself. */ |
| 464 | if (sc.arg1 != getpid ()) |
| 465 | { |
| 466 | sc.result = -1; |
| 467 | sc.errcode = TARGET_EPERM; |
| 468 | } |
| 469 | else |
| 470 | { |
| 471 | #ifdef HAVE_KILL |
| 472 | sc.result = kill (sc.arg1, sc.arg2); |
| 473 | goto sys_finish; |
| 474 | #else |
| 475 | sc.result = -1; |
| 476 | sc.errcode = TARGET_ENOSYS; |
| 477 | #endif |
| 478 | } |
| 479 | break; |
| 480 | |
| 481 | case CB_SYS_open: |
| 482 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) |
| 483 | strcpy (tstr, "???"); |
| 484 | tbuf += sprintf (tbuf, "open(%#x:\"%s\", %#x, %o)", |
| 485 | args[0], tstr, args[1], args[2]); |
| 486 | goto case_default; |
| 487 | case CB_SYS_close: |
| 488 | tbuf += sprintf (tbuf, "close(%i)", args[0]); |
| 489 | goto case_default; |
| 490 | case CB_SYS_read: |
| 491 | tbuf += sprintf (tbuf, "read(%i, %#x, %u)", args[0], args[1], args[2]); |
| 492 | goto case_default; |
| 493 | case CB_SYS_write: |
| 494 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[1])) |
| 495 | strcpy (tstr, "???"); |
| 496 | tbuf += sprintf (tbuf, "write(%i, %#x:\"%s\", %u)", |
| 497 | args[0], args[1], tstr, args[2]); |
| 498 | goto case_default; |
| 499 | case CB_SYS_lseek: |
| 500 | tbuf += sprintf (tbuf, "lseek(%i, %i, %i)", args[0], args[1], args[2]); |
| 501 | goto case_default; |
| 502 | case CB_SYS_unlink: |
| 503 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) |
| 504 | strcpy (tstr, "???"); |
| 505 | tbuf += sprintf (tbuf, "unlink(%#x:\"%s\")", args[0], tstr); |
| 506 | goto case_default; |
| 507 | case CB_SYS_truncate: |
| 508 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) |
| 509 | strcpy (tstr, "???"); |
| 510 | tbuf += sprintf (tbuf, "truncate(%#x:\"%s\", %i)", args[0], tstr, args[1]); |
| 511 | goto case_default; |
| 512 | case CB_SYS_ftruncate: |
| 513 | tbuf += sprintf (tbuf, "ftruncate(%i, %i)", args[0], args[1]); |
| 514 | goto case_default; |
| 515 | case CB_SYS_rename: |
| 516 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) |
| 517 | strcpy (tstr, "???"); |
| 518 | tbuf += sprintf (tbuf, "rename(%#x:\"%s\", ", args[0], tstr); |
| 519 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[1])) |
| 520 | strcpy (tstr, "???"); |
| 521 | tbuf += sprintf (tbuf, "%#x:\"%s\")", args[1], tstr); |
| 522 | goto case_default; |
| 523 | case CB_SYS_stat: |
| 524 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) |
| 525 | strcpy (tstr, "???"); |
| 526 | tbuf += sprintf (tbuf, "stat(%#x:\"%s\", %#x)", args[0], tstr, args[1]); |
| 527 | goto case_default; |
| 528 | case CB_SYS_fstat: |
| 529 | tbuf += sprintf (tbuf, "fstat(%i, %#x)", args[0], args[1]); |
| 530 | goto case_default; |
| 531 | case CB_SYS_lstat: |
| 532 | if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) |
| 533 | strcpy (tstr, "???"); |
| 534 | tbuf += sprintf (tbuf, "lstat(%#x:\"%s\", %#x)", args[0], tstr, args[1]); |
| 535 | goto case_default; |
| 536 | case CB_SYS_pipe: |
| 537 | tbuf += sprintf (tbuf, "pipe(%#x, %#x)", args[0], args[1]); |
| 538 | goto case_default; |
| 539 | |
| 540 | default: |
| 541 | tbuf += sprintf (tbuf, "???_%i(%#x, %#x, %#x, %#x, %#x, %#x)", sc.func, |
| 542 | args[0], args[1], args[2], args[3], args[4], args[5]); |
| 543 | case_default: |
| 544 | cb_syscall (cb, &sc); |
| 545 | break; |
| 546 | |
| 547 | sys_finish: |
| 548 | if (sc.result == -1) |
| 549 | { |
| 550 | cb->last_errno = errno; |
| 551 | sc.errcode = cb->get_errno (cb); |
| 552 | } |
| 553 | } |
| 554 | |
| 555 | TRACE_EVENTS (cpu, "syscall_%i(%#x, %#x, %#x, %#x, %#x, %#x) = %li (error = %i)", |
| 556 | sc.func, args[0], args[1], args[2], args[3], args[4], args[5], |
| 557 | sc.result, sc.errcode); |
| 558 | |
| 559 | tbuf += sprintf (tbuf, " = "); |
| 560 | if (STATE_ENVIRONMENT (sd) == USER_ENVIRONMENT) |
| 561 | { |
| 562 | if (sc.result == -1) |
| 563 | { |
| 564 | tbuf += sprintf (tbuf, "-1 (error = %i)", sc.errcode); |
| 565 | if (sc.errcode == cb_host_to_target_errno (cb, ENOSYS)) |
| 566 | { |
| 567 | sim_io_eprintf (sd, "bfin-sim: %#x: unimplemented syscall %i\n", |
| 568 | PCREG, sc.func); |
| 569 | } |
| 570 | SET_DREG (0, -sc.errcode); |
| 571 | } |
| 572 | else |
| 573 | { |
| 574 | if (fmt_ret_hex) |
| 575 | tbuf += sprintf (tbuf, "%#lx", sc.result); |
| 576 | else |
| 577 | tbuf += sprintf (tbuf, "%lu", sc.result); |
| 578 | SET_DREG (0, sc.result); |
| 579 | } |
| 580 | } |
| 581 | else |
| 582 | { |
| 583 | tbuf += sprintf (tbuf, "%lu (error = %i)", sc.result, sc.errcode); |
| 584 | SET_DREG (0, sc.result); |
| 585 | SET_DREG (1, sc.result2); |
| 586 | SET_DREG (2, sc.errcode); |
| 587 | } |
| 588 | |
| 589 | TRACE_SYSCALL (cpu, "%s", _tbuf); |
| 590 | } |
| 591 | |
| 592 | /* Execute a single instruction. */ |
| 593 | |
| 594 | static sim_cia |
| 595 | step_once (SIM_CPU *cpu) |
| 596 | { |
| 597 | SIM_DESC sd = CPU_STATE (cpu); |
| 598 | bu32 insn_len, oldpc = PCREG; |
| 599 | int i; |
| 600 | bool ssstep; |
| 601 | |
| 602 | if (TRACE_ANY_P (cpu)) |
| 603 | trace_prefix (sd, cpu, NULL_CIA, oldpc, TRACE_LINENUM_P (cpu), |
| 604 | NULL, 0, " "); /* Use a space for gcc warnings. */ |
| 605 | |
| 606 | TRACE_DISASM (cpu, oldpc); |
| 607 | |
| 608 | /* Handle hardware single stepping when lower than EVT3, and when SYSCFG |
| 609 | has already had the SSSTEP bit enabled. */ |
| 610 | ssstep = false; |
| 611 | if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT |
| 612 | && (SYSCFGREG & SYSCFG_SSSTEP)) |
| 613 | { |
| 614 | int ivg = cec_get_ivg (cpu); |
| 615 | if (ivg == -1 || ivg > 3) |
| 616 | ssstep = true; |
| 617 | } |
| 618 | |
| 619 | #if 0 |
| 620 | /* XXX: Is this what happens on the hardware ? */ |
| 621 | if (cec_get_ivg (cpu) == EVT_EMU) |
| 622 | cec_return (cpu, EVT_EMU); |
| 623 | #endif |
| 624 | |
| 625 | BFIN_CPU_STATE.did_jump = false; |
| 626 | |
| 627 | insn_len = interp_insn_bfin (cpu, oldpc); |
| 628 | |
| 629 | /* If we executed this insn successfully, then we always decrement |
| 630 | the loop counter. We don't want to update the PC though if the |
| 631 | last insn happened to be a change in code flow (jump/etc...). */ |
| 632 | if (!BFIN_CPU_STATE.did_jump) |
| 633 | SET_PCREG (hwloop_get_next_pc (cpu, oldpc, insn_len)); |
| 634 | for (i = 1; i >= 0; --i) |
| 635 | if (LCREG (i) && oldpc == LBREG (i)) |
| 636 | { |
| 637 | SET_LCREG (i, LCREG (i) - 1); |
| 638 | if (LCREG (i)) |
| 639 | break; |
| 640 | } |
| 641 | |
| 642 | ++ PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)); |
| 643 | |
| 644 | /* Handle hardware single stepping only if we're still lower than EVT3. |
| 645 | XXX: May not be entirely correct wrt EXCPT insns. */ |
| 646 | if (ssstep) |
| 647 | { |
| 648 | int ivg = cec_get_ivg (cpu); |
| 649 | if (ivg == -1 || ivg > 3) |
| 650 | { |
| 651 | INSN_LEN = 0; |
| 652 | cec_exception (cpu, VEC_STEP); |
| 653 | } |
| 654 | } |
| 655 | |
| 656 | return oldpc; |
| 657 | } |
| 658 | |
| 659 | void |
| 660 | sim_engine_run (SIM_DESC sd, |
| 661 | int next_cpu_nr, /* ignore */ |
| 662 | int nr_cpus, /* ignore */ |
| 663 | int siggnal) /* ignore */ |
| 664 | { |
| 665 | bu32 ticks; |
| 666 | SIM_CPU *cpu; |
| 667 | |
| 668 | SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); |
| 669 | |
| 670 | cpu = STATE_CPU (sd, 0); |
| 671 | |
| 672 | while (1) |
| 673 | { |
| 674 | step_once (cpu); |
| 675 | /* Process any events -- can't use tickn because it may |
| 676 | advance right over the next event. */ |
| 677 | for (ticks = 0; ticks < CYCLE_DELAY; ++ticks) |
| 678 | if (sim_events_tick (sd)) |
| 679 | sim_events_process (sd); |
| 680 | } |
| 681 | } |
| 682 | |
| 683 | /* Cover function of sim_state_free to free the cpu buffers as well. */ |
| 684 | |
| 685 | static void |
| 686 | free_state (SIM_DESC sd) |
| 687 | { |
| 688 | if (STATE_MODULES (sd) != NULL) |
| 689 | sim_module_uninstall (sd); |
| 690 | sim_cpu_free_all (sd); |
| 691 | sim_state_free (sd); |
| 692 | } |
| 693 | |
| 694 | /* Create an instance of the simulator. */ |
| 695 | |
| 696 | static void |
| 697 | bfin_initialize_cpu (SIM_DESC sd, SIM_CPU *cpu) |
| 698 | { |
| 699 | memset (&cpu->state, 0, sizeof (cpu->state)); |
| 700 | |
| 701 | PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) = 0; |
| 702 | |
| 703 | bfin_model_cpu_init (sd, cpu); |
| 704 | |
| 705 | /* Set default stack to top of scratch pad. */ |
| 706 | SET_SPREG (BFIN_DEFAULT_MEM_SIZE); |
| 707 | SET_KSPREG (BFIN_DEFAULT_MEM_SIZE); |
| 708 | SET_USPREG (BFIN_DEFAULT_MEM_SIZE); |
| 709 | |
| 710 | /* This is what the hardware likes. */ |
| 711 | SET_SYSCFGREG (0x30); |
| 712 | } |
| 713 | |
| 714 | SIM_DESC |
| 715 | sim_open (SIM_OPEN_KIND kind, host_callback *callback, |
| 716 | struct bfd *abfd, char * const *argv) |
| 717 | { |
| 718 | char c; |
| 719 | int i; |
| 720 | SIM_DESC sd = sim_state_alloc_extra (kind, callback, |
| 721 | sizeof (struct bfin_board_data)); |
| 722 | |
| 723 | /* Set default options before parsing user options. */ |
| 724 | current_alignment = STRICT_ALIGNMENT; |
| 725 | |
| 726 | /* The cpu data is kept in a separately allocated chunk of memory. */ |
| 727 | if (sim_cpu_alloc_all (sd, 1) != SIM_RC_OK) |
| 728 | { |
| 729 | free_state (sd); |
| 730 | return 0; |
| 731 | } |
| 732 | |
| 733 | if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) |
| 734 | { |
| 735 | free_state (sd); |
| 736 | return 0; |
| 737 | } |
| 738 | |
| 739 | /* XXX: Default to the Virtual environment. */ |
| 740 | if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT) |
| 741 | STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT; |
| 742 | |
| 743 | /* The parser will print an error message for us, so we silently return. */ |
| 744 | if (sim_parse_args (sd, argv) != SIM_RC_OK) |
| 745 | { |
| 746 | free_state (sd); |
| 747 | return 0; |
| 748 | } |
| 749 | |
| 750 | /* Allocate external memory if none specified by user. |
| 751 | Use address 4 here in case the user wanted address 0 unmapped. */ |
| 752 | if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0) |
| 753 | { |
| 754 | bu16 emuexcpt = 0x25; |
| 755 | sim_do_commandf (sd, "memory-size 0x%x", BFIN_DEFAULT_MEM_SIZE); |
| 756 | sim_write (sd, 0, (void *)&emuexcpt, 2); |
| 757 | } |
| 758 | |
| 759 | /* Check for/establish the a reference program image. */ |
| 760 | if (sim_analyze_program (sd, |
| 761 | (STATE_PROG_ARGV (sd) != NULL |
| 762 | ? *STATE_PROG_ARGV (sd) |
| 763 | : NULL), abfd) != SIM_RC_OK) |
| 764 | { |
| 765 | free_state (sd); |
| 766 | return 0; |
| 767 | } |
| 768 | |
| 769 | /* Establish any remaining configuration options. */ |
| 770 | if (sim_config (sd) != SIM_RC_OK) |
| 771 | { |
| 772 | free_state (sd); |
| 773 | return 0; |
| 774 | } |
| 775 | |
| 776 | if (sim_post_argv_init (sd) != SIM_RC_OK) |
| 777 | { |
| 778 | free_state (sd); |
| 779 | return 0; |
| 780 | } |
| 781 | |
| 782 | /* CPU specific initialization. */ |
| 783 | for (i = 0; i < MAX_NR_PROCESSORS; ++i) |
| 784 | { |
| 785 | SIM_CPU *cpu = STATE_CPU (sd, i); |
| 786 | bfin_initialize_cpu (sd, cpu); |
| 787 | } |
| 788 | |
| 789 | return sd; |
| 790 | } |
| 791 | |
| 792 | /* Some utils don't like having a NULL environ. */ |
| 793 | static char * const simple_env[] = { "HOME=/", "PATH=/bin", NULL }; |
| 794 | |
| 795 | static bu32 fdpic_load_offset; |
| 796 | |
| 797 | static bool |
| 798 | bfin_fdpic_load (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd, bu32 *sp, |
| 799 | bu32 *elf_addrs, char **ldso_path) |
| 800 | { |
| 801 | bool ret; |
| 802 | int i; |
| 803 | |
| 804 | Elf_Internal_Ehdr *iehdr; |
| 805 | Elf32_External_Ehdr ehdr; |
| 806 | Elf_Internal_Phdr *phdrs; |
| 807 | unsigned char *data; |
| 808 | long phdr_size; |
| 809 | int phdrc; |
| 810 | bu32 nsegs; |
| 811 | |
| 812 | bu32 max_load_addr; |
| 813 | |
| 814 | unsigned char null[4] = { 0, 0, 0, 0 }; |
| 815 | |
| 816 | ret = false; |
| 817 | *ldso_path = NULL; |
| 818 | |
| 819 | /* See if this an FDPIC ELF. */ |
| 820 | phdrs = NULL; |
| 821 | if (!abfd) |
| 822 | goto skip_fdpic_init; |
| 823 | if (bfd_seek (abfd, 0, SEEK_SET) != 0) |
| 824 | goto skip_fdpic_init; |
| 825 | if (bfd_bread (&ehdr, sizeof (ehdr), abfd) != sizeof (ehdr)) |
| 826 | goto skip_fdpic_init; |
| 827 | iehdr = elf_elfheader (abfd); |
| 828 | if (!(iehdr->e_flags & EF_BFIN_FDPIC)) |
| 829 | goto skip_fdpic_init; |
| 830 | |
| 831 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) |
| 832 | sim_io_printf (sd, "Loading FDPIC ELF %s\n Load base: %#x\n ELF entry: %#x\n", |
| 833 | bfd_get_filename (abfd), fdpic_load_offset, elf_addrs[0]); |
| 834 | |
| 835 | /* Grab the Program Headers to set up the loadsegs on the stack. */ |
| 836 | phdr_size = bfd_get_elf_phdr_upper_bound (abfd); |
| 837 | if (phdr_size == -1) |
| 838 | goto skip_fdpic_init; |
| 839 | phdrs = xmalloc (phdr_size); |
| 840 | phdrc = bfd_get_elf_phdrs (abfd, phdrs); |
| 841 | if (phdrc == -1) |
| 842 | goto skip_fdpic_init; |
| 843 | |
| 844 | /* Push the Ehdr onto the stack. */ |
| 845 | *sp -= sizeof (ehdr); |
| 846 | elf_addrs[3] = *sp; |
| 847 | sim_write (sd, *sp, (void *)&ehdr, sizeof (ehdr)); |
| 848 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) |
| 849 | sim_io_printf (sd, " Elf_Ehdr: %#x\n", *sp); |
| 850 | |
| 851 | /* Since we're relocating things ourselves, we need to relocate |
| 852 | the start address as well. */ |
| 853 | elf_addrs[0] = bfd_get_start_address (abfd) + fdpic_load_offset; |
| 854 | |
| 855 | /* And the Exec's Phdrs onto the stack. */ |
| 856 | if (STATE_PROG_BFD (sd) == abfd) |
| 857 | { |
| 858 | elf_addrs[4] = elf_addrs[0]; |
| 859 | |
| 860 | phdr_size = iehdr->e_phentsize * iehdr->e_phnum; |
| 861 | if (bfd_seek (abfd, iehdr->e_phoff, SEEK_SET) != 0) |
| 862 | goto skip_fdpic_init; |
| 863 | data = xmalloc (phdr_size); |
| 864 | if (bfd_bread (data, phdr_size, abfd) != phdr_size) |
| 865 | goto skip_fdpic_init; |
| 866 | *sp -= phdr_size; |
| 867 | elf_addrs[1] = *sp; |
| 868 | elf_addrs[2] = phdrc; |
| 869 | sim_write (sd, *sp, data, phdr_size); |
| 870 | free (data); |
| 871 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) |
| 872 | sim_io_printf (sd, " Elf_Phdrs: %#x\n", *sp); |
| 873 | } |
| 874 | |
| 875 | /* Now push all the loadsegs. */ |
| 876 | nsegs = 0; |
| 877 | max_load_addr = 0; |
| 878 | for (i = phdrc; i >= 0; --i) |
| 879 | if (phdrs[i].p_type == PT_LOAD) |
| 880 | { |
| 881 | Elf_Internal_Phdr *p = &phdrs[i]; |
| 882 | bu32 paddr, vaddr, memsz, filesz; |
| 883 | |
| 884 | paddr = p->p_paddr + fdpic_load_offset; |
| 885 | vaddr = p->p_vaddr; |
| 886 | memsz = p->p_memsz; |
| 887 | filesz = p->p_filesz; |
| 888 | |
| 889 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) |
| 890 | sim_io_printf (sd, " PHDR %i: vma %#x lma %#x filesz %#x memsz %#x\n", |
| 891 | i, vaddr, paddr, filesz, memsz); |
| 892 | |
| 893 | data = xmalloc (memsz); |
| 894 | if (memsz != filesz) |
| 895 | memset (data + filesz, 0, memsz - filesz); |
| 896 | |
| 897 | if (bfd_seek (abfd, p->p_offset, SEEK_SET) == 0 |
| 898 | && bfd_bread (data, filesz, abfd) == filesz) |
| 899 | sim_write (sd, paddr, data, memsz); |
| 900 | |
| 901 | free (data); |
| 902 | |
| 903 | max_load_addr = max (paddr + memsz, max_load_addr); |
| 904 | |
| 905 | *sp -= 12; |
| 906 | sim_write (sd, *sp+0, (void *)&paddr, 4); /* loadseg.addr */ |
| 907 | sim_write (sd, *sp+4, (void *)&vaddr, 4); /* loadseg.p_vaddr */ |
| 908 | sim_write (sd, *sp+8, (void *)&memsz, 4); /* loadseg.p_memsz */ |
| 909 | ++nsegs; |
| 910 | } |
| 911 | else if (phdrs[i].p_type == PT_DYNAMIC) |
| 912 | { |
| 913 | elf_addrs[5] = phdrs[i].p_paddr + fdpic_load_offset; |
| 914 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) |
| 915 | sim_io_printf (sd, " PT_DYNAMIC: %#x\n", elf_addrs[5]); |
| 916 | } |
| 917 | else if (phdrs[i].p_type == PT_INTERP) |
| 918 | { |
| 919 | uint32_t off = phdrs[i].p_offset; |
| 920 | uint32_t len = phdrs[i].p_filesz; |
| 921 | |
| 922 | *ldso_path = xmalloc (len); |
| 923 | if (bfd_seek (abfd, off, SEEK_SET) != 0 |
| 924 | || bfd_bread (*ldso_path, len, abfd) != len) |
| 925 | { |
| 926 | free (*ldso_path); |
| 927 | *ldso_path = NULL; |
| 928 | } |
| 929 | else if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) |
| 930 | sim_io_printf (sd, " PT_INTERP: %s\n", *ldso_path); |
| 931 | } |
| 932 | |
| 933 | /* Update the load offset with a few extra pages. */ |
| 934 | fdpic_load_offset = align_up (max (max_load_addr, fdpic_load_offset), |
| 935 | 0x10000); |
| 936 | fdpic_load_offset += 0x10000; |
| 937 | |
| 938 | /* Push the summary loadmap info onto the stack last. */ |
| 939 | *sp -= 4; |
| 940 | sim_write (sd, *sp+0, null, 2); /* loadmap.version */ |
| 941 | sim_write (sd, *sp+2, (void *)&nsegs, 2); /* loadmap.nsegs */ |
| 942 | |
| 943 | ret = true; |
| 944 | skip_fdpic_init: |
| 945 | free (phdrs); |
| 946 | |
| 947 | return ret; |
| 948 | } |
| 949 | |
| 950 | static void |
| 951 | bfin_user_init (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd, |
| 952 | char * const *argv, char * const *env) |
| 953 | { |
| 954 | /* XXX: Missing host -> target endian ... */ |
| 955 | /* Linux starts the user app with the stack: |
| 956 | argc |
| 957 | argv[0] -- pointers to the actual strings |
| 958 | argv[1..N] |
| 959 | NULL |
| 960 | env[0] |
| 961 | env[1..N] |
| 962 | NULL |
| 963 | auxvt[0].type -- ELF Auxiliary Vector Table |
| 964 | auxvt[0].value |
| 965 | auxvt[1..N] |
| 966 | AT_NULL |
| 967 | 0 |
| 968 | argv[0..N][0..M] -- actual argv/env strings |
| 969 | env[0..N][0..M] |
| 970 | FDPIC loadmaps -- for FDPIC apps |
| 971 | So set things up the same way. */ |
| 972 | int i, argc, envc; |
| 973 | bu32 argv_flat, env_flat; |
| 974 | |
| 975 | bu32 sp, sp_flat; |
| 976 | |
| 977 | /* start, at_phdr, at_phnum, at_base, at_entry, pt_dynamic */ |
| 978 | bu32 elf_addrs[6]; |
| 979 | bu32 auxvt; |
| 980 | bu32 exec_loadmap, ldso_loadmap; |
| 981 | char *ldso_path; |
| 982 | |
| 983 | unsigned char null[4] = { 0, 0, 0, 0 }; |
| 984 | |
| 985 | host_callback *cb = STATE_CALLBACK (sd); |
| 986 | |
| 987 | elf_addrs[0] = elf_addrs[4] = bfd_get_start_address (abfd); |
| 988 | elf_addrs[1] = elf_addrs[2] = elf_addrs[3] = elf_addrs[5] = 0; |
| 989 | |
| 990 | /* Keep the load addresses consistent between runs. Also make sure we make |
| 991 | space for the fixed code region (part of the Blackfin Linux ABI). */ |
| 992 | fdpic_load_offset = 0x1000; |
| 993 | |
| 994 | /* First try to load this as an FDPIC executable. */ |
| 995 | sp = SPREG; |
| 996 | if (!bfin_fdpic_load (sd, cpu, STATE_PROG_BFD (sd), &sp, elf_addrs, &ldso_path)) |
| 997 | goto skip_fdpic_init; |
| 998 | exec_loadmap = sp; |
| 999 | |
| 1000 | /* If that worked, then load the fixed code region. We only do this for |
| 1001 | FDPIC ELFs atm because they are PIEs and let us relocate them without |
| 1002 | manual fixups. FLAT files however require location processing which |
| 1003 | we do not do ourselves, and they link with a VMA of 0. */ |
| 1004 | sim_write (sd, 0x400, bfin_linux_fixed_code, sizeof (bfin_linux_fixed_code)); |
| 1005 | |
| 1006 | /* If the FDPIC needs an interpreter, then load it up too. */ |
| 1007 | if (ldso_path) |
| 1008 | { |
| 1009 | const char *ldso_full_path = concat (simulator_sysroot, ldso_path, NULL); |
| 1010 | struct bfd *ldso_bfd; |
| 1011 | |
| 1012 | ldso_bfd = bfd_openr (ldso_full_path, STATE_TARGET (sd)); |
| 1013 | if (!ldso_bfd) |
| 1014 | { |
| 1015 | sim_io_eprintf (sd, "bfin-sim: bfd open failed: %s\n", ldso_full_path); |
| 1016 | goto static_fdpic; |
| 1017 | } |
| 1018 | if (!bfd_check_format (ldso_bfd, bfd_object)) |
| 1019 | sim_io_eprintf (sd, "bfin-sim: bfd format not valid: %s\n", ldso_full_path); |
| 1020 | bfd_set_arch_info (ldso_bfd, STATE_ARCHITECTURE (sd)); |
| 1021 | |
| 1022 | if (!bfin_fdpic_load (sd, cpu, ldso_bfd, &sp, elf_addrs, &ldso_path)) |
| 1023 | sim_io_eprintf (sd, "bfin-sim: FDPIC ldso failed to load: %s\n", ldso_full_path); |
| 1024 | if (ldso_path) |
| 1025 | sim_io_eprintf (sd, "bfin-sim: FDPIC ldso (%s) needs an interpreter (%s) !?\n", |
| 1026 | ldso_full_path, ldso_path); |
| 1027 | |
| 1028 | ldso_loadmap = sp; |
| 1029 | } |
| 1030 | else |
| 1031 | static_fdpic: |
| 1032 | ldso_loadmap = 0; |
| 1033 | |
| 1034 | /* Finally setup the registers required by the FDPIC ABI. */ |
| 1035 | SET_DREG (7, 0); /* Zero out FINI funcptr -- ldso will set this up. */ |
| 1036 | SET_PREG (0, exec_loadmap); /* Exec loadmap addr. */ |
| 1037 | SET_PREG (1, ldso_loadmap); /* Interp loadmap addr. */ |
| 1038 | SET_PREG (2, elf_addrs[5]); /* PT_DYNAMIC map addr. */ |
| 1039 | |
| 1040 | auxvt = 1; |
| 1041 | SET_SPREG (sp); |
| 1042 | skip_fdpic_init: |
| 1043 | sim_pc_set (cpu, elf_addrs[0]); |
| 1044 | |
| 1045 | /* Figure out how much storage the argv/env strings need. */ |
| 1046 | argc = countargv ((char **)argv); |
| 1047 | if (argc == -1) |
| 1048 | argc = 0; |
| 1049 | argv_flat = argc; /* NUL bytes */ |
| 1050 | for (i = 0; i < argc; ++i) |
| 1051 | argv_flat += strlen (argv[i]); |
| 1052 | |
| 1053 | if (!env) |
| 1054 | env = simple_env; |
| 1055 | envc = countargv ((char **)env); |
| 1056 | env_flat = envc; /* NUL bytes */ |
| 1057 | for (i = 0; i < envc; ++i) |
| 1058 | env_flat += strlen (env[i]); |
| 1059 | |
| 1060 | /* Push the Auxiliary Vector Table between argv/env and actual strings. */ |
| 1061 | sp_flat = sp = align_up (SPREG - argv_flat - env_flat - 4, 4); |
| 1062 | if (auxvt) |
| 1063 | { |
| 1064 | # define AT_PUSH(at, val) \ |
| 1065 | auxvt_size += 8; \ |
| 1066 | sp -= 4; \ |
| 1067 | auxvt = (val); \ |
| 1068 | sim_write (sd, sp, (void *)&auxvt, 4); \ |
| 1069 | sp -= 4; \ |
| 1070 | auxvt = (at); \ |
| 1071 | sim_write (sd, sp, (void *)&auxvt, 4) |
| 1072 | unsigned int egid = getegid (), gid = getgid (); |
| 1073 | unsigned int euid = geteuid (), uid = getuid (); |
| 1074 | bu32 auxvt_size = 0; |
| 1075 | AT_PUSH (AT_NULL, 0); |
| 1076 | AT_PUSH (AT_SECURE, egid != gid || euid != uid); |
| 1077 | AT_PUSH (AT_EGID, egid); |
| 1078 | AT_PUSH (AT_GID, gid); |
| 1079 | AT_PUSH (AT_EUID, euid); |
| 1080 | AT_PUSH (AT_UID, uid); |
| 1081 | AT_PUSH (AT_ENTRY, elf_addrs[4]); |
| 1082 | AT_PUSH (AT_FLAGS, 0); |
| 1083 | AT_PUSH (AT_BASE, elf_addrs[3]); |
| 1084 | AT_PUSH (AT_PHNUM, elf_addrs[2]); |
| 1085 | AT_PUSH (AT_PHENT, sizeof (Elf32_External_Phdr)); |
| 1086 | AT_PUSH (AT_PHDR, elf_addrs[1]); |
| 1087 | AT_PUSH (AT_CLKTCK, 100); /* XXX: This ever not 100 ? */ |
| 1088 | AT_PUSH (AT_PAGESZ, 4096); |
| 1089 | AT_PUSH (AT_HWCAP, 0); |
| 1090 | #undef AT_PUSH |
| 1091 | } |
| 1092 | SET_SPREG (sp); |
| 1093 | |
| 1094 | /* Push the argc/argv/env after the auxvt. */ |
| 1095 | sp -= ((1 + argc + 1 + envc + 1) * 4); |
| 1096 | SET_SPREG (sp); |
| 1097 | |
| 1098 | /* First push the argc value. */ |
| 1099 | sim_write (sd, sp, (void *)&argc, 4); |
| 1100 | sp += 4; |
| 1101 | |
| 1102 | /* Then the actual argv strings so we know where to point argv[]. */ |
| 1103 | for (i = 0; i < argc; ++i) |
| 1104 | { |
| 1105 | unsigned len = strlen (argv[i]) + 1; |
| 1106 | sim_write (sd, sp_flat, (void *)argv[i], len); |
| 1107 | sim_write (sd, sp, (void *)&sp_flat, 4); |
| 1108 | sp_flat += len; |
| 1109 | sp += 4; |
| 1110 | } |
| 1111 | sim_write (sd, sp, null, 4); |
| 1112 | sp += 4; |
| 1113 | |
| 1114 | /* Then the actual env strings so we know where to point env[]. */ |
| 1115 | for (i = 0; i < envc; ++i) |
| 1116 | { |
| 1117 | unsigned len = strlen (env[i]) + 1; |
| 1118 | sim_write (sd, sp_flat, (void *)env[i], len); |
| 1119 | sim_write (sd, sp, (void *)&sp_flat, 4); |
| 1120 | sp_flat += len; |
| 1121 | sp += 4; |
| 1122 | } |
| 1123 | |
| 1124 | /* Set some callbacks. */ |
| 1125 | cb->syscall_map = cb_linux_syscall_map; |
| 1126 | cb->errno_map = cb_linux_errno_map; |
| 1127 | cb->open_map = cb_linux_open_map; |
| 1128 | cb->signal_map = cb_linux_signal_map; |
| 1129 | cb->stat_map = stat_map_32 = cb_linux_stat_map_32; |
| 1130 | stat_map_64 = cb_linux_stat_map_64; |
| 1131 | } |
| 1132 | |
| 1133 | static void |
| 1134 | bfin_os_init (SIM_DESC sd, SIM_CPU *cpu, char * const *argv) |
| 1135 | { |
| 1136 | /* Pass the command line via a string in R0 like Linux expects. */ |
| 1137 | int i; |
| 1138 | bu8 byte; |
| 1139 | bu32 cmdline = BFIN_L1_SRAM_SCRATCH; |
| 1140 | |
| 1141 | SET_DREG (0, cmdline); |
| 1142 | if (argv && argv[0]) |
| 1143 | { |
| 1144 | i = 1; |
| 1145 | byte = ' '; |
| 1146 | while (argv[i]) |
| 1147 | { |
| 1148 | bu32 len = strlen (argv[i]); |
| 1149 | sim_write (sd, cmdline, (void *)argv[i], len); |
| 1150 | cmdline += len; |
| 1151 | sim_write (sd, cmdline, &byte, 1); |
| 1152 | ++cmdline; |
| 1153 | ++i; |
| 1154 | } |
| 1155 | } |
| 1156 | byte = 0; |
| 1157 | sim_write (sd, cmdline, &byte, 1); |
| 1158 | } |
| 1159 | |
| 1160 | static void |
| 1161 | bfin_virtual_init (SIM_DESC sd, SIM_CPU *cpu) |
| 1162 | { |
| 1163 | host_callback *cb = STATE_CALLBACK (sd); |
| 1164 | |
| 1165 | cb->stat_map = stat_map_32 = cb_libgloss_stat_map_32; |
| 1166 | stat_map_64 = NULL; |
| 1167 | } |
| 1168 | |
| 1169 | SIM_RC |
| 1170 | sim_create_inferior (SIM_DESC sd, struct bfd *abfd, |
| 1171 | char * const *argv, char * const *env) |
| 1172 | { |
| 1173 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
| 1174 | SIM_ADDR addr; |
| 1175 | |
| 1176 | /* Set the PC. */ |
| 1177 | if (abfd != NULL) |
| 1178 | addr = bfd_get_start_address (abfd); |
| 1179 | else |
| 1180 | addr = 0; |
| 1181 | sim_pc_set (cpu, addr); |
| 1182 | |
| 1183 | /* Standalone mode (i.e. `run`) will take care of the argv for us in |
| 1184 | sim_open() -> sim_parse_args(). But in debug mode (i.e. 'target sim' |
| 1185 | with `gdb`), we need to handle it because the user can change the |
| 1186 | argv on the fly via gdb's 'run'. */ |
| 1187 | if (STATE_PROG_ARGV (sd) != argv) |
| 1188 | { |
| 1189 | freeargv (STATE_PROG_ARGV (sd)); |
| 1190 | STATE_PROG_ARGV (sd) = dupargv (argv); |
| 1191 | } |
| 1192 | |
| 1193 | switch (STATE_ENVIRONMENT (sd)) |
| 1194 | { |
| 1195 | case USER_ENVIRONMENT: |
| 1196 | bfin_user_init (sd, cpu, abfd, argv, env); |
| 1197 | break; |
| 1198 | case OPERATING_ENVIRONMENT: |
| 1199 | bfin_os_init (sd, cpu, argv); |
| 1200 | break; |
| 1201 | default: |
| 1202 | bfin_virtual_init (sd, cpu); |
| 1203 | break; |
| 1204 | } |
| 1205 | |
| 1206 | return SIM_RC_OK; |
| 1207 | } |