#include <time.h>
#include "qemu.h"
-#include "disas.h"
+#include "disas/disas.h"
#ifdef _ARCH_PPC64
#undef ARCH_DLINFO
ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
};
-#define TARGET_HAS_GUEST_VALIDATE_BASE
-/* We want the opportunity to check the suggested base */
-bool guest_validate_base(unsigned long guest_base)
+#define TARGET_HAS_VALIDATE_GUEST_SPACE
+/* Return 1 if the proposed guest space is suitable for the guest.
+ * Return 0 if the proposed guest space isn't suitable, but another
+ * address space should be tried.
+ * Return -1 if there is no way the proposed guest space can be
+ * valid regardless of the base.
+ * The guest code may leave a page mapped and populate it if the
+ * address is suitable.
+ */
+static int validate_guest_space(unsigned long guest_base,
+ unsigned long guest_size)
{
unsigned long real_start, test_page_addr;
* commpage at 0xffff0fxx
*/
test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask);
+
+ /* If the commpage lies within the already allocated guest space,
+ * then there is no way we can allocate it.
+ */
+ if (test_page_addr >= guest_base
+ && test_page_addr <= (guest_base + guest_size)) {
+ return -1;
+ }
+
/* Note it needs to be writeable to let us initialise it */
real_start = (unsigned long)
mmap((void *)test_page_addr, qemu_host_page_size,
#endif /* TARGET_MICROBLAZE */
+#ifdef TARGET_OPENRISC
+
+#define ELF_START_MMAP 0x08000000
+
+#define elf_check_arch(x) ((x) == EM_OPENRISC)
+
+#define ELF_ARCH EM_OPENRISC
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
+
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
+{
+ regs->pc = infop->entry;
+ regs->gpr[1] = infop->start_stack;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 8192
+
+/* See linux kernel arch/openrisc/include/asm/elf.h. */
+#define ELF_NREG 34 /* gprs and pc, sr */
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+static void elf_core_copy_regs(target_elf_gregset_t *regs,
+ const CPUOpenRISCState *env)
+{
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ (*regs)[i] = tswapl(env->gpr[i]);
+ }
+
+ (*regs)[32] = tswapl(env->pc);
+ (*regs)[33] = tswapl(env->sr);
+}
+#define ELF_HWCAP 0
+#define ELF_PLATFORM NULL
+
+#endif /* TARGET_OPENRISC */
+
#ifdef TARGET_SH4
#define ELF_START_MMAP 0x80000000
return sp;
}
-#ifndef TARGET_HAS_GUEST_VALIDATE_BASE
+#ifndef TARGET_HAS_VALIDATE_GUEST_SPACE
/* If the guest doesn't have a validation function just agree */
-bool guest_validate_base(unsigned long guest_base)
+static int validate_guest_space(unsigned long guest_base,
+ unsigned long guest_size)
{
return 1;
}
#endif
+unsigned long init_guest_space(unsigned long host_start,
+ unsigned long host_size,
+ unsigned long guest_start,
+ bool fixed)
+{
+ unsigned long current_start, real_start;
+ int flags;
+
+ assert(host_start || host_size);
+
+ /* If just a starting address is given, then just verify that
+ * address. */
+ if (host_start && !host_size) {
+ if (validate_guest_space(host_start, host_size) == 1) {
+ return host_start;
+ } else {
+ return (unsigned long)-1;
+ }
+ }
+
+ /* Setup the initial flags and start address. */
+ current_start = host_start & qemu_host_page_mask;
+ flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
+ if (fixed) {
+ flags |= MAP_FIXED;
+ }
+
+ /* Otherwise, a non-zero size region of memory needs to be mapped
+ * and validated. */
+ while (1) {
+ unsigned long real_size = host_size;
+
+ /* Do not use mmap_find_vma here because that is limited to the
+ * guest address space. We are going to make the
+ * guest address space fit whatever we're given.
+ */
+ real_start = (unsigned long)
+ mmap((void *)current_start, host_size, PROT_NONE, flags, -1, 0);
+ if (real_start == (unsigned long)-1) {
+ return (unsigned long)-1;
+ }
+
+ /* Ensure the address is properly aligned. */
+ if (real_start & ~qemu_host_page_mask) {
+ munmap((void *)real_start, host_size);
+ real_size = host_size + qemu_host_page_size;
+ real_start = (unsigned long)
+ mmap((void *)real_start, real_size, PROT_NONE, flags, -1, 0);
+ if (real_start == (unsigned long)-1) {
+ return (unsigned long)-1;
+ }
+ real_start = HOST_PAGE_ALIGN(real_start);
+ }
+
+ /* Check to see if the address is valid. */
+ if (!host_start || real_start == current_start) {
+ int valid = validate_guest_space(real_start - guest_start,
+ real_size);
+ if (valid == 1) {
+ break;
+ } else if (valid == -1) {
+ return (unsigned long)-1;
+ }
+ /* valid == 0, so try again. */
+ }
+
+ /* That address didn't work. Unmap and try a different one.
+ * The address the host picked because is typically right at
+ * the top of the host address space and leaves the guest with
+ * no usable address space. Resort to a linear search. We
+ * already compensated for mmap_min_addr, so this should not
+ * happen often. Probably means we got unlucky and host
+ * address space randomization put a shared library somewhere
+ * inconvenient.
+ */
+ munmap((void *)real_start, host_size);
+ current_start += qemu_host_page_size;
+ if (host_start == current_start) {
+ /* Theoretically possible if host doesn't have any suitably
+ * aligned areas. Normally the first mmap will fail.
+ */
+ return (unsigned long)-1;
+ }
+ }
+
+ qemu_log("Reserved 0x%lx bytes of guest address space\n", host_size);
+
+ return real_start;
+}
+
static void probe_guest_base(const char *image_name,
abi_ulong loaddr, abi_ulong hiaddr)
{
}
}
host_size = hiaddr - loaddr;
- while (1) {
- /* Do not use mmap_find_vma here because that is limited to the
- guest address space. We are going to make the
- guest address space fit whatever we're given. */
- real_start = (unsigned long)
- mmap((void *)host_start, host_size, PROT_NONE,
- MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
- if (real_start == (unsigned long)-1) {
- goto exit_perror;
- }
- guest_base = real_start - loaddr;
- if ((real_start == host_start) &&
- guest_validate_base(guest_base)) {
- break;
- }
- /* That address didn't work. Unmap and try a different one.
- The address the host picked because is typically right at
- the top of the host address space and leaves the guest with
- no usable address space. Resort to a linear search. We
- already compensated for mmap_min_addr, so this should not
- happen often. Probably means we got unlucky and host
- address space randomization put a shared library somewhere
- inconvenient. */
- munmap((void *)real_start, host_size);
- host_start += qemu_host_page_size;
- if (host_start == loaddr) {
- /* Theoretically possible if host doesn't have any suitably
- aligned areas. Normally the first mmap will fail. */
- errmsg = "Unable to find space for application";
- goto exit_errmsg;
- }
+
+ /* Setup the initial guest memory space with ranges gleaned from
+ * the ELF image that is being loaded.
+ */
+ real_start = init_guest_space(host_start, host_size, loaddr, false);
+ if (real_start == (unsigned long)-1) {
+ errmsg = "Unable to find space for application";
+ goto exit_errmsg;
}
+ guest_base = real_start - loaddr;
+
qemu_log("Relocating guest address space from 0x"
TARGET_ABI_FMT_lx " to 0x%lx\n",
loaddr, real_start);
}
return;
-exit_perror:
- errmsg = strerror(errno);
exit_errmsg:
fprintf(stderr, "%s: %s\n", image_name, errmsg);
exit(-1);
static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
{
- char *filename, *base_filename;
+ char *base_filename;
unsigned int i, len;
(void) memset(psinfo, 0, sizeof (*psinfo));
psinfo->pr_uid = getuid();
psinfo->pr_gid = getgid();
- filename = strdup(ts->bprm->filename);
- base_filename = strdup(basename(filename));
+ base_filename = g_path_get_basename(ts->bprm->filename);
+ /*
+ * Using strncpy here is fine: at max-length,
+ * this field is not NUL-terminated.
+ */
(void) strncpy(psinfo->pr_fname, base_filename,
sizeof(psinfo->pr_fname));
- free(base_filename);
- free(filename);
+ g_free(base_filename);
bswap_psinfo(psinfo);
return (0);
}