From e4b2a0b30c018bb6f566500113d6d496a0b1141c Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 6 Dec 2023 23:36:14 -0800 Subject: [PATCH] load_elf: copy linux's auxv, argv, and env layout --- src/openpower/decoder/isa/caller.py | 2 + src/openpower/decoder/isa/mem.py | 191 ++++++++++++++++++++++------ src/openpower/syscalls/ppc_flags.py | 1 + 3 files changed, 157 insertions(+), 37 deletions(-) diff --git a/src/openpower/decoder/isa/caller.py b/src/openpower/decoder/isa/caller.py index 44b0fd06..9bc051ee 100644 --- a/src/openpower/decoder/isa/caller.py +++ b/src/openpower/decoder/isa/caller.py @@ -2227,6 +2227,8 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop): # 2. Call the HDL implementation which invokes trap. # 3. Reroute the guest system call to host system call. # 4. Force return from the interrupt as if we had guest OS. + # FIXME: enable PPC_FEATURE2_SCV in mem.py DEFAULT_AT_HWCAP2 when + # scv emulation works. if ((asmop in ("sc", "scv")) and (self.syscall is not None) and not syscall_emu_active): diff --git a/src/openpower/decoder/isa/mem.py b/src/openpower/decoder/isa/mem.py index fc308cc8..74a43ca2 100644 --- a/src/openpower/decoder/isa/mem.py +++ b/src/openpower/decoder/isa/mem.py @@ -1105,8 +1105,57 @@ def raise_if_syscall_err(result): # TODO: change to much smaller size once GROWSDOWN is implemented DEFAULT_INIT_STACK_SZ = 4 << 20 - -def load_elf(mem, elf_file, args=(), env=(), stack_size=DEFAULT_INIT_STACK_SZ): +# TODO: power9 identifies PowerISA v3.0, figure out if it's best... +DEFAULT_AT_PLATFORM = "power9" # default value of AT_PLATFORM +DEFAULT_AT_BASE_PLATFORM = "power9" # default value of AT_BASE_PLATFORM +# TODO: use correct cache block sizes +DEFAULT_AT_DCACHEBSIZE = 128 # default value of AT_DCACHEBSIZE +DEFAULT_AT_ICACHEBSIZE = 128 # default value of AT_ICACHEBSIZE +DEFAULT_AT_UCACHEBSIZE = 0 # default value of AT_UCACHEBSIZE +DEFAULT_AT_L1I_CACHESIZE = 0x8000 # default value of AT_L1I_CACHESIZE +DEFAULT_AT_L1I_CACHEGEOMETRY = 0x80 # default value of AT_L1I_CACHEGEOMETRY +DEFAULT_AT_L1D_CACHESIZE = 0x8000 # default value of AT_L1D_CACHESIZE +DEFAULT_AT_L1D_CACHEGEOMETRY = 0x80 # default value of AT_L1D_CACHEGEOMETRY +DEFAULT_AT_L2_CACHESIZE = 0 # default value of AT_L2_CACHESIZE +DEFAULT_AT_L2_CACHEGEOMETRY = 0 # default value of AT_L2_CACHEGEOMETRY +DEFAULT_AT_L3_CACHESIZE = 0 # default value of AT_L3_CACHESIZE +DEFAULT_AT_L3_CACHEGEOMETRY = 0 # default value of AT_L3_CACHEGEOMETRY + +# default value of AT_HWCAP +DEFAULT_AT_HWCAP = (ppc_flags.PPC_FEATURE_32 | ppc_flags.PPC_FEATURE_64 | + ppc_flags.PPC_FEATURE_HAS_FPU | ppc_flags.PPC_FEATURE_HAS_MMU | + ppc_flags.PPC_FEATURE_ARCH_2_06 | ppc_flags.PPC_FEATURE_TRUE_LE) + +# default value of AT_HWCAP2 +DEFAULT_AT_HWCAP2 = (ppc_flags.PPC_FEATURE2_ARCH_2_07 | + ppc_flags.PPC_FEATURE2_HAS_ISEL | ppc_flags.PPC_FEATURE2_HAS_TAR | + ppc_flags.PPC_FEATURE2_ARCH_3_00 | ppc_flags.PPC_FEATURE2_DARN) + +# FIXME: enable when scv emulation works +# DEFAULT_AT_HWCAP2 |= ppc_flags.PPC_FEATURE2_SCV + +# FIXME: enable if/when v3.1 PO1 prefixed insns work +# DEFAULT_AT_HWCAP2 |= ppc_flags.PPC_FEATURE2_ARCH_3_1 + +CLOCKS_PER_SEC = 100 + + +def load_elf( + mem, elf_file, args=(), env=(), stack_size=DEFAULT_INIT_STACK_SZ, + platform=DEFAULT_AT_PLATFORM, base_platform=DEFAULT_AT_BASE_PLATFORM, + rand_byte16=None, dcachebsize=DEFAULT_AT_DCACHEBSIZE, + icachebsize=DEFAULT_AT_ICACHEBSIZE, ucachebsize=DEFAULT_AT_UCACHEBSIZE, + l1i_cachesize=DEFAULT_AT_L1I_CACHESIZE, + l1i_cachegeometry=DEFAULT_AT_L1I_CACHEGEOMETRY, + l1d_cachesize=DEFAULT_AT_L1D_CACHESIZE, + l1d_cachegeometry=DEFAULT_AT_L1D_CACHEGEOMETRY, + l2_cachesize=DEFAULT_AT_L2_CACHESIZE, + l2_cachegeometry=DEFAULT_AT_L2_CACHEGEOMETRY, + l3_cachesize=DEFAULT_AT_L3_CACHESIZE, + l3_cachegeometry=DEFAULT_AT_L3_CACHEGEOMETRY, + hwcap=DEFAULT_AT_HWCAP, hwcap2=DEFAULT_AT_HWCAP2, + was_setuid_like=False, execfd=None, +): if not isinstance(mem, MemMMap): raise TypeError("MemMMap required to load ELFs") if not isinstance(elf_file, ELFFile): @@ -1115,7 +1164,9 @@ def load_elf(mem, elf_file, args=(), env=(), stack_size=DEFAULT_INIT_STACK_SZ): raise NotImplementedError("dynamic binaries aren't implemented") fd = elf_file.stream.fileno() heap_start = -1 + phnum = 0 for segment in elf_file.iter_segments(): + phnum += 1 if segment.header['p_type'] in ('PT_DYNAMIC', 'PT_INTERP'): raise NotImplementedError("dynamic binaries aren't implemented") elif segment.header['p_type'] == 'PT_LOAD': @@ -1182,6 +1233,30 @@ def load_elf(mem, elf_file, args=(), env=(), stack_size=DEFAULT_INIT_STACK_SZ): stack_low, stack_size, prot, flags, fd=-1, offset=0, is_mmap2=False) raise_if_syscall_err(result) + def copy_to_stack(buf): + nonlocal stack_top + l = len(buf) + stack_top -= l + addr = stack_top + if l > 0: + mem.get_ctypes(addr, l, True)[:] = buf + return addr + + def copy_cstr_to_stack(s): + if s is None: + return None + if isinstance(s, str): + s = s.encode() + else: + s = bytes(s) + if b"\0" in s: + raise ValueError("c string can't contain NUL") + s += b"\0" + return copy_to_stack(s) + + stack_top -= 7 # weird, but matches linux + program_name = copy_cstr_to_stack(os.readlink("/proc/self/fd/%i" % fd)) + env_bytes = bytearray() env_offsets = [] for env_entry in env: @@ -1204,7 +1279,7 @@ def load_elf(mem, elf_file, args=(), env=(), stack_size=DEFAULT_INIT_STACK_SZ): args = tuple(args) if len(args) == 0: - args = ("program",) # glibc depends on argc != 0 + args = ("",) # glibc depends on argc != 0 args_bytes = bytearray() arg_offsets = [] for arg in args: @@ -1222,46 +1297,88 @@ def load_elf(mem, elf_file, args=(), env=(), stack_size=DEFAULT_INIT_STACK_SZ): args_bytes_addr = stack_top mem.get_ctypes(args_bytes_addr, len(args_bytes), True)[:] = args_bytes - stack_top -= stack_top % 8 # align stack top for auxv - - auxv_t = struct.Struct(" #include #include +#include """ if isinstance(compiler, str): compiler = [compiler] -- 2.30.2