2011-03-06 08:20:21 +08:00
|
|
|
/* Simulator for Analog Devices Blackfin processors.
|
|
|
|
|
2022-01-01 22:56:03 +08:00
|
|
|
Copyright (C) 2005-2022 Free Software Foundation, Inc.
|
2011-03-06 08:20:21 +08:00
|
|
|
Contributed by Analog Devices, Inc.
|
|
|
|
|
|
|
|
This file is part of simulators.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
2021-05-02 06:05:23 +08:00
|
|
|
/* This must come before any other includes. */
|
|
|
|
#include "defs.h"
|
2011-03-06 08:20:21 +08:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
2021-05-30 04:07:43 +08:00
|
|
|
#include "portability.h"
|
2021-05-12 12:35:54 +08:00
|
|
|
#include "sim/callback.h"
|
2011-03-06 08:20:21 +08:00
|
|
|
#include "gdb/signals.h"
|
|
|
|
#include "sim-main.h"
|
2015-06-15 23:24:21 +08:00
|
|
|
#include "sim-syscall.h"
|
2011-03-06 08:20:21 +08:00
|
|
|
#include "sim-hw.h"
|
|
|
|
|
2015-06-13 00:12:52 +08:00
|
|
|
/* The numbers here do not matter. They just need to be unique. They also
|
|
|
|
need not be static across releases -- they're used internally only. The
|
|
|
|
mapping from the Linux ABI to the CB values is in linux-targ-map.h. */
|
2011-03-06 08:20:21 +08:00
|
|
|
#define CB_SYS_ioctl 201
|
|
|
|
#define CB_SYS_mmap2 202
|
|
|
|
#define CB_SYS_munmap 203
|
|
|
|
#define CB_SYS_dup2 204
|
|
|
|
#define CB_SYS_getuid 205
|
|
|
|
#define CB_SYS_getuid32 206
|
|
|
|
#define CB_SYS_getgid 207
|
|
|
|
#define CB_SYS_getgid32 208
|
|
|
|
#define CB_SYS_setuid 209
|
|
|
|
#define CB_SYS_setuid32 210
|
|
|
|
#define CB_SYS_setgid 211
|
|
|
|
#define CB_SYS_setgid32 212
|
|
|
|
#define CB_SYS_pread 213
|
|
|
|
#define CB_SYS__llseek 214
|
|
|
|
#define CB_SYS_getcwd 215
|
|
|
|
#define CB_SYS_stat64 216
|
|
|
|
#define CB_SYS_lstat64 217
|
|
|
|
#define CB_SYS_fstat64 218
|
|
|
|
#define CB_SYS_ftruncate64 219
|
|
|
|
#define CB_SYS_gettimeofday 220
|
|
|
|
#define CB_SYS_access 221
|
|
|
|
#include "linux-targ-map.h"
|
|
|
|
#include "linux-fixed-code.h"
|
|
|
|
|
|
|
|
#include "elf/common.h"
|
|
|
|
#include "elf/external.h"
|
|
|
|
#include "elf/internal.h"
|
|
|
|
#include "elf/bfin.h"
|
|
|
|
#include "elf-bfd.h"
|
|
|
|
|
|
|
|
#include "dv-bfin_cec.h"
|
|
|
|
#include "dv-bfin_mmu.h"
|
|
|
|
|
2011-07-02 05:53:03 +08:00
|
|
|
static const char cb_linux_stat_map_32[] =
|
2011-03-06 08:20:21 +08:00
|
|
|
/* Linux kernel 32bit layout: */
|
|
|
|
"st_dev,2:space,2:st_ino,4:st_mode,2:st_nlink,2:st_uid,2:st_gid,2:st_rdev,2:"
|
|
|
|
"space,2:st_size,4:st_blksize,4:st_blocks,4:st_atime,4:st_atimensec,4:"
|
|
|
|
"st_mtime,4:st_mtimensec,4:st_ctime,4:st_ctimensec,4:space,4:space,4";
|
|
|
|
/* uClibc public ABI 32bit layout:
|
|
|
|
"st_dev,8:space,2:space,2:st_ino,4:st_mode,4:st_nlink,4:st_uid,4:st_gid,4:"
|
|
|
|
"st_rdev,8:space,2:space,2:st_size,4:st_blksiez,4:st_blocks,4:st_atime,4:"
|
|
|
|
"st_atimensec,4:st_mtime,4:st_mtimensec,4:st_ctime,4:st_ctimensec,4:space,4:"
|
|
|
|
"space,4"; */
|
2011-07-02 05:53:03 +08:00
|
|
|
static const char cb_linux_stat_map_64[] =
|
2011-03-06 08:20:21 +08:00
|
|
|
"st_dev,8:space,4:space,4:st_mode,4:st_nlink,4:st_uid,4:st_gid,4:st_rdev,8:"
|
|
|
|
"space,4:st_size,8:st_blksize,4:st_blocks,8:st_atime,4:st_atimensec,4:"
|
|
|
|
"st_mtime,4:st_mtimensec,4:st_ctime,4:st_ctimensec,4:st_ino,8";
|
2011-07-02 05:53:03 +08:00
|
|
|
static const char cb_libgloss_stat_map_32[] =
|
|
|
|
"st_dev,2:st_ino,2:st_mode,4:st_nlink,2:st_uid,2:st_gid,2:st_rdev,2:"
|
|
|
|
"st_size,4:st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:"
|
|
|
|
"space,4:st_blksize,4:st_blocks,4:space,8";
|
|
|
|
static const char *stat_map_32, *stat_map_64;
|
2011-03-06 08:20:21 +08:00
|
|
|
|
|
|
|
/* Simulate a monitor trap, put the result into r0 and errno into r1
|
|
|
|
return offset by which to adjust pc. */
|
|
|
|
|
|
|
|
void
|
|
|
|
bfin_syscall (SIM_CPU *cpu)
|
|
|
|
{
|
|
|
|
SIM_DESC sd = CPU_STATE (cpu);
|
2016-01-03 14:51:44 +08:00
|
|
|
char * const *argv = (void *)STATE_PROG_ARGV (sd);
|
2011-03-06 08:20:21 +08:00
|
|
|
host_callback *cb = STATE_CALLBACK (sd);
|
|
|
|
bu32 args[6];
|
|
|
|
CB_SYSCALL sc;
|
|
|
|
char *p;
|
2011-12-04 03:05:15 +08:00
|
|
|
char _tbuf[1024 * 3], *tbuf = _tbuf, tstr[1024];
|
2011-03-06 08:20:21 +08:00
|
|
|
int fmt_ret_hex = 0;
|
|
|
|
|
|
|
|
CB_SYSCALL_INIT (&sc);
|
|
|
|
|
|
|
|
if (STATE_ENVIRONMENT (sd) == USER_ENVIRONMENT)
|
|
|
|
{
|
|
|
|
/* Linux syscall. */
|
|
|
|
sc.func = PREG (0);
|
|
|
|
sc.arg1 = args[0] = DREG (0);
|
|
|
|
sc.arg2 = args[1] = DREG (1);
|
|
|
|
sc.arg3 = args[2] = DREG (2);
|
|
|
|
sc.arg4 = args[3] = DREG (3);
|
2021-06-24 12:14:15 +08:00
|
|
|
sc.arg5 = args[4] = DREG (4);
|
|
|
|
sc.arg6 = args[5] = DREG (5);
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* libgloss syscall. */
|
|
|
|
sc.func = PREG (0);
|
|
|
|
sc.arg1 = args[0] = GET_LONG (DREG (0));
|
|
|
|
sc.arg2 = args[1] = GET_LONG (DREG (0) + 4);
|
|
|
|
sc.arg3 = args[2] = GET_LONG (DREG (0) + 8);
|
|
|
|
sc.arg4 = args[3] = GET_LONG (DREG (0) + 12);
|
2021-06-24 12:14:15 +08:00
|
|
|
sc.arg5 = args[4] = GET_LONG (DREG (0) + 16);
|
|
|
|
sc.arg6 = args[5] = GET_LONG (DREG (0) + 20);
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
sc.p1 = (PTR) sd;
|
|
|
|
sc.p2 = (PTR) cpu;
|
2015-06-15 23:24:21 +08:00
|
|
|
sc.read_mem = sim_syscall_read_mem;
|
|
|
|
sc.write_mem = sim_syscall_write_mem;
|
2011-03-06 08:20:21 +08:00
|
|
|
|
|
|
|
/* Common cb_syscall() handles most functions. */
|
|
|
|
switch (cb_target_to_host_syscall (cb, sc.func))
|
|
|
|
{
|
|
|
|
case CB_SYS_exit:
|
|
|
|
tbuf += sprintf (tbuf, "exit(%i)", args[0]);
|
|
|
|
sim_engine_halt (sd, cpu, NULL, PCREG, sim_exited, sc.arg1);
|
|
|
|
|
|
|
|
case CB_SYS_gettimeofday:
|
|
|
|
{
|
|
|
|
struct timeval _tv, *tv = &_tv;
|
|
|
|
struct timezone _tz, *tz = &_tz;
|
|
|
|
|
|
|
|
tbuf += sprintf (tbuf, "gettimeofday(%#x, %#x)", args[0], args[1]);
|
|
|
|
|
|
|
|
if (sc.arg1 == 0)
|
|
|
|
tv = NULL;
|
|
|
|
if (sc.arg2 == 0)
|
|
|
|
tz = NULL;
|
|
|
|
sc.result = gettimeofday (tv, tz);
|
|
|
|
|
|
|
|
if (sc.result == 0)
|
|
|
|
{
|
|
|
|
bu32 t;
|
|
|
|
|
|
|
|
if (tv)
|
|
|
|
{
|
|
|
|
t = tv->tv_sec;
|
|
|
|
sc.write_mem (cb, &sc, sc.arg1, (void *)&t, 4);
|
|
|
|
t = tv->tv_usec;
|
|
|
|
sc.write_mem (cb, &sc, sc.arg1 + 4, (void *)&t, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc.arg2)
|
|
|
|
{
|
|
|
|
t = tz->tz_minuteswest;
|
|
|
|
sc.write_mem (cb, &sc, sc.arg1, (void *)&t, 4);
|
|
|
|
t = tz->tz_dsttime;
|
|
|
|
sc.write_mem (cb, &sc, sc.arg1 + 4, (void *)&t, 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
goto sys_finish;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_SYS_ioctl:
|
|
|
|
/* XXX: hack just enough to get basic stdio w/uClibc ... */
|
|
|
|
tbuf += sprintf (tbuf, "ioctl(%i, %#x, %u)", args[0], args[1], args[2]);
|
|
|
|
if (sc.arg2 == 0x5401)
|
|
|
|
{
|
|
|
|
sc.result = !isatty (sc.arg1);
|
|
|
|
sc.errcode = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sc.result = -1;
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, EINVAL);
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_SYS_mmap2:
|
|
|
|
{
|
|
|
|
static bu32 heap = BFIN_DEFAULT_MEM_SIZE / 2;
|
|
|
|
|
|
|
|
fmt_ret_hex = 1;
|
|
|
|
tbuf += sprintf (tbuf, "mmap2(%#x, %u, %#x, %#x, %i, %u)",
|
|
|
|
args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
|
|
|
|
|
|
sc.errcode = 0;
|
|
|
|
|
|
|
|
if (sc.arg4 & 0x20 /*MAP_ANONYMOUS*/)
|
|
|
|
/* XXX: We don't handle zeroing, but default is all zeros. */;
|
|
|
|
else if (args[4] >= MAX_CALLBACK_FDS)
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, ENOSYS);
|
2011-03-06 08:20:21 +08:00
|
|
|
else
|
|
|
|
{
|
2011-03-18 03:03:30 +08:00
|
|
|
#ifdef HAVE_PREAD
|
2011-03-06 08:20:21 +08:00
|
|
|
char *data = xmalloc (sc.arg2);
|
|
|
|
|
|
|
|
/* XXX: Should add a cb->pread. */
|
|
|
|
if (pread (cb->fdmap[args[4]], data, sc.arg2, args[5] << 12) == sc.arg2)
|
|
|
|
sc.write_mem (cb, &sc, heap, data, sc.arg2);
|
|
|
|
else
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, EINVAL);
|
2011-03-06 08:20:21 +08:00
|
|
|
|
|
|
|
free (data);
|
2011-03-18 03:03:30 +08:00
|
|
|
#else
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, ENOSYS);
|
2011-03-18 03:03:30 +08:00
|
|
|
#endif
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sc.errcode)
|
|
|
|
{
|
|
|
|
sc.result = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sc.result = heap;
|
|
|
|
heap += sc.arg2;
|
|
|
|
/* Keep it page aligned. */
|
2015-06-24 00:32:47 +08:00
|
|
|
heap = align_up (heap, 4096);
|
2011-03-06 08:20:21 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case CB_SYS_munmap:
|
|
|
|
/* XXX: meh, just lie for mmap(). */
|
|
|
|
tbuf += sprintf (tbuf, "munmap(%#x, %u)", args[0], args[1]);
|
|
|
|
sc.result = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_SYS_dup2:
|
|
|
|
tbuf += sprintf (tbuf, "dup2(%i, %i)", args[0], args[1]);
|
|
|
|
if (sc.arg1 >= MAX_CALLBACK_FDS || sc.arg2 >= MAX_CALLBACK_FDS)
|
|
|
|
{
|
|
|
|
sc.result = -1;
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, EINVAL);
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sc.result = dup2 (cb->fdmap[sc.arg1], cb->fdmap[sc.arg2]);
|
|
|
|
goto sys_finish;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_SYS__llseek:
|
|
|
|
tbuf += sprintf (tbuf, "llseek(%i, %u, %u, %#x, %u)",
|
|
|
|
args[0], args[1], args[2], args[3], args[4]);
|
|
|
|
sc.func = TARGET_LINUX_SYS_lseek;
|
|
|
|
if (sc.arg2)
|
|
|
|
{
|
|
|
|
sc.result = -1;
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, EINVAL);
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sc.arg2 = sc.arg3;
|
|
|
|
sc.arg3 = args[4];
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
if (sc.result != -1)
|
|
|
|
{
|
|
|
|
bu32 z = 0;
|
|
|
|
sc.write_mem (cb, &sc, args[3], (void *)&sc.result, 4);
|
|
|
|
sc.write_mem (cb, &sc, args[3] + 4, (void *)&z, 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* XXX: Should add a cb->pread. */
|
|
|
|
case CB_SYS_pread:
|
|
|
|
tbuf += sprintf (tbuf, "pread(%i, %#x, %u, %i)",
|
|
|
|
args[0], args[1], args[2], args[3]);
|
|
|
|
if (sc.arg1 >= MAX_CALLBACK_FDS)
|
|
|
|
{
|
|
|
|
sc.result = -1;
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, EINVAL);
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
long old_pos, read_result, read_errcode;
|
|
|
|
|
|
|
|
/* Get current filepos. */
|
|
|
|
sc.func = TARGET_LINUX_SYS_lseek;
|
|
|
|
sc.arg2 = 0;
|
|
|
|
sc.arg3 = SEEK_CUR;
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
if (sc.result == -1)
|
|
|
|
break;
|
|
|
|
old_pos = sc.result;
|
|
|
|
|
|
|
|
/* Move to the new pos. */
|
|
|
|
sc.func = TARGET_LINUX_SYS_lseek;
|
|
|
|
sc.arg2 = args[3];
|
|
|
|
sc.arg3 = SEEK_SET;
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
if (sc.result == -1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read the data. */
|
|
|
|
sc.func = TARGET_LINUX_SYS_read;
|
|
|
|
sc.arg2 = args[1];
|
|
|
|
sc.arg3 = args[2];
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
read_result = sc.result;
|
|
|
|
read_errcode = sc.errcode;
|
|
|
|
|
|
|
|
/* Move back to the old pos. */
|
|
|
|
sc.func = TARGET_LINUX_SYS_lseek;
|
|
|
|
sc.arg2 = old_pos;
|
|
|
|
sc.arg3 = SEEK_SET;
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
|
|
|
|
sc.result = read_result;
|
|
|
|
sc.errcode = read_errcode;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_SYS_getcwd:
|
|
|
|
tbuf += sprintf (tbuf, "getcwd(%#x, %u)", args[0], args[1]);
|
|
|
|
|
|
|
|
p = alloca (sc.arg2);
|
|
|
|
if (getcwd (p, sc.arg2) == NULL)
|
|
|
|
{
|
|
|
|
sc.result = -1;
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, EINVAL);
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sc.write_mem (cb, &sc, sc.arg1, p, sc.arg2);
|
|
|
|
sc.result = sc.arg1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_SYS_stat64:
|
2011-12-04 03:05:15 +08:00
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "stat64(%#x:\"%s\", %u)", args[0], tstr, args[1]);
|
2011-03-06 08:20:21 +08:00
|
|
|
cb->stat_map = stat_map_64;
|
|
|
|
sc.func = TARGET_LINUX_SYS_stat;
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
cb->stat_map = stat_map_32;
|
|
|
|
break;
|
|
|
|
case CB_SYS_lstat64:
|
2011-12-04 03:05:15 +08:00
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "lstat64(%#x:\"%s\", %u)", args[0], tstr, args[1]);
|
2011-03-06 08:20:21 +08:00
|
|
|
cb->stat_map = stat_map_64;
|
|
|
|
sc.func = TARGET_LINUX_SYS_lstat;
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
cb->stat_map = stat_map_32;
|
|
|
|
break;
|
|
|
|
case CB_SYS_fstat64:
|
|
|
|
tbuf += sprintf (tbuf, "fstat64(%#x, %u)", args[0], args[1]);
|
|
|
|
cb->stat_map = stat_map_64;
|
|
|
|
sc.func = TARGET_LINUX_SYS_fstat;
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
cb->stat_map = stat_map_32;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_SYS_ftruncate64:
|
|
|
|
tbuf += sprintf (tbuf, "ftruncate64(%u, %u)", args[0], args[1]);
|
|
|
|
sc.func = TARGET_LINUX_SYS_ftruncate;
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_SYS_getuid:
|
|
|
|
case CB_SYS_getuid32:
|
|
|
|
tbuf += sprintf (tbuf, "getuid()");
|
|
|
|
sc.result = getuid ();
|
|
|
|
goto sys_finish;
|
|
|
|
case CB_SYS_getgid:
|
|
|
|
case CB_SYS_getgid32:
|
|
|
|
tbuf += sprintf (tbuf, "getgid()");
|
|
|
|
sc.result = getgid ();
|
|
|
|
goto sys_finish;
|
|
|
|
case CB_SYS_setuid:
|
|
|
|
sc.arg1 &= 0xffff;
|
|
|
|
case CB_SYS_setuid32:
|
|
|
|
tbuf += sprintf (tbuf, "setuid(%u)", args[0]);
|
|
|
|
sc.result = setuid (sc.arg1);
|
|
|
|
goto sys_finish;
|
|
|
|
case CB_SYS_setgid:
|
|
|
|
sc.arg1 &= 0xffff;
|
|
|
|
case CB_SYS_setgid32:
|
|
|
|
tbuf += sprintf (tbuf, "setgid(%u)", args[0]);
|
|
|
|
sc.result = setgid (sc.arg1);
|
|
|
|
goto sys_finish;
|
|
|
|
|
|
|
|
case CB_SYS_kill:
|
|
|
|
tbuf += sprintf (tbuf, "kill(%u, %i)", args[0], args[1]);
|
|
|
|
/* Only let the app kill itself. */
|
|
|
|
if (sc.arg1 != getpid ())
|
|
|
|
{
|
|
|
|
sc.result = -1;
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, EPERM);
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-03-18 03:03:30 +08:00
|
|
|
#ifdef HAVE_KILL
|
2011-03-06 08:20:21 +08:00
|
|
|
sc.result = kill (sc.arg1, sc.arg2);
|
|
|
|
goto sys_finish;
|
2011-03-18 03:03:30 +08:00
|
|
|
#else
|
|
|
|
sc.result = -1;
|
2021-07-07 10:23:02 +08:00
|
|
|
sc.errcode = cb_host_to_target_errno (cb, ENOSYS);
|
2011-03-18 03:03:30 +08:00
|
|
|
#endif
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_SYS_open:
|
2011-12-04 03:05:15 +08:00
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "open(%#x:\"%s\", %#x, %o)",
|
|
|
|
args[0], tstr, args[1], args[2]);
|
2011-03-06 08:20:21 +08:00
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_close:
|
|
|
|
tbuf += sprintf (tbuf, "close(%i)", args[0]);
|
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_read:
|
|
|
|
tbuf += sprintf (tbuf, "read(%i, %#x, %u)", args[0], args[1], args[2]);
|
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_write:
|
2011-12-04 03:05:15 +08:00
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[1]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "write(%i, %#x:\"%s\", %u)",
|
|
|
|
args[0], args[1], tstr, args[2]);
|
2011-03-06 08:20:21 +08:00
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_lseek:
|
|
|
|
tbuf += sprintf (tbuf, "lseek(%i, %i, %i)", args[0], args[1], args[2]);
|
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_unlink:
|
2011-12-04 03:05:15 +08:00
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "unlink(%#x:\"%s\")", args[0], tstr);
|
2011-03-06 08:20:21 +08:00
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_truncate:
|
2011-12-04 03:05:15 +08:00
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "truncate(%#x:\"%s\", %i)", args[0], tstr, args[1]);
|
2011-03-06 08:20:21 +08:00
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_ftruncate:
|
|
|
|
tbuf += sprintf (tbuf, "ftruncate(%i, %i)", args[0], args[1]);
|
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_rename:
|
2011-12-04 03:05:15 +08:00
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "rename(%#x:\"%s\", ", args[0], tstr);
|
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[1]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "%#x:\"%s\")", args[1], tstr);
|
2011-03-06 08:20:21 +08:00
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_stat:
|
2011-12-04 03:05:15 +08:00
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "stat(%#x:\"%s\", %#x)", args[0], tstr, args[1]);
|
2011-03-06 08:20:21 +08:00
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_fstat:
|
|
|
|
tbuf += sprintf (tbuf, "fstat(%i, %#x)", args[0], args[1]);
|
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_lstat:
|
2011-12-04 03:05:15 +08:00
|
|
|
if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0]))
|
|
|
|
strcpy (tstr, "???");
|
|
|
|
tbuf += sprintf (tbuf, "lstat(%#x:\"%s\", %#x)", args[0], tstr, args[1]);
|
2011-03-06 08:20:21 +08:00
|
|
|
goto case_default;
|
|
|
|
case CB_SYS_pipe:
|
|
|
|
tbuf += sprintf (tbuf, "pipe(%#x, %#x)", args[0], args[1]);
|
|
|
|
goto case_default;
|
|
|
|
|
|
|
|
default:
|
|
|
|
tbuf += sprintf (tbuf, "???_%i(%#x, %#x, %#x, %#x, %#x, %#x)", sc.func,
|
|
|
|
args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
|
|
case_default:
|
|
|
|
cb_syscall (cb, &sc);
|
|
|
|
break;
|
|
|
|
|
|
|
|
sys_finish:
|
|
|
|
if (sc.result == -1)
|
|
|
|
{
|
|
|
|
cb->last_errno = errno;
|
|
|
|
sc.errcode = cb->get_errno (cb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE_EVENTS (cpu, "syscall_%i(%#x, %#x, %#x, %#x, %#x, %#x) = %li (error = %i)",
|
|
|
|
sc.func, args[0], args[1], args[2], args[3], args[4], args[5],
|
|
|
|
sc.result, sc.errcode);
|
|
|
|
|
|
|
|
tbuf += sprintf (tbuf, " = ");
|
|
|
|
if (STATE_ENVIRONMENT (sd) == USER_ENVIRONMENT)
|
|
|
|
{
|
|
|
|
if (sc.result == -1)
|
|
|
|
{
|
|
|
|
tbuf += sprintf (tbuf, "-1 (error = %i)", sc.errcode);
|
|
|
|
if (sc.errcode == cb_host_to_target_errno (cb, ENOSYS))
|
|
|
|
{
|
|
|
|
sim_io_eprintf (sd, "bfin-sim: %#x: unimplemented syscall %i\n",
|
|
|
|
PCREG, sc.func);
|
|
|
|
}
|
|
|
|
SET_DREG (0, -sc.errcode);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fmt_ret_hex)
|
|
|
|
tbuf += sprintf (tbuf, "%#lx", sc.result);
|
|
|
|
else
|
|
|
|
tbuf += sprintf (tbuf, "%lu", sc.result);
|
|
|
|
SET_DREG (0, sc.result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tbuf += sprintf (tbuf, "%lu (error = %i)", sc.result, sc.errcode);
|
|
|
|
SET_DREG (0, sc.result);
|
2011-06-22 12:21:29 +08:00
|
|
|
SET_DREG (1, sc.result2);
|
|
|
|
SET_DREG (2, sc.errcode);
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TRACE_SYSCALL (cpu, "%s", _tbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Execute a single instruction. */
|
|
|
|
|
|
|
|
static sim_cia
|
|
|
|
step_once (SIM_CPU *cpu)
|
|
|
|
{
|
|
|
|
SIM_DESC sd = CPU_STATE (cpu);
|
|
|
|
bu32 insn_len, oldpc = PCREG;
|
|
|
|
int i;
|
|
|
|
bool ssstep;
|
|
|
|
|
|
|
|
if (TRACE_ANY_P (cpu))
|
|
|
|
trace_prefix (sd, cpu, NULL_CIA, oldpc, TRACE_LINENUM_P (cpu),
|
|
|
|
NULL, 0, " "); /* Use a space for gcc warnings. */
|
|
|
|
|
2015-12-31 12:20:23 +08:00
|
|
|
TRACE_DISASM (cpu, oldpc);
|
|
|
|
|
2011-03-06 08:20:21 +08:00
|
|
|
/* Handle hardware single stepping when lower than EVT3, and when SYSCFG
|
|
|
|
has already had the SSSTEP bit enabled. */
|
|
|
|
ssstep = false;
|
|
|
|
if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT
|
|
|
|
&& (SYSCFGREG & SYSCFG_SSSTEP))
|
|
|
|
{
|
|
|
|
int ivg = cec_get_ivg (cpu);
|
|
|
|
if (ivg == -1 || ivg > 3)
|
|
|
|
ssstep = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* XXX: Is this what happens on the hardware ? */
|
|
|
|
if (cec_get_ivg (cpu) == EVT_EMU)
|
|
|
|
cec_return (cpu, EVT_EMU);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BFIN_CPU_STATE.did_jump = false;
|
|
|
|
|
|
|
|
insn_len = interp_insn_bfin (cpu, oldpc);
|
|
|
|
|
|
|
|
/* If we executed this insn successfully, then we always decrement
|
|
|
|
the loop counter. We don't want to update the PC though if the
|
|
|
|
last insn happened to be a change in code flow (jump/etc...). */
|
|
|
|
if (!BFIN_CPU_STATE.did_jump)
|
|
|
|
SET_PCREG (hwloop_get_next_pc (cpu, oldpc, insn_len));
|
|
|
|
for (i = 1; i >= 0; --i)
|
|
|
|
if (LCREG (i) && oldpc == LBREG (i))
|
|
|
|
{
|
|
|
|
SET_LCREG (i, LCREG (i) - 1);
|
|
|
|
if (LCREG (i))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
++ PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu));
|
|
|
|
|
|
|
|
/* Handle hardware single stepping only if we're still lower than EVT3.
|
|
|
|
XXX: May not be entirely correct wrt EXCPT insns. */
|
|
|
|
if (ssstep)
|
|
|
|
{
|
|
|
|
int ivg = cec_get_ivg (cpu);
|
|
|
|
if (ivg == -1 || ivg > 3)
|
|
|
|
{
|
|
|
|
INSN_LEN = 0;
|
|
|
|
cec_exception (cpu, VEC_STEP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return oldpc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_engine_run (SIM_DESC sd,
|
|
|
|
int next_cpu_nr, /* ignore */
|
|
|
|
int nr_cpus, /* ignore */
|
|
|
|
int siggnal) /* ignore */
|
|
|
|
{
|
|
|
|
bu32 ticks;
|
|
|
|
SIM_CPU *cpu;
|
|
|
|
|
|
|
|
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
|
|
|
|
|
|
|
|
cpu = STATE_CPU (sd, 0);
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
step_once (cpu);
|
|
|
|
/* Process any events -- can't use tickn because it may
|
|
|
|
advance right over the next event. */
|
|
|
|
for (ticks = 0; ticks < CYCLE_DELAY; ++ticks)
|
|
|
|
if (sim_events_tick (sd))
|
|
|
|
sim_events_process (sd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cover function of sim_state_free to free the cpu buffers as well. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_state (SIM_DESC sd)
|
|
|
|
{
|
|
|
|
if (STATE_MODULES (sd) != NULL)
|
|
|
|
sim_module_uninstall (sd);
|
|
|
|
sim_cpu_free_all (sd);
|
|
|
|
sim_state_free (sd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create an instance of the simulator. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
bfin_initialize_cpu (SIM_DESC sd, SIM_CPU *cpu)
|
|
|
|
{
|
|
|
|
memset (&cpu->state, 0, sizeof (cpu->state));
|
|
|
|
|
|
|
|
PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) = 0;
|
|
|
|
|
|
|
|
bfin_model_cpu_init (sd, cpu);
|
|
|
|
|
|
|
|
/* Set default stack to top of scratch pad. */
|
|
|
|
SET_SPREG (BFIN_DEFAULT_MEM_SIZE);
|
|
|
|
SET_KSPREG (BFIN_DEFAULT_MEM_SIZE);
|
|
|
|
SET_USPREG (BFIN_DEFAULT_MEM_SIZE);
|
|
|
|
|
|
|
|
/* This is what the hardware likes. */
|
|
|
|
SET_SYSCFGREG (0x30);
|
|
|
|
}
|
|
|
|
|
|
|
|
SIM_DESC
|
|
|
|
sim_open (SIM_OPEN_KIND kind, host_callback *callback,
|
2016-01-03 14:51:44 +08:00
|
|
|
struct bfd *abfd, char * const *argv)
|
2011-03-06 08:20:21 +08:00
|
|
|
{
|
|
|
|
char c;
|
|
|
|
int i;
|
2016-01-22 10:05:33 +08:00
|
|
|
SIM_DESC sd = sim_state_alloc_extra (kind, callback,
|
|
|
|
sizeof (struct bfin_board_data));
|
2011-03-06 08:20:21 +08:00
|
|
|
|
sim: overhaul alignment settings management
Currently, the sim-config module will abort if alignment settings
haven't been specified by the port's configure.ac. This is a bit
weird when we've allowed SIM_AC_OPTION_ALIGNMENT to seem like it's
optional to use. Thus everyone invokes it.
There are 4 alignment settings, but really only 2 matters: strict
and nonstrict. The "mixed" setting is just the default ("unset"),
and "forced" isn't used directly by anyone (it's available as a
runtime option for some ports).
The m4 macro has 2 args: the "wire" settings (which represents the
hardwired port behavior), and the default settings (which are used
if nothing else is specified). If none are specified, then the
build won't work (see above as if SIM_AC_OPTION_ALIGNMENT wasn't
called). If default settings are provided, then that is used, but
we allow the user to override at runtime. Otherwise, the "wire"
settings are used and user runtime options to change are ignored.
Most ports specify a default, or set the "wire" to nonstrict. A
few set "wire" to strict, but it's not clear that's necessary as
it doesn't make the code behavior, by default, any different. It
might make things a little faster, but we should provide the user
the choice of the compromises to make: force a specific mode at
compile time for faster runtime, or allow the choice at runtime.
More likely it seems like an oversight when these ports were
initially created, and/or copied & pasted from existing ports.
With all that backstory, let's get to what this commit does.
First kill off the idea of a compile-time default alignment and
set it to nonstrict in the common code. For any ports that want
strict alignment by default, that code is moved to sim_open while
initializing the sim. That means WITH_DEFAULT_ALIGNMENT can be
completely removed.
Moving the default alignment to the runtime also allows removal
of setting the "wire" settings at configure time. Which allows
removing of all arguments to SIM_AC_OPTION_ALIGNMENT and moving
that call to common code.
The macro logic can be reworked to not pass WITH_ALIGNMENT as -D
CPPFLAG and instead move it to config.h.
All of these taken together mean we can hoist the macro up to the
top level and share it among all sims so behavior is consistent
among all the ports.
2021-06-07 12:54:20 +08:00
|
|
|
/* Set default options before parsing user options. */
|
2021-06-29 09:42:56 +08:00
|
|
|
STATE_MACHS (sd) = bfin_sim_machs;
|
2021-06-29 10:07:44 +08:00
|
|
|
STATE_MODEL_NAME (sd) = "bf537";
|
sim: overhaul alignment settings management
Currently, the sim-config module will abort if alignment settings
haven't been specified by the port's configure.ac. This is a bit
weird when we've allowed SIM_AC_OPTION_ALIGNMENT to seem like it's
optional to use. Thus everyone invokes it.
There are 4 alignment settings, but really only 2 matters: strict
and nonstrict. The "mixed" setting is just the default ("unset"),
and "forced" isn't used directly by anyone (it's available as a
runtime option for some ports).
The m4 macro has 2 args: the "wire" settings (which represents the
hardwired port behavior), and the default settings (which are used
if nothing else is specified). If none are specified, then the
build won't work (see above as if SIM_AC_OPTION_ALIGNMENT wasn't
called). If default settings are provided, then that is used, but
we allow the user to override at runtime. Otherwise, the "wire"
settings are used and user runtime options to change are ignored.
Most ports specify a default, or set the "wire" to nonstrict. A
few set "wire" to strict, but it's not clear that's necessary as
it doesn't make the code behavior, by default, any different. It
might make things a little faster, but we should provide the user
the choice of the compromises to make: force a specific mode at
compile time for faster runtime, or allow the choice at runtime.
More likely it seems like an oversight when these ports were
initially created, and/or copied & pasted from existing ports.
With all that backstory, let's get to what this commit does.
First kill off the idea of a compile-time default alignment and
set it to nonstrict in the common code. For any ports that want
strict alignment by default, that code is moved to sim_open while
initializing the sim. That means WITH_DEFAULT_ALIGNMENT can be
completely removed.
Moving the default alignment to the runtime also allows removal
of setting the "wire" settings at configure time. Which allows
removing of all arguments to SIM_AC_OPTION_ALIGNMENT and moving
that call to common code.
The macro logic can be reworked to not pass WITH_ALIGNMENT as -D
CPPFLAG and instead move it to config.h.
All of these taken together mean we can hoist the macro up to the
top level and share it among all sims so behavior is consistent
among all the ports.
2021-06-07 12:54:20 +08:00
|
|
|
current_alignment = STRICT_ALIGNMENT;
|
sim: overhaul & unify endian settings management
The m4 macro has 2 args: the "wire" settings (which represents the
hardwired port behavior), and the default settings (which are used
if nothing else is specified). If none are specified, the arch is
expected to support both, and the value will be probed based on the
user runtime options or the input program.
Only two arches today set the default value (bpf & mips). We can
probably let this go as it only shows up in one scenario: the sim
is invoked, but with no inputs, and no user endian selection. This
means bpf will not behave like the other arches: an error is shown
and forces the user to make a choice. If an input program is used
though, we'll still switch the default to that. This allows us to
remove the WITH_DEFAULT_TARGET_BYTE_ORDER setting.
For the ports that set a "wire" endian, move it to the runtime init
of the respective sim_open calls. This allows us to change the
WITH_TARGET_BYTE_ORDER to purely a user-selected configure setting
if they want to force a specific endianness.
With all the endian logic moved to runtime selection, we can move
the configure call up to the common dir so we only process it once
across all ports.
The ppc arch was picking the wire endian based on the target used,
but since we weren't doing that for other biendian arches, we can
let this go too. We'll rely on the input selecting the endian, or
make the user decide.
2021-06-16 07:51:52 +08:00
|
|
|
current_target_byte_order = BFD_ENDIAN_LITTLE;
|
sim: overhaul alignment settings management
Currently, the sim-config module will abort if alignment settings
haven't been specified by the port's configure.ac. This is a bit
weird when we've allowed SIM_AC_OPTION_ALIGNMENT to seem like it's
optional to use. Thus everyone invokes it.
There are 4 alignment settings, but really only 2 matters: strict
and nonstrict. The "mixed" setting is just the default ("unset"),
and "forced" isn't used directly by anyone (it's available as a
runtime option for some ports).
The m4 macro has 2 args: the "wire" settings (which represents the
hardwired port behavior), and the default settings (which are used
if nothing else is specified). If none are specified, then the
build won't work (see above as if SIM_AC_OPTION_ALIGNMENT wasn't
called). If default settings are provided, then that is used, but
we allow the user to override at runtime. Otherwise, the "wire"
settings are used and user runtime options to change are ignored.
Most ports specify a default, or set the "wire" to nonstrict. A
few set "wire" to strict, but it's not clear that's necessary as
it doesn't make the code behavior, by default, any different. It
might make things a little faster, but we should provide the user
the choice of the compromises to make: force a specific mode at
compile time for faster runtime, or allow the choice at runtime.
More likely it seems like an oversight when these ports were
initially created, and/or copied & pasted from existing ports.
With all that backstory, let's get to what this commit does.
First kill off the idea of a compile-time default alignment and
set it to nonstrict in the common code. For any ports that want
strict alignment by default, that code is moved to sim_open while
initializing the sim. That means WITH_DEFAULT_ALIGNMENT can be
completely removed.
Moving the default alignment to the runtime also allows removal
of setting the "wire" settings at configure time. Which allows
removing of all arguments to SIM_AC_OPTION_ALIGNMENT and moving
that call to common code.
The macro logic can be reworked to not pass WITH_ALIGNMENT as -D
CPPFLAG and instead move it to config.h.
All of these taken together mean we can hoist the macro up to the
top level and share it among all sims so behavior is consistent
among all the ports.
2021-06-07 12:54:20 +08:00
|
|
|
|
2011-03-06 08:20:21 +08:00
|
|
|
/* The cpu data is kept in a separately allocated chunk of memory. */
|
2016-08-12 22:12:41 +08:00
|
|
|
if (sim_cpu_alloc_all (sd, 1) != SIM_RC_OK)
|
2011-03-06 08:20:21 +08:00
|
|
|
{
|
|
|
|
free_state (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
|
|
|
|
{
|
|
|
|
free_state (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: Default to the Virtual environment. */
|
|
|
|
if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT)
|
|
|
|
STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT;
|
|
|
|
|
2016-01-04 10:40:34 +08:00
|
|
|
/* The parser will print an error message for us, so we silently return. */
|
2011-03-06 08:20:21 +08:00
|
|
|
if (sim_parse_args (sd, argv) != SIM_RC_OK)
|
|
|
|
{
|
|
|
|
free_state (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate external memory if none specified by user.
|
|
|
|
Use address 4 here in case the user wanted address 0 unmapped. */
|
|
|
|
if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
|
|
|
|
{
|
|
|
|
bu16 emuexcpt = 0x25;
|
2021-05-03 22:54:08 +08:00
|
|
|
sim_do_commandf (sd, "memory-size 0x%x", BFIN_DEFAULT_MEM_SIZE);
|
2011-03-06 08:20:21 +08:00
|
|
|
sim_write (sd, 0, (void *)&emuexcpt, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for/establish the a reference program image. */
|
2021-11-15 15:32:06 +08:00
|
|
|
if (sim_analyze_program (sd, STATE_PROG_FILE (sd), abfd) != SIM_RC_OK)
|
2011-03-06 08:20:21 +08:00
|
|
|
{
|
|
|
|
free_state (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Establish any remaining configuration options. */
|
|
|
|
if (sim_config (sd) != SIM_RC_OK)
|
|
|
|
{
|
|
|
|
free_state (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sim_post_argv_init (sd) != SIM_RC_OK)
|
|
|
|
{
|
|
|
|
free_state (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CPU specific initialization. */
|
|
|
|
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
|
|
|
|
{
|
|
|
|
SIM_CPU *cpu = STATE_CPU (sd, i);
|
|
|
|
bfin_initialize_cpu (sd, cpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Some utils don't like having a NULL environ. */
|
2016-01-03 14:51:44 +08:00
|
|
|
static char * const simple_env[] = { "HOME=/", "PATH=/bin", NULL };
|
2011-03-06 08:20:21 +08:00
|
|
|
|
|
|
|
static bu32 fdpic_load_offset;
|
|
|
|
|
|
|
|
static bool
|
|
|
|
bfin_fdpic_load (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd, bu32 *sp,
|
|
|
|
bu32 *elf_addrs, char **ldso_path)
|
|
|
|
{
|
|
|
|
bool ret;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
Elf_Internal_Ehdr *iehdr;
|
|
|
|
Elf32_External_Ehdr ehdr;
|
|
|
|
Elf_Internal_Phdr *phdrs;
|
|
|
|
unsigned char *data;
|
|
|
|
long phdr_size;
|
|
|
|
int phdrc;
|
|
|
|
bu32 nsegs;
|
|
|
|
|
|
|
|
bu32 max_load_addr;
|
|
|
|
|
|
|
|
unsigned char null[4] = { 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
ret = false;
|
|
|
|
*ldso_path = NULL;
|
|
|
|
|
|
|
|
/* See if this an FDPIC ELF. */
|
|
|
|
phdrs = NULL;
|
|
|
|
if (!abfd)
|
|
|
|
goto skip_fdpic_init;
|
|
|
|
if (bfd_seek (abfd, 0, SEEK_SET) != 0)
|
|
|
|
goto skip_fdpic_init;
|
|
|
|
if (bfd_bread (&ehdr, sizeof (ehdr), abfd) != sizeof (ehdr))
|
|
|
|
goto skip_fdpic_init;
|
|
|
|
iehdr = elf_elfheader (abfd);
|
|
|
|
if (!(iehdr->e_flags & EF_BFIN_FDPIC))
|
|
|
|
goto skip_fdpic_init;
|
|
|
|
|
|
|
|
if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
|
|
|
|
sim_io_printf (sd, "Loading FDPIC ELF %s\n Load base: %#x\n ELF entry: %#x\n",
|
|
|
|
bfd_get_filename (abfd), fdpic_load_offset, elf_addrs[0]);
|
|
|
|
|
|
|
|
/* Grab the Program Headers to set up the loadsegs on the stack. */
|
|
|
|
phdr_size = bfd_get_elf_phdr_upper_bound (abfd);
|
|
|
|
if (phdr_size == -1)
|
|
|
|
goto skip_fdpic_init;
|
|
|
|
phdrs = xmalloc (phdr_size);
|
|
|
|
phdrc = bfd_get_elf_phdrs (abfd, phdrs);
|
|
|
|
if (phdrc == -1)
|
|
|
|
goto skip_fdpic_init;
|
|
|
|
|
|
|
|
/* Push the Ehdr onto the stack. */
|
|
|
|
*sp -= sizeof (ehdr);
|
|
|
|
elf_addrs[3] = *sp;
|
|
|
|
sim_write (sd, *sp, (void *)&ehdr, sizeof (ehdr));
|
|
|
|
if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
|
|
|
|
sim_io_printf (sd, " Elf_Ehdr: %#x\n", *sp);
|
|
|
|
|
|
|
|
/* Since we're relocating things ourselves, we need to relocate
|
|
|
|
the start address as well. */
|
|
|
|
elf_addrs[0] = bfd_get_start_address (abfd) + fdpic_load_offset;
|
|
|
|
|
|
|
|
/* And the Exec's Phdrs onto the stack. */
|
|
|
|
if (STATE_PROG_BFD (sd) == abfd)
|
|
|
|
{
|
|
|
|
elf_addrs[4] = elf_addrs[0];
|
|
|
|
|
|
|
|
phdr_size = iehdr->e_phentsize * iehdr->e_phnum;
|
|
|
|
if (bfd_seek (abfd, iehdr->e_phoff, SEEK_SET) != 0)
|
|
|
|
goto skip_fdpic_init;
|
|
|
|
data = xmalloc (phdr_size);
|
|
|
|
if (bfd_bread (data, phdr_size, abfd) != phdr_size)
|
|
|
|
goto skip_fdpic_init;
|
|
|
|
*sp -= phdr_size;
|
|
|
|
elf_addrs[1] = *sp;
|
|
|
|
elf_addrs[2] = phdrc;
|
|
|
|
sim_write (sd, *sp, data, phdr_size);
|
|
|
|
free (data);
|
|
|
|
if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
|
|
|
|
sim_io_printf (sd, " Elf_Phdrs: %#x\n", *sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now push all the loadsegs. */
|
|
|
|
nsegs = 0;
|
|
|
|
max_load_addr = 0;
|
|
|
|
for (i = phdrc; i >= 0; --i)
|
|
|
|
if (phdrs[i].p_type == PT_LOAD)
|
|
|
|
{
|
|
|
|
Elf_Internal_Phdr *p = &phdrs[i];
|
|
|
|
bu32 paddr, vaddr, memsz, filesz;
|
|
|
|
|
|
|
|
paddr = p->p_paddr + fdpic_load_offset;
|
|
|
|
vaddr = p->p_vaddr;
|
|
|
|
memsz = p->p_memsz;
|
|
|
|
filesz = p->p_filesz;
|
|
|
|
|
|
|
|
if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
|
|
|
|
sim_io_printf (sd, " PHDR %i: vma %#x lma %#x filesz %#x memsz %#x\n",
|
|
|
|
i, vaddr, paddr, filesz, memsz);
|
|
|
|
|
|
|
|
data = xmalloc (memsz);
|
|
|
|
if (memsz != filesz)
|
|
|
|
memset (data + filesz, 0, memsz - filesz);
|
|
|
|
|
|
|
|
if (bfd_seek (abfd, p->p_offset, SEEK_SET) == 0
|
|
|
|
&& bfd_bread (data, filesz, abfd) == filesz)
|
|
|
|
sim_write (sd, paddr, data, memsz);
|
|
|
|
|
|
|
|
free (data);
|
|
|
|
|
2016-01-05 11:24:03 +08:00
|
|
|
max_load_addr = max (paddr + memsz, max_load_addr);
|
2011-03-06 08:20:21 +08:00
|
|
|
|
|
|
|
*sp -= 12;
|
|
|
|
sim_write (sd, *sp+0, (void *)&paddr, 4); /* loadseg.addr */
|
|
|
|
sim_write (sd, *sp+4, (void *)&vaddr, 4); /* loadseg.p_vaddr */
|
|
|
|
sim_write (sd, *sp+8, (void *)&memsz, 4); /* loadseg.p_memsz */
|
|
|
|
++nsegs;
|
|
|
|
}
|
|
|
|
else if (phdrs[i].p_type == PT_DYNAMIC)
|
|
|
|
{
|
|
|
|
elf_addrs[5] = phdrs[i].p_paddr + fdpic_load_offset;
|
|
|
|
if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
|
|
|
|
sim_io_printf (sd, " PT_DYNAMIC: %#x\n", elf_addrs[5]);
|
|
|
|
}
|
|
|
|
else if (phdrs[i].p_type == PT_INTERP)
|
|
|
|
{
|
|
|
|
uint32_t off = phdrs[i].p_offset;
|
|
|
|
uint32_t len = phdrs[i].p_filesz;
|
|
|
|
|
|
|
|
*ldso_path = xmalloc (len);
|
|
|
|
if (bfd_seek (abfd, off, SEEK_SET) != 0
|
|
|
|
|| bfd_bread (*ldso_path, len, abfd) != len)
|
|
|
|
{
|
|
|
|
free (*ldso_path);
|
|
|
|
*ldso_path = NULL;
|
|
|
|
}
|
|
|
|
else if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
|
|
|
|
sim_io_printf (sd, " PT_INTERP: %s\n", *ldso_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the load offset with a few extra pages. */
|
2015-06-24 00:32:47 +08:00
|
|
|
fdpic_load_offset = align_up (max (max_load_addr, fdpic_load_offset),
|
|
|
|
0x10000);
|
2011-03-06 08:20:21 +08:00
|
|
|
fdpic_load_offset += 0x10000;
|
|
|
|
|
|
|
|
/* Push the summary loadmap info onto the stack last. */
|
|
|
|
*sp -= 4;
|
|
|
|
sim_write (sd, *sp+0, null, 2); /* loadmap.version */
|
|
|
|
sim_write (sd, *sp+2, (void *)&nsegs, 2); /* loadmap.nsegs */
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
skip_fdpic_init:
|
|
|
|
free (phdrs);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bfin_user_init (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd,
|
2016-01-03 14:51:44 +08:00
|
|
|
char * const *argv, char * const *env)
|
2011-03-06 08:20:21 +08:00
|
|
|
{
|
|
|
|
/* XXX: Missing host -> target endian ... */
|
|
|
|
/* Linux starts the user app with the stack:
|
|
|
|
argc
|
|
|
|
argv[0] -- pointers to the actual strings
|
|
|
|
argv[1..N]
|
|
|
|
NULL
|
|
|
|
env[0]
|
|
|
|
env[1..N]
|
|
|
|
NULL
|
|
|
|
auxvt[0].type -- ELF Auxiliary Vector Table
|
|
|
|
auxvt[0].value
|
|
|
|
auxvt[1..N]
|
|
|
|
AT_NULL
|
|
|
|
0
|
|
|
|
argv[0..N][0..M] -- actual argv/env strings
|
|
|
|
env[0..N][0..M]
|
|
|
|
FDPIC loadmaps -- for FDPIC apps
|
|
|
|
So set things up the same way. */
|
|
|
|
int i, argc, envc;
|
|
|
|
bu32 argv_flat, env_flat;
|
|
|
|
|
|
|
|
bu32 sp, sp_flat;
|
|
|
|
|
|
|
|
/* start, at_phdr, at_phnum, at_base, at_entry, pt_dynamic */
|
|
|
|
bu32 elf_addrs[6];
|
2012-04-01 10:39:12 +08:00
|
|
|
bu32 auxvt;
|
2011-03-06 08:20:21 +08:00
|
|
|
bu32 exec_loadmap, ldso_loadmap;
|
|
|
|
char *ldso_path;
|
|
|
|
|
|
|
|
unsigned char null[4] = { 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
host_callback *cb = STATE_CALLBACK (sd);
|
|
|
|
|
|
|
|
elf_addrs[0] = elf_addrs[4] = bfd_get_start_address (abfd);
|
|
|
|
elf_addrs[1] = elf_addrs[2] = elf_addrs[3] = elf_addrs[5] = 0;
|
|
|
|
|
|
|
|
/* Keep the load addresses consistent between runs. Also make sure we make
|
|
|
|
space for the fixed code region (part of the Blackfin Linux ABI). */
|
|
|
|
fdpic_load_offset = 0x1000;
|
|
|
|
|
|
|
|
/* First try to load this as an FDPIC executable. */
|
|
|
|
sp = SPREG;
|
|
|
|
if (!bfin_fdpic_load (sd, cpu, STATE_PROG_BFD (sd), &sp, elf_addrs, &ldso_path))
|
|
|
|
goto skip_fdpic_init;
|
|
|
|
exec_loadmap = sp;
|
|
|
|
|
|
|
|
/* If that worked, then load the fixed code region. We only do this for
|
|
|
|
FDPIC ELFs atm because they are PIEs and let us relocate them without
|
|
|
|
manual fixups. FLAT files however require location processing which
|
|
|
|
we do not do ourselves, and they link with a VMA of 0. */
|
|
|
|
sim_write (sd, 0x400, bfin_linux_fixed_code, sizeof (bfin_linux_fixed_code));
|
|
|
|
|
|
|
|
/* If the FDPIC needs an interpreter, then load it up too. */
|
|
|
|
if (ldso_path)
|
|
|
|
{
|
|
|
|
const char *ldso_full_path = concat (simulator_sysroot, ldso_path, NULL);
|
|
|
|
struct bfd *ldso_bfd;
|
|
|
|
|
|
|
|
ldso_bfd = bfd_openr (ldso_full_path, STATE_TARGET (sd));
|
|
|
|
if (!ldso_bfd)
|
|
|
|
{
|
|
|
|
sim_io_eprintf (sd, "bfin-sim: bfd open failed: %s\n", ldso_full_path);
|
|
|
|
goto static_fdpic;
|
|
|
|
}
|
|
|
|
if (!bfd_check_format (ldso_bfd, bfd_object))
|
|
|
|
sim_io_eprintf (sd, "bfin-sim: bfd format not valid: %s\n", ldso_full_path);
|
|
|
|
bfd_set_arch_info (ldso_bfd, STATE_ARCHITECTURE (sd));
|
|
|
|
|
|
|
|
if (!bfin_fdpic_load (sd, cpu, ldso_bfd, &sp, elf_addrs, &ldso_path))
|
|
|
|
sim_io_eprintf (sd, "bfin-sim: FDPIC ldso failed to load: %s\n", ldso_full_path);
|
|
|
|
if (ldso_path)
|
|
|
|
sim_io_eprintf (sd, "bfin-sim: FDPIC ldso (%s) needs an interpreter (%s) !?\n",
|
|
|
|
ldso_full_path, ldso_path);
|
|
|
|
|
|
|
|
ldso_loadmap = sp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
static_fdpic:
|
|
|
|
ldso_loadmap = 0;
|
|
|
|
|
|
|
|
/* Finally setup the registers required by the FDPIC ABI. */
|
|
|
|
SET_DREG (7, 0); /* Zero out FINI funcptr -- ldso will set this up. */
|
|
|
|
SET_PREG (0, exec_loadmap); /* Exec loadmap addr. */
|
|
|
|
SET_PREG (1, ldso_loadmap); /* Interp loadmap addr. */
|
|
|
|
SET_PREG (2, elf_addrs[5]); /* PT_DYNAMIC map addr. */
|
|
|
|
|
|
|
|
auxvt = 1;
|
|
|
|
SET_SPREG (sp);
|
|
|
|
skip_fdpic_init:
|
|
|
|
sim_pc_set (cpu, elf_addrs[0]);
|
|
|
|
|
|
|
|
/* Figure out how much storage the argv/env strings need. */
|
2016-01-03 14:40:46 +08:00
|
|
|
argc = countargv ((char **)argv);
|
2011-03-06 08:20:21 +08:00
|
|
|
if (argc == -1)
|
|
|
|
argc = 0;
|
|
|
|
argv_flat = argc; /* NUL bytes */
|
|
|
|
for (i = 0; i < argc; ++i)
|
|
|
|
argv_flat += strlen (argv[i]);
|
|
|
|
|
|
|
|
if (!env)
|
|
|
|
env = simple_env;
|
2016-01-03 14:40:46 +08:00
|
|
|
envc = countargv ((char **)env);
|
2011-03-06 08:20:21 +08:00
|
|
|
env_flat = envc; /* NUL bytes */
|
|
|
|
for (i = 0; i < envc; ++i)
|
|
|
|
env_flat += strlen (env[i]);
|
|
|
|
|
|
|
|
/* Push the Auxiliary Vector Table between argv/env and actual strings. */
|
2015-06-24 00:32:47 +08:00
|
|
|
sp_flat = sp = align_up (SPREG - argv_flat - env_flat - 4, 4);
|
2011-03-06 08:20:21 +08:00
|
|
|
if (auxvt)
|
|
|
|
{
|
|
|
|
# define AT_PUSH(at, val) \
|
|
|
|
auxvt_size += 8; \
|
|
|
|
sp -= 4; \
|
|
|
|
auxvt = (val); \
|
|
|
|
sim_write (sd, sp, (void *)&auxvt, 4); \
|
|
|
|
sp -= 4; \
|
|
|
|
auxvt = (at); \
|
|
|
|
sim_write (sd, sp, (void *)&auxvt, 4)
|
|
|
|
unsigned int egid = getegid (), gid = getgid ();
|
|
|
|
unsigned int euid = geteuid (), uid = getuid ();
|
2012-04-01 10:39:12 +08:00
|
|
|
bu32 auxvt_size = 0;
|
2011-03-06 08:20:21 +08:00
|
|
|
AT_PUSH (AT_NULL, 0);
|
|
|
|
AT_PUSH (AT_SECURE, egid != gid || euid != uid);
|
|
|
|
AT_PUSH (AT_EGID, egid);
|
|
|
|
AT_PUSH (AT_GID, gid);
|
|
|
|
AT_PUSH (AT_EUID, euid);
|
|
|
|
AT_PUSH (AT_UID, uid);
|
|
|
|
AT_PUSH (AT_ENTRY, elf_addrs[4]);
|
|
|
|
AT_PUSH (AT_FLAGS, 0);
|
|
|
|
AT_PUSH (AT_BASE, elf_addrs[3]);
|
|
|
|
AT_PUSH (AT_PHNUM, elf_addrs[2]);
|
|
|
|
AT_PUSH (AT_PHENT, sizeof (Elf32_External_Phdr));
|
|
|
|
AT_PUSH (AT_PHDR, elf_addrs[1]);
|
|
|
|
AT_PUSH (AT_CLKTCK, 100); /* XXX: This ever not 100 ? */
|
|
|
|
AT_PUSH (AT_PAGESZ, 4096);
|
|
|
|
AT_PUSH (AT_HWCAP, 0);
|
|
|
|
#undef AT_PUSH
|
|
|
|
}
|
|
|
|
SET_SPREG (sp);
|
|
|
|
|
|
|
|
/* Push the argc/argv/env after the auxvt. */
|
|
|
|
sp -= ((1 + argc + 1 + envc + 1) * 4);
|
|
|
|
SET_SPREG (sp);
|
|
|
|
|
|
|
|
/* First push the argc value. */
|
|
|
|
sim_write (sd, sp, (void *)&argc, 4);
|
|
|
|
sp += 4;
|
|
|
|
|
|
|
|
/* Then the actual argv strings so we know where to point argv[]. */
|
|
|
|
for (i = 0; i < argc; ++i)
|
|
|
|
{
|
|
|
|
unsigned len = strlen (argv[i]) + 1;
|
|
|
|
sim_write (sd, sp_flat, (void *)argv[i], len);
|
|
|
|
sim_write (sd, sp, (void *)&sp_flat, 4);
|
|
|
|
sp_flat += len;
|
|
|
|
sp += 4;
|
|
|
|
}
|
|
|
|
sim_write (sd, sp, null, 4);
|
|
|
|
sp += 4;
|
|
|
|
|
|
|
|
/* Then the actual env strings so we know where to point env[]. */
|
|
|
|
for (i = 0; i < envc; ++i)
|
|
|
|
{
|
|
|
|
unsigned len = strlen (env[i]) + 1;
|
|
|
|
sim_write (sd, sp_flat, (void *)env[i], len);
|
|
|
|
sim_write (sd, sp, (void *)&sp_flat, 4);
|
|
|
|
sp_flat += len;
|
|
|
|
sp += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set some callbacks. */
|
|
|
|
cb->syscall_map = cb_linux_syscall_map;
|
|
|
|
cb->errno_map = cb_linux_errno_map;
|
|
|
|
cb->open_map = cb_linux_open_map;
|
|
|
|
cb->signal_map = cb_linux_signal_map;
|
2011-07-02 05:53:03 +08:00
|
|
|
cb->stat_map = stat_map_32 = cb_linux_stat_map_32;
|
|
|
|
stat_map_64 = cb_linux_stat_map_64;
|
2011-03-06 08:20:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-01-03 14:51:44 +08:00
|
|
|
bfin_os_init (SIM_DESC sd, SIM_CPU *cpu, char * const *argv)
|
2011-03-06 08:20:21 +08:00
|
|
|
{
|
|
|
|
/* Pass the command line via a string in R0 like Linux expects. */
|
|
|
|
int i;
|
|
|
|
bu8 byte;
|
|
|
|
bu32 cmdline = BFIN_L1_SRAM_SCRATCH;
|
|
|
|
|
|
|
|
SET_DREG (0, cmdline);
|
|
|
|
if (argv && argv[0])
|
|
|
|
{
|
|
|
|
i = 1;
|
|
|
|
byte = ' ';
|
|
|
|
while (argv[i])
|
|
|
|
{
|
|
|
|
bu32 len = strlen (argv[i]);
|
|
|
|
sim_write (sd, cmdline, (void *)argv[i], len);
|
|
|
|
cmdline += len;
|
|
|
|
sim_write (sd, cmdline, &byte, 1);
|
|
|
|
++cmdline;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
byte = 0;
|
|
|
|
sim_write (sd, cmdline, &byte, 1);
|
|
|
|
}
|
|
|
|
|
2011-07-02 05:53:03 +08:00
|
|
|
static void
|
|
|
|
bfin_virtual_init (SIM_DESC sd, SIM_CPU *cpu)
|
|
|
|
{
|
|
|
|
host_callback *cb = STATE_CALLBACK (sd);
|
|
|
|
|
|
|
|
cb->stat_map = stat_map_32 = cb_libgloss_stat_map_32;
|
|
|
|
stat_map_64 = NULL;
|
|
|
|
}
|
|
|
|
|
2011-03-06 08:20:21 +08:00
|
|
|
SIM_RC
|
|
|
|
sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
|
2016-01-03 14:51:44 +08:00
|
|
|
char * const *argv, char * const *env)
|
2011-03-06 08:20:21 +08:00
|
|
|
{
|
|
|
|
SIM_CPU *cpu = STATE_CPU (sd, 0);
|
2021-11-16 12:04:10 +08:00
|
|
|
host_callback *cb = STATE_CALLBACK (sd);
|
2011-03-06 08:20:21 +08:00
|
|
|
SIM_ADDR addr;
|
|
|
|
|
|
|
|
/* Set the PC. */
|
|
|
|
if (abfd != NULL)
|
|
|
|
addr = bfd_get_start_address (abfd);
|
|
|
|
else
|
|
|
|
addr = 0;
|
|
|
|
sim_pc_set (cpu, addr);
|
|
|
|
|
2015-12-26 20:05:41 +08:00
|
|
|
/* Standalone mode (i.e. `run`) will take care of the argv for us in
|
|
|
|
sim_open() -> sim_parse_args(). But in debug mode (i.e. 'target sim'
|
|
|
|
with `gdb`), we need to handle it because the user can change the
|
|
|
|
argv on the fly via gdb's 'run'. */
|
|
|
|
if (STATE_PROG_ARGV (sd) != argv)
|
2011-03-06 08:20:21 +08:00
|
|
|
{
|
2011-06-19 01:20:38 +08:00
|
|
|
freeargv (STATE_PROG_ARGV (sd));
|
2011-03-06 08:20:21 +08:00
|
|
|
STATE_PROG_ARGV (sd) = dupargv (argv);
|
|
|
|
}
|
|
|
|
|
2021-11-16 12:00:04 +08:00
|
|
|
if (STATE_PROG_ENVP (sd) != env)
|
|
|
|
{
|
|
|
|
freeargv (STATE_PROG_ENVP (sd));
|
|
|
|
STATE_PROG_ENVP (sd) = dupargv (env);
|
|
|
|
}
|
|
|
|
|
2021-11-16 12:04:10 +08:00
|
|
|
cb->argv = STATE_PROG_ARGV (sd);
|
|
|
|
cb->envp = STATE_PROG_ENVP (sd);
|
|
|
|
|
2011-03-06 08:20:21 +08:00
|
|
|
switch (STATE_ENVIRONMENT (sd))
|
|
|
|
{
|
|
|
|
case USER_ENVIRONMENT:
|
2016-01-03 14:51:44 +08:00
|
|
|
bfin_user_init (sd, cpu, abfd, argv, env);
|
2011-03-06 08:20:21 +08:00
|
|
|
break;
|
|
|
|
case OPERATING_ENVIRONMENT:
|
2016-01-03 14:51:44 +08:00
|
|
|
bfin_os_init (sd, cpu, argv);
|
2011-03-06 08:20:21 +08:00
|
|
|
break;
|
|
|
|
default:
|
2011-07-02 05:53:03 +08:00
|
|
|
bfin_virtual_init (sd, cpu);
|
2011-03-06 08:20:21 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIM_RC_OK;
|
|
|
|
}
|