diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/Makefile.objs b/xnu-qemu-arm64-5.1.0/hw/arm/Makefile.objs index 534a6a1..3cd9b77 100644 --- a/xnu-qemu-arm64-5.1.0/hw/arm/Makefile.objs +++ b/xnu-qemu-arm64-5.1.0/hw/arm/Makefile.objs @@ -1,4 +1,4 @@ -obj-y += boot.o +obj-y += boot.o xnu_fb_cfg.o xnu_trampoline_hook.o xnu_pagetable.o xnu_cpacr.o xnu_dtb.o xnu_file_mmio_dev.o xnu_mem.o xnu.o j273_macos11.o guest-services.o guest-socket.o guest-fds.o guest-file.o obj-$(CONFIG_PLATFORM_BUS) += sysbus-fdt.o obj-$(CONFIG_ARM_VIRT) += virt.o obj-$(CONFIG_ACPI) += virt-acpi-build.o diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/guest-fds.c b/xnu-qemu-arm64-5.1.0/hw/arm/guest-fds.c new file mode 100644 index 0000000..f109443 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/guest-fds.c @@ -0,0 +1,72 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "hw/arm/guest-services/fds.h" +#include "cpu.h" + +int32_t guest_svcs_fds[MAX_FD_COUNT] = { [0 ... MAX_FD_COUNT-1] = -1 }; + +int32_t qc_handle_close(CPUState *cpu, int32_t fd) +{ + VERIFY_FD(fd); + + int retval = -1; + + if ((retval = close(guest_svcs_fds[fd])) < 0) { + guest_svcs_errno = errno; + } else { + // TODO: should this be in the "else" clause, or performed regardless? + guest_svcs_fds[fd] = -1; + } + + return retval; +} + +int32_t qc_handle_fcntl_getfl(CPUState *cpu, int32_t fd) +{ + VERIFY_FD(fd); + + int retval = -1; + + if ((retval = fcntl(guest_svcs_fds[fd], F_GETFL)) < 0) { + guest_svcs_errno = errno; + } + + return retval; +} + +int32_t qc_handle_fcntl_setfl(CPUState *cpu, int32_t fd, int32_t flags) +{ + VERIFY_FD(fd); + + int retval = -1; + + if ((retval = fcntl(guest_svcs_fds[fd], F_SETFL, flags)) < 0) { + guest_svcs_errno = errno; + } + + return retval; +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/guest-file.c b/xnu-qemu-arm64-5.1.0/hw/arm/guest-file.c new file mode 100644 index 0000000..f9f4709 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/guest-file.c @@ -0,0 +1,111 @@ +/* + * QEMU Host file guest access + * + * Copyright (c) 2020 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/arm/guest-services/file.h" +#include "cpu.h" + +static int32_t file_fds[MAX_FILE_FDS] = { [0 ... MAX_FILE_FDS-1] = -1 }; + +void qc_file_open(uint64_t index, const char *filename) +{ + if (index >= MAX_FILE_FDS) { + abort(); + } + if (-1 != file_fds[index]) { + abort(); + } + file_fds[index] = open(filename, O_RDWR); + if (-1 == file_fds[index]) { + abort(); + } +} + +int64_t qc_handle_write_file(CPUState *cpu, uint64_t buffer_guest_ptr, + uint64_t length, uint64_t offset, uint64_t index) +{ + uint8_t buf[MAX_FILE_TRANSACTION_LEN]; + + if (index >= MAX_FILE_FDS) { + abort(); + } + int fd = file_fds[index]; + if (-1 == fd) { + abort(); + } + if (offset != lseek(fd, offset, SEEK_SET)) { + abort(); + } + if (length > MAX_FILE_TRANSACTION_LEN) { + abort(); + } + cpu_memory_rw_debug(cpu, buffer_guest_ptr, &buf[0], length, 0); + if (length != write(fd, &buf[0], length)) { + abort(); + } + + return 0; +} + +int64_t qc_handle_read_file(CPUState *cpu, uint64_t buffer_guest_ptr, + uint64_t length, uint64_t offset, uint64_t index) +{ + uint8_t buf[MAX_FILE_TRANSACTION_LEN]; + if (index >= MAX_FILE_FDS) { + abort(); + } + int fd = file_fds[index]; + if (-1 == fd) { + abort(); + } + if (offset != lseek(fd, offset, SEEK_SET)) { + abort(); + } + if (length > MAX_FILE_TRANSACTION_LEN) { + abort(); + } + if (length != read(fd, &buf[0], length)) { + abort(); + } + cpu_memory_rw_debug(cpu, buffer_guest_ptr, &buf[0], length, 1); + + return 0; +} + +int64_t qc_handle_size_file(uint64_t index) +{ + struct stat st; + + if (index >= MAX_FILE_FDS) { + abort(); + } + int fd = file_fds[index]; + if (-1 == fd) { + abort(); + } + if (-1 == fstat(fd, &st)) { + abort(); + } + + return st.st_size; +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/guest-services.c b/xnu-qemu-arm64-5.1.0/hw/arm/guest-services.c new file mode 100644 index 0000000..fed1a7e --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/guest-services.c @@ -0,0 +1,185 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "exec/address-spaces.h" +#include "hw/misc/unimp.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/platform-bus.h" + +#include "hw/arm/j273_macos11.h" +#include "hw/arm/guest-services/general.h" +#include "hw/arm/xnu_trampoline_hook.h" + +int32_t guest_svcs_errno = 0; + +uint64_t qemu_call_status(CPUARMState *env, const ARMCPRegInfo *ri) +{ + // NOT USED FOR NOW + return 0; +} + +void qemu_call(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +{ + CPUState *cpu = qemu_get_cpu(0); + qemu_call_t qcall; + uint64_t i = 0; + + static uint8_t hooks_installed = false; + + if (!value) { + // Special case: not a regular QEMU call. This is used by our + // kernel task port patch to notify of the readiness for the + // hook installation. + + J273MachineState *nms = J273_MACHINE(qdev_get_machine()); + KernelTrHookParams *hook = &nms->hook; + + if (0 != hook->va) { + //install the hook here because we need the MMU to be already + //configured and all the memory mapped before installing the hook + xnu_hook_tr_copy_install(hook->va, hook->pa, hook->buf_va, + hook->buf_pa, hook->code, hook->code_size, + hook->buf_size, hook->scratch_reg); + + } + + if (!hooks_installed) { + for (i = 0; i < nms->hook_funcs_count; i++) { + xnu_hook_tr_copy_install(nms->hook_funcs[i].va, + nms->hook_funcs[i].pa, + nms->hook_funcs[i].buf_va, + nms->hook_funcs[i].buf_pa, + nms->hook_funcs[i].code, + nms->hook_funcs[i].code_size, + nms->hook_funcs[i].buf_size, + nms->hook_funcs[i].scratch_reg); + } + hooks_installed = true; + } + + //emulate original opcode: str x19, [x20] + value = env->xregs[19]; + cpu_memory_rw_debug(cpu, env->xregs[20], (uint8_t*) &value, + sizeof(value), 1); + ////emulate original opcode: str x20, [x23] + //value = env->xregs[20]; + //cpu_memory_rw_debug(cpu, env->xregs[23], (uint8_t*) &value, + // sizeof(value), 1); + + return; + } + + // Read the request + cpu_memory_rw_debug(cpu, value, (uint8_t*) &qcall, sizeof(qcall), 0); + + switch (qcall.call_number) { + // File Descriptors + case QC_CLOSE: + qcall.retval = qc_handle_close(cpu, qcall.args.close.fd); + break; + case QC_FCNTL: + switch (qcall.args.fcntl.cmd) { + case F_GETFL: + qcall.retval = qc_handle_fcntl_getfl( + cpu, qcall.args.fcntl.fd); + break; + case F_SETFL: + qcall.retval = qc_handle_fcntl_setfl( + cpu, qcall.args.fcntl.fd, qcall.args.fcntl.flags); + break; + default: + guest_svcs_errno = EINVAL; + qcall.retval = -1; + } + break; + + // Socket API + case QC_SOCKET: + qcall.retval = qc_handle_socket(cpu, qcall.args.socket.domain, + qcall.args.socket.type, + qcall.args.socket.protocol); + break; + case QC_ACCEPT: + qcall.retval = qc_handle_accept(cpu, qcall.args.accept.socket, + qcall.args.accept.addr, + qcall.args.accept.addrlen); + break; + case QC_BIND: + qcall.retval = qc_handle_bind(cpu, qcall.args.bind.socket, + qcall.args.bind.addr, + qcall.args.bind.addrlen); + break; + case QC_CONNECT: + qcall.retval = qc_handle_connect(cpu, qcall.args.connect.socket, + qcall.args.connect.addr, + qcall.args.connect.addrlen); + break; + case QC_LISTEN: + qcall.retval = qc_handle_listen(cpu, qcall.args.listen.socket, + qcall.args.listen.backlog); + break; + case QC_RECV: + qcall.retval = qc_handle_recv(cpu, qcall.args.recv.socket, + qcall.args.recv.buffer, + qcall.args.recv.length, + qcall.args.recv.flags); + break; + case QC_SEND: + qcall.retval = qc_handle_send(cpu, qcall.args.send.socket, + qcall.args.send.buffer, + qcall.args.send.length, + qcall.args.send.flags); + break; + case QC_WRITE_FILE: + qcall.retval = qc_handle_write_file(cpu, + qcall.args.write_file.buffer_guest_ptr, + qcall.args.write_file.length, + qcall.args.write_file.offset, + qcall.args.write_file.index); + break; + case QC_READ_FILE: + qcall.retval = qc_handle_read_file(cpu, + qcall.args.read_file.buffer_guest_ptr, + qcall.args.read_file.length, + qcall.args.read_file.offset, + qcall.args.read_file.index); + break; + case QC_SIZE_FILE: + qcall.retval = qc_handle_size_file(qcall.args.size_file.index); + break; + default: + // TODO: handle unknown call numbers + break; + } + + qcall.error = guest_svcs_errno; + + // Write the response + cpu_memory_rw_debug(cpu, value, (uint8_t*) &qcall, sizeof(qcall), 1); +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/guest-socket.c b/xnu-qemu-arm64-5.1.0/hw/arm/guest-socket.c new file mode 100644 index 0000000..fdf9d1e --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/guest-socket.c @@ -0,0 +1,192 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/arm/guest-services/socket.h" +#include "hw/arm/guest-services/fds.h" +#include "sys/socket.h" +#include "cpu.h" + +#define SOCKET_TIMEOUT_USECS (10) + +static int32_t find_free_socket(void) { + for (int i = 0; i < MAX_FD_COUNT; ++i) { + if (-1 == guest_svcs_fds[i]) { + return i; + } + } + + guest_svcs_errno = ENOMEM; + return -1; +} + +int32_t qc_handle_socket(CPUState *cpu, int32_t domain, int32_t type, + int32_t protocol) +{ + int retval = find_free_socket(); + + if (retval < 0) { + guest_svcs_errno = ENOTSOCK; + } else if ((guest_svcs_fds[retval] = socket(domain, type, protocol)) < 0) { + retval = -1; + guest_svcs_errno = errno; + } + + return retval; +} + +int32_t qc_handle_accept(CPUState *cpu, int32_t sckt, struct sockaddr *g_addr, + socklen_t *g_addrlen) +{ + struct sockaddr_in addr; + socklen_t addrlen; + + VERIFY_FD(sckt); + + int retval = find_free_socket(); + + // TODO: timeout + if (retval < 0) { + guest_svcs_errno = ENOTSOCK; + } else if ((guest_svcs_fds[retval] = accept(guest_svcs_fds[sckt], + (struct sockaddr *) &addr, + &addrlen)) < 0) { + retval = -1; + guest_svcs_errno = errno; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 1); + cpu_memory_rw_debug(cpu, (target_ulong) g_addrlen, + (uint8_t*) &addrlen, sizeof(addrlen), 1); + } + + return retval; +} + +int32_t qc_handle_bind(CPUState *cpu, int32_t sckt, struct sockaddr *g_addr, + socklen_t addrlen) +{ + struct sockaddr_in addr; + + VERIFY_FD(sckt); + + int retval = 0; + + if (addrlen > sizeof(addr)) { + guest_svcs_errno = ENOMEM; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 0); + + if ((retval = bind(guest_svcs_fds[sckt], (struct sockaddr *) &addr, + addrlen)) < 0) { + guest_svcs_errno = errno; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 1); + } + } + + return retval; +} + +int32_t qc_handle_connect(CPUState *cpu, int32_t sckt, struct sockaddr *g_addr, + socklen_t addrlen) +{ + struct sockaddr_in addr; + + VERIFY_FD(sckt); + + int retval = 0; + + if (addrlen > sizeof(addr)) { + guest_svcs_errno = ENOMEM; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 0); + + if ((retval = connect(guest_svcs_fds[sckt], (struct sockaddr *) &addr, + addrlen)) < 0) { + guest_svcs_errno = errno; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 1); + } + } + + return retval; +} + +int32_t qc_handle_listen(CPUState *cpu, int32_t sckt, int32_t backlog) +{ + VERIFY_FD(sckt); + + int retval = 0; + + if ((retval = listen(guest_svcs_fds[sckt], backlog)) < 0) { + guest_svcs_errno = errno; + } + + return retval; +} + +int32_t qc_handle_recv(CPUState *cpu, int32_t sckt, void *g_buffer, + size_t length, int32_t flags) +{ + VERIFY_FD(sckt); + uint8_t buffer[MAX_BUF_SIZE]; + + int retval = -1; + + // TODO: timeout + if (length > MAX_BUF_SIZE) { + guest_svcs_errno = ENOMEM; + } else if ((retval = recv(guest_svcs_fds[sckt], buffer, length, flags)) <= 0) { + guest_svcs_errno = errno; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_buffer, buffer, retval, 1); + } + + return retval; +} + +int32_t qc_handle_send(CPUState *cpu, int32_t sckt, void *g_buffer, + size_t length, int32_t flags) +{ + VERIFY_FD(sckt); + uint8_t buffer[MAX_BUF_SIZE]; + + int retval = -1; + + if (length > MAX_BUF_SIZE) { + guest_svcs_errno = ENOMEM; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_buffer, buffer, length, 0); + + if ((retval = send(guest_svcs_fds[sckt], buffer, length, flags)) < 0) { + guest_svcs_errno = errno; + } + } + + return retval; +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/j273_macos11.c b/xnu-qemu-arm64-5.1.0/hw/arm/j273_macos11.c new file mode 100644 index 0000000..6cda40a --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/j273_macos11.c @@ -0,0 +1,997 @@ +/* + * macOS 11 Big Sur - j273 - A12Z + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "exec/address-spaces.h" +#include "hw/misc/unimp.h" +#include "sysemu/sysemu.h" +#include "sysemu/reset.h" +#include "qemu/error-report.h" +#include "hw/platform-bus.h" + +#include "hw/arm/j273_macos11.h" + +#include "hw/arm/exynos4210.h" +#include "hw/arm/guest-services/general.h" + +#define J273_SECURE_RAM_SIZE (0x100000) +#define J273_PHYS_BASE (0x40000000) + +//compiled nop instruction: mov x0, x0 +#define NOP_INST (0xaa0003e0) +#define RET_INST (0xd65f03c0) // *NEW* +#define MOV_W0_01_INST (0x52800020) +#define CMP_X9_x9_INST (0xeb09013f) +//compiled instruction: mov w7, #0 +#define W7_ZERO_INST (0x52800007) +#define W10_ZERO_INST (0x5280000a) +#define W23_ZERO_INST (0x52800017) +#define ORR_X0_2_INST (0xb27f0000) // *NEW* + +//hook the kernel to execute our "driver" code in this function +//after things are already running in the kernel but the root mount is not +//yet mounted. +//We chose this place in the beginning of ubc_init() inlined in bsd_init() +//because enough things are up and running for our driver to properly setup, +//This means that global IOKIT locks and dictionaries are already initialized +//and in general, the IOKIT system is already initialized. +//We are now able to initialize our driver and attach it to an existing +//IOReg object. +//On the other hand, no mounting of any FS happened yet so we have a chance +//for our block device driver to present a new block device that will be +//mounted on the root mount. +//We need to choose the hook location carefully. +//We need 3 instructions in a row that we overwrite that are not location +//dependant (such as adr, adrp and branching) as we are going to execute +//them elsewhere. +//We also need a register to use as a scratch register that its value is +//disregarded right after the hook and does not affect anything. +#define UBC_INIT_VADDR_16B92 (0xfffffff0073dec10) + +#define J273_CPREG_FUNCS(name) \ +static uint64_t j273_cpreg_read_##name(CPUARMState *env, \ + const ARMCPRegInfo *ri) \ +{ \ + J273MachineState *nms = (J273MachineState *)ri->opaque; \ + return nms->J273_CPREG_VAR_NAME(name); \ +} \ +static void j273_cpreg_write_##name(CPUARMState *env, const ARMCPRegInfo *ri, \ + uint64_t value) \ +{ \ + J273MachineState *nms = (J273MachineState *)ri->opaque; \ + nms->J273_CPREG_VAR_NAME(name) = value; \ +} + +#define J273_CPREG_DEF(p_name, p_op0, p_op1, p_crn, p_crm, p_op2, p_access) \ + { .cp = CP_REG_ARM64_SYSREG_CP, \ + .name = #p_name, .opc0 = p_op0, .crn = p_crn, .crm = p_crm, \ + .opc1 = p_op1, .opc2 = p_op2, .access = p_access, .type = ARM_CP_IO, \ + .state = ARM_CP_STATE_AA64, .readfn = j273_cpreg_read_##p_name, \ + .writefn = j273_cpreg_write_##p_name } + +#define ENABLE_EL2_REGS + +J273_CPREG_FUNCS(ARM64_REG_EHID1) +J273_CPREG_FUNCS(ARM64_REG_EHID10) +J273_CPREG_FUNCS(ARM64_REG_EHID4) +J273_CPREG_FUNCS(ARM64_REG_HID11) +J273_CPREG_FUNCS(ARM64_REG_HID3) +J273_CPREG_FUNCS(ARM64_REG_HID5) +J273_CPREG_FUNCS(ARM64_REG_HID4) +J273_CPREG_FUNCS(ARM64_REG_HID8) +J273_CPREG_FUNCS(ARM64_REG_HID7) +J273_CPREG_FUNCS(ARM64_REG_LSU_ERR_STS) +J273_CPREG_FUNCS(PMC0) +J273_CPREG_FUNCS(PMC1) +J273_CPREG_FUNCS(PMCR1) +J273_CPREG_FUNCS(PMSR) +J273_CPREG_FUNCS(L2ACTLR_EL1) +#ifdef ENABLE_EL2_REGS +J273_CPREG_FUNCS(ARM64_REG_MIGSTS_EL1); +J273_CPREG_FUNCS(ARM64_REG_KERNELKEYLO_EL1); +J273_CPREG_FUNCS(ARM64_REG_KERNELKEYHI_EL1); +J273_CPREG_FUNCS(ARM64_REG_VMSA_LOCK_EL1); +J273_CPREG_FUNCS(APRR_EL0); +J273_CPREG_FUNCS(APRR_EL1); +J273_CPREG_FUNCS(CTRR_LOCK); +J273_CPREG_FUNCS(CTRR_A_LWR_EL1); +J273_CPREG_FUNCS(CTRR_A_UPR_EL1); +J273_CPREG_FUNCS(CTRR_CTL_EL1); +J273_CPREG_FUNCS(APRR_MASK_EN_EL1); +J273_CPREG_FUNCS(APRR_MASK_EL0); +J273_CPREG_FUNCS(ACC_CTRR_A_LWR_EL2); +J273_CPREG_FUNCS(ACC_CTRR_A_UPR_EL2); +J273_CPREG_FUNCS(ACC_CTRR_CTL_EL2); +J273_CPREG_FUNCS(ACC_CTRR_LOCK_EL2); +J273_CPREG_FUNCS(ARM64_REG_CYC_CFG); +J273_CPREG_FUNCS(ARM64_REG_CYC_OVRD); +J273_CPREG_FUNCS(IPI_SR); +J273_CPREG_FUNCS(UPMCR0); +J273_CPREG_FUNCS(UPMPCM); +#endif + +static const ARMCPRegInfo j273_cp_reginfo_kvm[] = { + // Apple-specific registers + J273_CPREG_DEF(ARM64_REG_EHID1, 3, 0, 15, 3, 1, PL1_RW), + J273_CPREG_DEF(ARM64_REG_EHID10, 3, 0, 15, 10, 1, PL1_RW), + J273_CPREG_DEF(ARM64_REG_EHID4, 3, 0, 15, 4, 1, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID11, 3, 0, 15, 13, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID3, 3, 0, 15, 3, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID4, 3, 0, 15, 4, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID5, 3, 0, 15, 5, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID7, 3, 0, 15, 7, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID8, 3, 0, 15, 8, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_LSU_ERR_STS, 3, 3, 15, 0, 0, PL1_RW), + J273_CPREG_DEF(PMC0, 3, 2, 15, 0, 0, PL1_RW), + J273_CPREG_DEF(PMC1, 3, 2, 15, 1, 0, PL1_RW), + J273_CPREG_DEF(PMCR1, 3, 1, 15, 1, 0, PL1_RW), + J273_CPREG_DEF(PMSR, 3, 1, 15, 13, 0, PL1_RW), + J273_CPREG_DEF(L2ACTLR_EL1, 3, 1, 15, 0, 0, PL1_RW), +#ifdef ENABLE_EL2_REGS + J273_CPREG_DEF(ARM64_REG_MIGSTS_EL1, 3, 4, 15, 0, 4, PL1_RW), + J273_CPREG_DEF(ARM64_REG_KERNELKEYLO_EL1, 3, 4, 15, 1, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_KERNELKEYHI_EL1, 3, 4, 15, 1, 1, PL1_RW), + J273_CPREG_DEF(ARM64_REG_VMSA_LOCK_EL1, 3, 4, 15, 1, 2, PL1_RW), + J273_CPREG_DEF(APRR_EL0, 3, 4, 15, 2, 0, PL1_RW), + J273_CPREG_DEF(APRR_EL1, 3, 4, 15, 2, 1, PL1_RW), + J273_CPREG_DEF(CTRR_LOCK, 3, 4, 15, 2, 2, PL1_RW), + J273_CPREG_DEF(CTRR_A_LWR_EL1, 3, 4, 15, 2, 3, PL1_RW), + J273_CPREG_DEF(CTRR_A_UPR_EL1, 3, 4, 15, 2, 4, PL1_RW), + J273_CPREG_DEF(CTRR_CTL_EL1, 3, 4, 15, 2, 5, PL1_RW), + J273_CPREG_DEF(APRR_MASK_EN_EL1, 3, 4, 15, 2, 6, PL1_RW), + J273_CPREG_DEF(APRR_MASK_EL0, 3, 4, 15, 2, 7, PL1_RW), + J273_CPREG_DEF(ACC_CTRR_A_LWR_EL2, 3, 4, 15, 11, 0, PL1_RW), + J273_CPREG_DEF(ACC_CTRR_A_UPR_EL2, 3, 4, 15, 11, 1, PL1_RW), + J273_CPREG_DEF(ACC_CTRR_CTL_EL2, 3, 4, 15, 11, 4, PL1_RW), + J273_CPREG_DEF(ACC_CTRR_LOCK_EL2, 3, 4, 15, 11, 5, PL1_RW), + J273_CPREG_DEF(ARM64_REG_CYC_CFG, 3, 5, 15, 4, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_CYC_OVRD, 3, 5, 15, 5, 0, PL1_RW), + J273_CPREG_DEF(IPI_SR, 3, 5, 15, 1, 1, PL1_RW), + J273_CPREG_DEF(UPMCR0, 3, 7, 15, 0, 4, PL1_RW), + J273_CPREG_DEF(UPMPCM, 3, 7, 15, 5, 4, PL1_RW), +#endif + + // Aleph-specific registers for communicating with QEMU + + // REG_QEMU_CALL: + { .cp = CP_REG_ARM64_SYSREG_CP, .name = "REG_QEMU_CALL", + .opc0 = 3, .opc1 = 3, .crn = 15, .crm = 15, .opc2 = 0, + .access = PL0_RW, .type = ARM_CP_IO, .state = ARM_CP_STATE_AA64, + .readfn = qemu_call_status, + .writefn = qemu_call }, + + REGINFO_SENTINEL, +}; + +// This is the same as the array for kvm, but without +// the L2ACTLR_EL1, which is already defined in TCG. +// Duplicating this list isn't a perfect solution, +// but it's quick and reliable. +static const ARMCPRegInfo j273_cp_reginfo_tcg[] = { + // Apple-specific registers + J273_CPREG_DEF(ARM64_REG_EHID1, 3, 0, 15, 3, 1, PL1_RW), + J273_CPREG_DEF(ARM64_REG_EHID10, 3, 0, 15, 10, 1, PL1_RW), + J273_CPREG_DEF(ARM64_REG_EHID4, 3, 0, 15, 4, 1, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID11, 3, 0, 15, 13, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID3, 3, 0, 15, 3, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID5, 3, 0, 15, 5, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID4, 3, 0, 15, 4, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID8, 3, 0, 15, 8, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_HID7, 3, 0, 15, 7, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_LSU_ERR_STS, 3, 3, 15, 0, 0, PL1_RW), + J273_CPREG_DEF(PMC0, 3, 2, 15, 0, 0, PL1_RW), + J273_CPREG_DEF(PMC1, 3, 2, 15, 1, 0, PL1_RW), + J273_CPREG_DEF(PMCR1, 3, 1, 15, 1, 0, PL1_RW), + J273_CPREG_DEF(PMSR, 3, 1, 15, 13, 0, PL1_RW), +#ifdef ENABLE_EL2_REGS + J273_CPREG_DEF(ARM64_REG_MIGSTS_EL1, 3, 4, 15, 0, 4, PL1_RW), + J273_CPREG_DEF(ARM64_REG_KERNELKEYLO_EL1, 3, 4, 15, 1, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_KERNELKEYHI_EL1, 3, 4, 15, 1, 1, PL1_RW), + J273_CPREG_DEF(ARM64_REG_VMSA_LOCK_EL1, 3, 4, 15, 1, 2, PL1_RW), + J273_CPREG_DEF(APRR_EL0, 3, 4, 15, 2, 0, PL1_RW), + J273_CPREG_DEF(APRR_EL1, 3, 4, 15, 2, 1, PL1_RW), + J273_CPREG_DEF(CTRR_LOCK, 3, 4, 15, 2, 2, PL1_RW), + J273_CPREG_DEF(CTRR_A_LWR_EL1, 3, 4, 15, 2, 3, PL1_RW), + J273_CPREG_DEF(CTRR_A_UPR_EL1, 3, 4, 15, 2, 4, PL1_RW), + J273_CPREG_DEF(CTRR_CTL_EL1, 3, 4, 15, 2, 5, PL1_RW), + J273_CPREG_DEF(APRR_MASK_EN_EL1, 3, 4, 15, 2, 6, PL1_RW), + J273_CPREG_DEF(APRR_MASK_EL0, 3, 4, 15, 2, 7, PL1_RW), + J273_CPREG_DEF(ACC_CTRR_A_LWR_EL2, 3, 4, 15, 11, 0, PL1_RW), + J273_CPREG_DEF(ACC_CTRR_A_UPR_EL2, 3, 4, 15, 11, 1, PL1_RW), + J273_CPREG_DEF(ACC_CTRR_CTL_EL2, 3, 4, 15, 11, 4, PL1_RW), + J273_CPREG_DEF(ACC_CTRR_LOCK_EL2, 3, 4, 15, 11, 5, PL1_RW), + J273_CPREG_DEF(ARM64_REG_CYC_CFG, 3, 5, 15, 4, 0, PL1_RW), + J273_CPREG_DEF(ARM64_REG_CYC_OVRD, 3, 5, 15, 5, 0, PL1_RW), + J273_CPREG_DEF(IPI_SR, 3, 5, 15, 1, 1, PL1_RW), + J273_CPREG_DEF(UPMCR0, 3, 7, 15, 0, 4, PL1_RW), + J273_CPREG_DEF(UPMPCM, 3, 7, 15, 5, 4, PL1_RW), +#endif + + // Aleph-specific registers for communicating with QEMU + + // REG_QEMU_CALL: + { .cp = CP_REG_ARM64_SYSREG_CP, .name = "REG_QEMU_CALL", + .opc0 = 3, .opc1 = 3, .crn = 15, .crm = 15, .opc2 = 0, + .access = PL0_RW, .type = ARM_CP_IO, .state = ARM_CP_STATE_AA64, + .readfn = qemu_call_status, + .writefn = qemu_call }, + + REGINFO_SENTINEL, +}; + +static uint32_t g_nop_inst = NOP_INST; +static uint32_t g_ret_inst = RET_INST; +static uint32_t g_mov_w0_01_inst = MOV_W0_01_INST; +static uint32_t g_compare_true_inst = CMP_X9_x9_INST; +static uint32_t g_w7_zero_inst = W7_ZERO_INST; +static uint32_t g_w10_zero_inst = W10_ZERO_INST; +static uint32_t g_w23_zero_inst = W23_ZERO_INST; +static uint32_t g_orr_x0_2_inst = ORR_X0_2_INST; +static uint32_t g_set_cpacr_and_branch_inst[] = { + // 91400c21 add x1, x1, 3, lsl 12 # x1 = x1 + 0x3000 + // d378dc21 lsl x1, x1, 8 # x1 = x1 * 0x100 (x1 = 0x300000) + // d5181041 msr cpacr_el1, x1 # cpacr_el1 = x1 (enable FP) + // d2800041 mov x1, #2 + // d51cf081 mov apctl_el1, x1 + // aa1f03e1 mov x1, xzr # x1 = 0 + // 14000eb5 b 0x1fc0 # branch to regular start + 0x91400c21, 0xd378dc21, 0xd5181041, + 0xd2800041, 0xd51cf081, 0xaa1f03e1, + 0x14000eb5 +}; +static uint32_t g_bzero_branch_unconditionally_inst = 0x14000039; +static uint32_t g_qemu_call = 0xd51bff1f; + +typedef struct darwin_patch { + uint64_t addr; + uint32_t *inst; + uint32_t len; +} darwin_patch; + +typedef struct darwin_kernel_patch { + const char *darwin_str; + uint32_t num_patches; + struct darwin_patch patches[]; +} darwin_kernel_patch; + +// Patch is a single instruction +#define DARWIN_PATCH(offset, instruction) \ +{ .addr = offset, .inst = &instruction, .len = sizeof(instruction) } + +// Patch is an array of instructions +#define DARWIN_PATCH_A(offset, instruction) \ +{ .addr = offset, .inst = instruction, .len = sizeof(instruction) } + +struct darwin_kernel_patch darwin_patches_20A5364e = { + .darwin_str = + "Darwin Kernel Version 20.0.0: Sun Jun 14 21:36:36 PDT 2020; " + "root:Bridge_xnu-7090.111.5.2~1/RELEASE_ARM64_T8020", + .num_patches = 6, .patches = { + DARWIN_PATCH_A(0xfffffe00079f0580, g_set_cpacr_and_branch_inst), // initial branch + DARWIN_PATCH(0xfffffe00079e49fc, g_bzero_branch_unconditionally_inst), // bzero conditional branch + DARWIN_PATCH(0xfffffe0007f8330c, g_w23_zero_inst), // parse_machfile slide set instruction + DARWIN_PATCH(0xfffffe0007a5b47c, g_qemu_call), // notify kernel task pointer + DARWIN_PATCH(0xfffffe0008af5e3c, g_mov_w0_01_inst), // core trust check + DARWIN_PATCH(0xfffffe0007f83108, g_nop_inst), // load_machfile: disable IMGPF_NOJOP + } +}; + +struct darwin_kernel_patch darwin_patches_20B5012d = { + .darwin_str = + "Darwin Kernel Version 20.1.0: Sat Oct 24 21:20:41 PDT 2020; " + "root:xnu-7195.50.3.201.1~1/RELEASE_ARM64_T8020", + .num_patches = 6, .patches = { + DARWIN_PATCH_A(0xfffffe0007ab0580, g_set_cpacr_and_branch_inst), // initial branch + DARWIN_PATCH(0xfffffe0007aa49fc, g_bzero_branch_unconditionally_inst), // bzero conditional branch + DARWIN_PATCH(0xfffffe0008056168, g_w10_zero_inst), // parse_machfile slide set instruction + DARWIN_PATCH(0xfffffe0007b1f4d8, g_qemu_call), // notify kernel task pointer + DARWIN_PATCH(0xfffffe0008c96538, g_mov_w0_01_inst), // core trust check + DARWIN_PATCH(0xfffffe0008055f64, g_nop_inst), // load_machfile: disable IMGPF_NOJOP + } +}; + +struct darwin_kernel_patch darwin_patches_20C69 = { + .darwin_str = + "Darwin Kernel Version 20.2.0: Wed Dec 2 20:40:22 PST 2020; " + "root:xnu-7195.60.75~1/RELEASE_ARM64_T8020", + .num_patches = 5, .patches = { + DARWIN_PATCH_A(0xfffffe0007ac4580, g_set_cpacr_and_branch_inst), // initial branch + DARWIN_PATCH(0xfffffe0007ab8a3c, g_bzero_branch_unconditionally_inst), // bzero conditional branch + DARWIN_PATCH(0xfffffe000806b438, g_w10_zero_inst), // parse_machfile slide set instruction + DARWIN_PATCH(0xfffffe0008cb6538, g_mov_w0_01_inst), // core trust check + DARWIN_PATCH(0xfffffe000806b234, g_nop_inst), // load_machfile: disable IMGPF_NOJOP + } +}; + +struct darwin_kernel_patch *darwin_patches[] = { + &darwin_patches_20A5364e, + &darwin_patches_20B5012d, + &darwin_patches_20C69, +}; + +static void j273_add_cpregs(J273MachineState *nms) +{ + ARMCPU *cpu = nms->cpu; + + nms->J273_CPREG_VAR_NAME(ARM64_REG_EHID1) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_EHID10) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_EHID4) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_HID11) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_HID3) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_HID5) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_HID8) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_HID7) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_LSU_ERR_STS) = 0; + nms->J273_CPREG_VAR_NAME(PMC0) = 0; + nms->J273_CPREG_VAR_NAME(PMC1) = 0; + nms->J273_CPREG_VAR_NAME(PMCR1) = 0; + nms->J273_CPREG_VAR_NAME(PMSR) = 0; + nms->J273_CPREG_VAR_NAME(L2ACTLR_EL1) = 0; +#ifdef ENABLE_EL2_REGS + nms->J273_CPREG_VAR_NAME(ARM64_REG_MIGSTS_EL1) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_KERNELKEYLO_EL1) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_KERNELKEYHI_EL1) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_VMSA_LOCK_EL1) = 0; + nms->J273_CPREG_VAR_NAME(APRR_EL0) = 0; + nms->J273_CPREG_VAR_NAME(APRR_EL1) = 0; + nms->J273_CPREG_VAR_NAME(CTRR_LOCK) = 0; + nms->J273_CPREG_VAR_NAME(CTRR_A_LWR_EL1) = 0; + nms->J273_CPREG_VAR_NAME(CTRR_A_UPR_EL1) = 0; + nms->J273_CPREG_VAR_NAME(CTRR_CTL_EL1) = 0; + nms->J273_CPREG_VAR_NAME(APRR_MASK_EN_EL1) = 0; + nms->J273_CPREG_VAR_NAME(APRR_MASK_EL0) = 0; + nms->J273_CPREG_VAR_NAME(ACC_CTRR_A_LWR_EL2) = 0; + nms->J273_CPREG_VAR_NAME(ACC_CTRR_A_UPR_EL2) = 0; + nms->J273_CPREG_VAR_NAME(ACC_CTRR_CTL_EL2) = 0; + nms->J273_CPREG_VAR_NAME(ACC_CTRR_LOCK_EL2) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_CYC_CFG) = 0; + nms->J273_CPREG_VAR_NAME(ARM64_REG_CYC_OVRD) = 0; + nms->J273_CPREG_VAR_NAME(UPMCR0) = 0; + nms->J273_CPREG_VAR_NAME(UPMPCM) = 0; +#endif + + if (kvm_enabled()) { + define_arm_cp_regs_with_opaque(cpu, j273_cp_reginfo_kvm, nms); + } else { + define_arm_cp_regs_with_opaque(cpu, j273_cp_reginfo_tcg, nms); + } +} + +static void j273_create_s3c_uart(const J273MachineState *nms, Chardev *chr) +{ + qemu_irq irq; + DeviceState *d; + SysBusDevice *s; + hwaddr base = nms->uart_mmio_pa; + + //hack for now. create a device that is not used just to have a dummy + //unused interrupt + d = qdev_new(TYPE_PLATFORM_BUS_DEVICE); + s = SYS_BUS_DEVICE(d); + sysbus_init_irq(s, &irq); + //pass a dummy irq as we don't need nor want interrupts for this UART + DeviceState *dev = exynos4210_uart_create(base, 256, 0, chr, irq); + if (!dev) { + abort(); + } +} + +static void j273_patch_kernel(AddressSpace *nsas, char *darwin_ver) +{ + bool found = false; + darwin_patch *patch; + darwin_kernel_patch *kernel_patch; + for (int i = 0; i < sizeof(darwin_patches) / sizeof(uint64_t); i++) { + kernel_patch = darwin_patches[i]; + if (!strncmp(darwin_ver, kernel_patch->darwin_str, 1024)) { + for (int a = 0; a < kernel_patch->num_patches; a++) { + patch = &kernel_patch->patches[a]; + address_space_rw(nsas, vtop_static(patch->addr), + MEMTXATTRS_UNSPECIFIED, (uint8_t *)patch->inst, + patch->len, 1); + } + found = true; + } + } + if (found == false) { + printf("No support for %s\n", darwin_ver); + abort(); + } +} + +static void j273_ns_memory_setup(MachineState *machine, MemoryRegion *sysmem, + AddressSpace *nsas) +{ + uint64_t used_ram_for_blobs = 0; + hwaddr kernel_low; + hwaddr kernel_high; + hwaddr virt_base; + hwaddr dtb_va; + uint64_t dtb_size; + hwaddr kbootargs_pa; + hwaddr top_of_kernel_data_pa; + hwaddr mem_size; + hwaddr remaining_mem_size; + hwaddr allocated_ram_pa; + hwaddr phys_ptr; + hwaddr phys_pc; + hwaddr ramfb_pa = 0; + video_boot_args v_bootargs = {0}; + J273MachineState *nms = J273_MACHINE(machine); + char darwin_ver[1024]; + + //setup the memory layout: + + //At the beginning of the non-secure ram we have the raw kernel file. + //After that we have the static trust cache. + //After that we have all the kernel sections. + //After that we have ramdosk + //After that we have the device tree + //After that we have the kernel boot args + //After that we have the rest of the RAM + + macho_file_highest_lowest_base(nms->kernel_filename, J273_PHYS_BASE, + &virt_base, &kernel_low, &kernel_high); + + g_virt_base = virt_base; + g_phys_base = J273_PHYS_BASE; + phys_ptr = J273_PHYS_BASE; + + //now account for the loaded kernel + arm_load_macho(nms->kernel_filename, nsas, sysmem, "kernel.j273", + J273_PHYS_BASE, virt_base, kernel_low, + kernel_high, &phys_pc, darwin_ver); + nms->kpc_pa = phys_pc; + used_ram_for_blobs += (align_64k_high(kernel_high) - kernel_low); + + j273_patch_kernel(nsas, darwin_ver); + + phys_ptr = align_64k_high(vtop_static(kernel_high)); + + //now account for the ramdisk + nms->ramdisk_file_dev.pa = 0; + hwaddr ramdisk_size = 0; + if (0 != nms->ramdisk_filename[0]) { + nms->ramdisk_file_dev.pa = phys_ptr; + macho_map_raw_file(nms->ramdisk_filename, nsas, sysmem, + "ramdisk_raw_file.j273", nms->ramdisk_file_dev.pa, + &nms->ramdisk_file_dev.size); + ramdisk_size = nms->ramdisk_file_dev.size; + phys_ptr += align_64k_high(nms->ramdisk_file_dev.size); + } + + //now account for device tree + macho_load_dtb(nms->dtb_filename, nsas, sysmem, "dtb.j273", phys_ptr, + &dtb_size, nms->ramdisk_file_dev.pa, + ramdisk_size, &nms->uart_mmio_pa); + dtb_va = ptov_static(phys_ptr); + phys_ptr += align_64k_high(dtb_size); + used_ram_for_blobs += align_64k_high(dtb_size); + + //now account for kernel boot args + used_ram_for_blobs += align_64k_high(sizeof(struct xnu_arm64_boot_args)); + kbootargs_pa = phys_ptr; + nms->kbootargs_pa = kbootargs_pa; + phys_ptr += align_64k_high(sizeof(struct xnu_arm64_boot_args)); + nms->extra_data_pa = phys_ptr; + allocated_ram_pa = phys_ptr; + + if (nms->use_ramfb){ + ramfb_pa = ((hwaddr)&((AllocatedData *)nms->extra_data_pa)->ramfb[0]); + xnu_define_ramfb_device(nsas,ramfb_pa); + xnu_get_video_bootargs(&v_bootargs, ramfb_pa); + } + + phys_ptr += align_64k_high(sizeof(AllocatedData)); + top_of_kernel_data_pa = phys_ptr; + remaining_mem_size = machine->ram_size - used_ram_for_blobs; + mem_size = allocated_ram_pa - J273_PHYS_BASE + remaining_mem_size; + macho_setup_bootargs("k_bootargs.j273", nsas, sysmem, kbootargs_pa, + virt_base, J273_PHYS_BASE, mem_size, + top_of_kernel_data_pa, dtb_va, dtb_size, + v_bootargs, nms->kern_args); + + allocate_ram(sysmem, "j273.ram", allocated_ram_pa, remaining_mem_size); +} + +static void j273_memory_setup(MachineState *machine, + MemoryRegion *sysmem, + MemoryRegion *secure_sysmem, + AddressSpace *nsas) +{ + j273_ns_memory_setup(machine, sysmem, nsas); +} + +static void j273_cpu_setup(MachineState *machine, MemoryRegion **sysmem, + MemoryRegion **secure_sysmem, ARMCPU **cpu, + AddressSpace **nsas) +{ + Object *cpuobj = object_new(machine->cpu_type); + *cpu = ARM_CPU(cpuobj); + CPUState *cs = CPU(*cpu); + + *sysmem = get_system_memory(); + + object_property_set_link(cpuobj, "memory", + OBJECT(*sysmem), &error_abort); + + //set secure monitor to false + object_property_set_bool(cpuobj, "has_el3", false, NULL); + + object_property_set_bool(cpuobj, "has_el2", false, NULL); + + object_property_set_bool(cpuobj, "realized", true, &error_fatal); + + *nsas = cpu_get_address_space(cs, ARMASIdx_NS); + + object_unref(cpuobj); + //currently support only a single CPU and thus + //use no interrupt controller and wire IRQs from devices directly to the CPU +} + +static void j273_bootargs_setup(MachineState *machine) +{ + J273MachineState *nms = J273_MACHINE(machine); + nms->bootinfo.firmware_loaded = true; +} + +static void j273_cpu_reset(void *opaque) +{ + J273MachineState *nms = J273_MACHINE((MachineState *)opaque); + ARMCPU *cpu = nms->cpu; + CPUState *cs = CPU(cpu); + CPUARMState *env = &cpu->env; + + cpu_reset(cs); + + env->xregs[0] = nms->kbootargs_pa; + env->pc = nms->kpc_pa; +} + +//hooks arg is expected like this: +//"hookfilepath@va@scratch_reg#hookfilepath@va@scratch_reg#..." + +static void j273_machine_init_hook_funcs(J273MachineState *nms, + AddressSpace *nsas) +{ + AllocatedData *allocated_data = (AllocatedData *)nms->extra_data_pa; + uint64_t i = 0; + char *orig_pos = NULL; + size_t orig_len = 0; + char *pos = NULL; + char *next_pos = NULL; + size_t len = 0; + char *elem = NULL; + char *next_elem = NULL; + size_t elem_len = 0; + char *end; + + //ugly solution but a simple one for now, use this memory which is fixed at + //(pa: 0x0000000049BF4C00 va: 0xFFFFFFF009BF4C00) for globals to be common + //between drivers/hooks. Please adjust address if anything changes in + //the layout of the memory the "boot loader" sets up + uint64_t zero_var = 0; + address_space_rw(nsas, (hwaddr)&allocated_data->hook_globals[0], + MEMTXATTRS_UNSPECIFIED, (uint8_t *)&zero_var, + sizeof(zero_var), 1); + + nms->hook_funcs_count = 0; + + pos = &nms->hook_funcs_cfg[0]; + if ((NULL == pos) || (0 == strlen(pos))) { + //fprintf(stderr, "no function hooks configured\n"); + return; + } + + orig_pos = pos; + orig_len = strlen(pos); + + do { + next_pos = memchr(pos, '#', strlen(pos)); + if (NULL != next_pos) { + len = next_pos - pos; + } else { + len = strlen(pos); + } + + elem = pos; + next_elem = memchr(elem, '@', len); + if (NULL == next_elem) { + fprintf(stderr, "hook[%lu] failed to find '@' in %s\n", i, elem); + abort(); + } + elem_len = next_elem - elem; + elem[elem_len] = 0; + + uint8_t *code = NULL; + size_t size = 0; + if (!g_file_get_contents(elem, (char **)&code, &size, NULL)) { + fprintf(stderr, "hook[%lu] failed to read filepath: %s\n", + i, elem); + abort(); + } + + elem += elem_len + 1; + next_elem = memchr(elem, '@', len); + if (NULL == next_elem) { + fprintf(stderr, "hook[%lu] failed to find '@' in %s\n", i, elem); + abort(); + } + elem_len = next_elem - elem; + elem[elem_len] = 0; + + nms->hook_funcs[i].va = strtoull(elem, &end, 16); + nms->hook_funcs[i].pa = vtop_static(nms->hook_funcs[i].va); + nms->hook_funcs[i].buf_va = + ptov_static((hwaddr)&allocated_data->hook_funcs_code[i][0]); + nms->hook_funcs[i].buf_pa = + (hwaddr)&allocated_data->hook_funcs_code[i][0]; + nms->hook_funcs[i].buf_size = HOOK_CODE_ALLOC_SIZE; + nms->hook_funcs[i].code = (uint8_t *)code; + nms->hook_funcs[i].code_size = size; + + elem += elem_len + 1; + if (NULL != next_pos) { + elem_len = next_pos - elem; + } else { + elem_len = strlen(elem); + } + elem[elem_len] = 0; + + nms->hook_funcs[i].scratch_reg = (uint8_t)strtoul(elem, &end, 10); + + i++; + pos += len + 1; + } while ((NULL != pos) && (pos < (orig_pos + orig_len))); + + nms->hook_funcs_count = i; +} + +static void j273_machine_init(MachineState *machine) +{ + J273MachineState *nms = J273_MACHINE(machine); + MemoryRegion *sysmem; + MemoryRegion *secure_sysmem; + AddressSpace *nsas; + ARMCPU *cpu; + CPUState *cs; + DeviceState *cpudev; + + j273_cpu_setup(machine, &sysmem, &secure_sysmem, &cpu, &nsas); + + nms->cpu = cpu; + + j273_memory_setup(machine, sysmem, secure_sysmem, nsas); + + cpudev = DEVICE(cpu); + cs = CPU(cpu); + AllocatedData *allocated_data = (AllocatedData *)nms->extra_data_pa; + + if (0 != nms->driver_filename[0]) { + xnu_hook_tr_setup(nsas, cpu); + uint8_t *code = NULL; + unsigned long size; + if (!g_file_get_contents(nms->driver_filename, (char **)&code, + &size, NULL)) { + abort(); + } + nms->hook.va = UBC_INIT_VADDR_16B92; + nms->hook.pa = vtop_static(UBC_INIT_VADDR_16B92); + nms->hook.buf_va = + ptov_static((hwaddr)&allocated_data->hook_code[0]); + nms->hook.buf_pa = (hwaddr)&allocated_data->hook_code[0]; + nms->hook.buf_size = HOOK_CODE_ALLOC_SIZE; + nms->hook.code = (uint8_t *)code; + nms->hook.code_size = size; + nms->hook.scratch_reg = 2; + } + + if (0 != nms->qc_file_0_filename[0]) { + qc_file_open(0, &nms->qc_file_0_filename[0]); + } + + if (0 != nms->qc_file_1_filename[0]) { + qc_file_open(1, &nms->qc_file_1_filename[0]); + } + + if (0 != nms->qc_file_log_filename[0]) { + qc_file_open(2, &nms->qc_file_log_filename[0]); + } + + j273_machine_init_hook_funcs(nms, nsas); + + j273_add_cpregs(nms); + + j273_create_s3c_uart(nms, serial_hd(0)); + + //wire timer to FIQ as expected by Apple's SoCs + qdev_connect_gpio_out(cpudev, GTIMER_VIRT, + qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); + + j273_bootargs_setup(machine); + + qemu_register_reset(j273_cpu_reset, nms); +} + +static void j273_set_ramdisk_filename(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + + g_strlcpy(nms->ramdisk_filename, value, sizeof(nms->ramdisk_filename)); +} + +static char *j273_get_ramdisk_filename(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + return g_strdup(nms->ramdisk_filename); +} + +static void j273_set_kernel_filename(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + + g_strlcpy(nms->kernel_filename, value, sizeof(nms->kernel_filename)); +} + +static char *j273_get_kernel_filename(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + return g_strdup(nms->kernel_filename); +} + +static void j273_set_dtb_filename(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + + g_strlcpy(nms->dtb_filename, value, sizeof(nms->dtb_filename)); +} + +static char *j273_get_dtb_filename(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + return g_strdup(nms->dtb_filename); +} + +static void j273_set_kern_args(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + + g_strlcpy(nms->kern_args, value, sizeof(nms->kern_args)); +} + +static char *j273_get_kern_args(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + return g_strdup(nms->kern_args); +} + +static void j273_set_tunnel_port(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + nms->tunnel_port = atoi(value); +} + +static char *j273_get_tunnel_port(Object *obj, Error **errp) +{ + char buf[128]; + J273MachineState *nms = J273_MACHINE(obj); + snprintf(buf, 128, "%d", nms->tunnel_port); + return g_strdup(buf); +} + +static void j273_set_hook_funcs(Object *obj, const char *value, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + + g_strlcpy(nms->hook_funcs_cfg, value, sizeof(nms->hook_funcs_cfg)); +} + +static char *j273_get_hook_funcs(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + return g_strdup(nms->hook_funcs_cfg); +} + +static void j273_set_driver_filename(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + + g_strlcpy(nms->driver_filename, value, sizeof(nms->driver_filename)); +} + +static char *j273_get_driver_filename(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + return g_strdup(nms->driver_filename); +} + +static void j273_set_qc_file_0_filename(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + + g_strlcpy(nms->qc_file_0_filename, value, sizeof(nms->qc_file_0_filename)); +} + +static char *j273_get_qc_file_0_filename(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + return g_strdup(nms->qc_file_0_filename); +} + +static void j273_set_qc_file_1_filename(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + + g_strlcpy(nms->qc_file_1_filename, value, sizeof(nms->qc_file_1_filename)); +} + +static char *j273_get_qc_file_1_filename(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + return g_strdup(nms->qc_file_1_filename); +} + +static void j273_set_qc_file_log_filename(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + + g_strlcpy(nms->qc_file_log_filename, value, + sizeof(nms->qc_file_log_filename)); +} + +static char *j273_get_qc_file_log_filename(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + return g_strdup(nms->qc_file_log_filename); +} + +static void j273_set_xnu_ramfb(Object *obj, const char *value, + Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + if (strcmp(value,"on") == 0) + nms->use_ramfb = true; + else { + if (strcmp(value,"off") != 0) + fprintf(stderr,"NOTE: the value of xnu-ramfb is not valid,\ +the framebuffer will be disabled.\n"); + nms->use_ramfb = false; + } +} + +static char* j273_get_xnu_ramfb(Object *obj, Error **errp) +{ + J273MachineState *nms = J273_MACHINE(obj); + if (nms->use_ramfb) + return g_strdup("on"); + else + return g_strdup("off"); +} + +static void j273_instance_init(Object *obj) +{ + object_property_add_str(obj, "ramdisk-filename", j273_get_ramdisk_filename, + j273_set_ramdisk_filename); + object_property_set_description(obj, "ramdisk-filename", + "Set the ramdisk filename to be loaded"); + + object_property_add_str(obj, "kernel-filename", j273_get_kernel_filename, + j273_set_kernel_filename); + object_property_set_description(obj, "kernel-filename", + "Set the kernel filename to be loaded"); + + object_property_add_str(obj, "dtb-filename", j273_get_dtb_filename, + j273_set_dtb_filename); + object_property_set_description(obj, "dtb-filename", + "Set the dev tree filename to be loaded"); + + object_property_add_str(obj, "kern-cmd-args", j273_get_kern_args, + j273_set_kern_args); + object_property_set_description(obj, "kern-cmd-args", + "Set the XNU kernel cmd args"); + + object_property_add_str(obj, "tunnel-port", j273_get_tunnel_port, + j273_set_tunnel_port); + object_property_set_description(obj, "tunnel-port", + "Set the port for the tunnel connection"); + + object_property_add_str(obj, "hook-funcs", j273_get_hook_funcs, + j273_set_hook_funcs); + object_property_set_description(obj, "hook-funcs", + "Set the hook funcs to be loaded"); + + object_property_add_str(obj, "driver-filename", j273_get_driver_filename, + j273_set_driver_filename); + object_property_set_description(obj, "driver-filename", + "Set the driver filename to be loaded"); + + object_property_add_str(obj, "qc-file-0-filename", + j273_get_qc_file_0_filename, + j273_set_qc_file_0_filename); + object_property_set_description(obj, "qc-file-0-filename", + "Set the qc file 0 filename to be loaded"); + + object_property_add_str(obj, "qc-file-1-filename", + j273_get_qc_file_1_filename, + j273_set_qc_file_1_filename); + object_property_set_description(obj, "qc-file-1-filename", + "Set the qc file 1 filename to be loaded"); + + object_property_add_str(obj, "qc-file-log-filename", + j273_get_qc_file_log_filename, + j273_set_qc_file_log_filename); + object_property_set_description(obj, "qc-file-log-filename", + "Set the qc file log filename to be loaded"); + + object_property_add_str(obj, "xnu-ramfb", + j273_get_xnu_ramfb, + j273_set_xnu_ramfb); + object_property_set_description(obj, "xnu-ramfb", + "Turn on the display framebuffer"); + +} + +static void j273_machine_class_init(ObjectClass *klass, void *data) +{ + MachineClass *mc = MACHINE_CLASS(klass); + mc->desc = "macOS Big Sur Beta 6 (j273 - A12Z)"; + mc->init = j273_machine_init; + mc->max_cpus = 1; + //this disables the error message "Failed to query for block devices!" + //when starting qemu - must keep at least one device + //mc->no_sdcard = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_parallel = 1; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a57"); + mc->minimum_page_bits = 12; +} + +static const TypeInfo j273_machine_info = { + .name = TYPE_J273_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(J273MachineState), + .class_size = sizeof(J273MachineClass), + .class_init = j273_machine_class_init, + .instance_init = j273_instance_init, +}; + +static void j273_machine_types(void) +{ + type_register_static(&j273_machine_info); +} + +type_init(j273_machine_types) diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/xnu.c b/xnu-qemu-arm64-5.1.0/hw/arm/xnu.c new file mode 100644 index 0000000..70ffeaf --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/xnu.c @@ -0,0 +1,343 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/arm/xnu.h" +#include "hw/loader.h" + +static void allocate_and_copy(MemoryRegion *mem, AddressSpace *as, + const char *name, hwaddr pa, hwaddr size, + void *buf) +{ + if (mem) { + allocate_ram(mem, name, pa, align_64k_high(size)); + } + address_space_rw(as, pa, MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, size, 1); +} + +void macho_load_dtb(char *filename, AddressSpace *as, MemoryRegion *mem, + const char *name, hwaddr dtb_pa, uint64_t *size, + hwaddr ramdisk_addr, hwaddr ramdisk_size, + hwaddr *uart_mmio_pa) +{ + uint8_t *file_data = NULL; + unsigned long fsize; + + if (g_file_get_contents(filename, (char **)&file_data, &fsize, NULL)) { + DTBNode *root = load_dtb(file_data); + + //first fetch the uart mmio address + DTBNode *child = get_dtb_child_node_by_name(root, "arm-io"); + if (NULL == child) { + abort(); + } + DTBProp *prop = get_dtb_prop(child, "ranges"); + if (NULL == prop) { + abort(); + } + hwaddr *ranges = (hwaddr *)prop->value; + hwaddr soc_base_pa = ranges[1]; + child = get_dtb_child_node_by_name(child, "uart0"); + if (NULL == child) { + abort(); + } + //make sure this node has the boot-console prop + prop = get_dtb_prop(child, "boot-console"); + if (NULL == prop) { + abort(); + } + prop = get_dtb_prop(child, "reg"); + if (NULL == prop) { + abort(); + } + hwaddr *uart_offset = (hwaddr *)prop->value; + if (NULL != uart_mmio_pa) { + *uart_mmio_pa = soc_base_pa + uart_offset[0]; + } + + child = get_dtb_child_node_by_name(root, "chosen"); + child = get_dtb_child_node_by_name(child, "memory-map"); + if (NULL == child) { + abort(); + } + + uint64_t memmap[2] = {0}; + + if ((0 != ramdisk_addr) && (0 != ramdisk_size)) { + memmap[0] = ramdisk_addr; + memmap[1] = ramdisk_size; + add_dtb_prop(child, "RAMDisk", sizeof(memmap), + (uint8_t *)&memmap[0]); + } + + uint64_t size_n = get_dtb_node_buffer_size(root); + + uint8_t *buf = g_malloc0(size_n); + save_dtb(buf, root); + + allocate_and_copy(mem, as, name, dtb_pa, size_n, buf); + g_free(file_data); + delete_dtb_node(root); + g_free(buf); + *size = size_n; + } else { + abort(); + } +} + +void macho_map_raw_file(const char *filename, AddressSpace *as, MemoryRegion *mem, + const char *name, hwaddr file_pa, uint64_t *size) +{ + Error *err = NULL; + MemoryRegion *mr = NULL; + struct stat file_info; + + if (stat(filename, &file_info)) { + fprintf(stderr, "Couldn't get file size for mmapping. Loading into RAM.\n"); + goto load_fallback; + } + + mr = g_new(MemoryRegion, 1); + *size = file_info.st_size; + + memory_region_init_ram_from_file(mr, NULL, name, *size & (~0xffffUL), 0, 0, filename, &err); + if (err) { + error_report_err(err); + fprintf(stderr, "Couldn't mmap file. Loading into RAM.\n"); + goto load_fallback; + } + memory_region_add_subregion(mem, file_pa, mr); + return; + +load_fallback: + if (mr) { + g_free(mr); + } + macho_load_raw_file(filename, as, mem, name, file_pa, size); +} + +void macho_load_raw_file(const char *filename, AddressSpace *as, MemoryRegion *mem, + const char *name, hwaddr file_pa, uint64_t *size) +{ + uint8_t* file_data = NULL; + unsigned long sizef; + if (g_file_get_contents(filename, (char **)&file_data, &sizef, NULL)) { + *size = sizef; + allocate_and_copy(mem, as, name, file_pa, *size, file_data); + g_free(file_data); + } else { + abort(); + } +} + +void macho_tz_setup_bootargs(const char *name, AddressSpace *as, + MemoryRegion *mem, hwaddr bootargs_addr, + hwaddr virt_base, hwaddr phys_base, + hwaddr mem_size, hwaddr kern_args, + hwaddr kern_entry, hwaddr kern_phys_base) +{ + struct xnu_arm64_monitor_boot_args boot_args; + memset(&boot_args, 0, sizeof(boot_args)); + boot_args.version = xnu_arm64_kBootArgsVersion2; + boot_args.virtBase = virt_base; + boot_args.physBase = phys_base; + boot_args.memSize = mem_size; + boot_args.kernArgs = kern_args; + boot_args.kernEntry = kern_entry; + boot_args.kernPhysBase = kern_phys_base; + + boot_args.kernPhysSlide = 0; + boot_args.kernVirtSlide = 0; + + allocate_and_copy(mem, as, name, bootargs_addr, sizeof(boot_args), + &boot_args); +} + +void macho_setup_bootargs(const char *name, AddressSpace *as, + MemoryRegion *mem, hwaddr bootargs_pa, + hwaddr virt_base, hwaddr phys_base, hwaddr mem_size, + hwaddr top_of_kernel_data_pa, hwaddr dtb_va, + hwaddr dtb_size, video_boot_args v_bootargs, + char *kern_args) +{ + struct xnu_arm64_boot_args boot_args; + memset(&boot_args, 0, sizeof(boot_args)); + boot_args.Revision = xnu_arm64_kBootArgsRevision2; + boot_args.Version = xnu_arm64_kBootArgsVersion2; + boot_args.virtBase = virt_base; + boot_args.physBase = phys_base; + boot_args.memSize = mem_size; + + boot_args.Video.v_baseAddr = v_bootargs.v_baseAddr; + boot_args.Video.v_depth = v_bootargs.v_depth; + boot_args.Video.v_display = v_bootargs.v_display; + boot_args.Video.v_height = v_bootargs.v_height; + boot_args.Video.v_rowBytes = v_bootargs.v_rowBytes; + boot_args.Video.v_width = v_bootargs.v_width; + + boot_args.topOfKernelData = top_of_kernel_data_pa; + boot_args.deviceTreeP = dtb_va; + boot_args.deviceTreeLength = dtb_size; + boot_args.memSizeActual = 0; + if (kern_args) { + g_strlcpy(boot_args.CommandLine, kern_args, + sizeof(boot_args.CommandLine)); + } + + allocate_and_copy(mem, as, name, bootargs_pa, sizeof(boot_args), + &boot_args); +} + +static void macho_highest_lowest(struct mach_header_64* mh, uint64_t *lowaddr, + uint64_t *highaddr) +{ + struct load_command* cmd = (struct load_command*)((uint8_t*)mh + + sizeof(struct mach_header_64)); + // iterate all the segments once to find highest and lowest addresses + uint64_t low_addr_temp = ~0; + uint64_t high_addr_temp = 0; + for (unsigned int index = 0; index < mh->ncmds; index++) { + switch (cmd->cmd) { + case LC_SEGMENT_64: { + struct segment_command_64 *segCmd = + (struct segment_command_64 *)cmd; + if (segCmd->vmaddr < low_addr_temp) { + low_addr_temp = segCmd->vmaddr; + } + if (segCmd->vmaddr + segCmd->vmsize > high_addr_temp) { + high_addr_temp = segCmd->vmaddr + segCmd->vmsize; + } + break; + } + } + cmd = (struct load_command*)((char*)cmd + cmd->cmdsize); + } + *lowaddr = low_addr_temp; + *highaddr = high_addr_temp; +} + +static void macho_file_highest_lowest(const char *filename, hwaddr *lowest, + hwaddr *highest) +{ + gsize len; + uint8_t *data = NULL; + if (!g_file_get_contents(filename, (char **)&data, &len, NULL)) { + abort(); + } + struct mach_header_64* mh = (struct mach_header_64*)data; + macho_highest_lowest(mh, lowest, highest); + g_free(data); +} + +void macho_file_highest_lowest_base(const char *filename, hwaddr phys_base, + hwaddr *virt_base, hwaddr *lowest, + hwaddr *highest) +{ + uint8_t high_Low_dif_bit_index; + uint8_t phys_base_non_zero_bit_index; + hwaddr bit_mask_for_index; + + macho_file_highest_lowest(filename, lowest, highest); + high_Low_dif_bit_index = + get_highest_different_bit_index(align_64k_high(*highest), + align_64k_low(*lowest)); + if (phys_base) { + phys_base_non_zero_bit_index = + get_lowest_non_zero_bit_index(phys_base); + + //make sure we have enough zero bits to have all the diffrent kernel + //image addresses have the same non static bits in physical and in + //virtual memory. + if (high_Low_dif_bit_index > phys_base_non_zero_bit_index) { + abort(); + } + bit_mask_for_index = + get_low_bits_mask_for_bit_index(phys_base_non_zero_bit_index); + + *virt_base = align_64k_low(*lowest) & (~bit_mask_for_index); + } + +} + +void arm_load_macho(char *filename, AddressSpace *as, MemoryRegion *mem, + const char *name, hwaddr phys_base, hwaddr virt_base, + hwaddr low_virt_addr, hwaddr high_virt_addr, hwaddr *pc, + char *darwin_ver) +{ + uint8_t *data = NULL; + gsize len; + uint8_t* rom_buf = NULL; + + if (!g_file_get_contents(filename, (char **)&data, &len, NULL)) { + abort(); + } + + const char *darwin_str = "Darwin Kernel Version"; + if (darwin_ver) { + char *res = memmem((char *)data, len, darwin_str, + sizeof(darwin_str)); + if (!res) + abort(); + strncpy(darwin_ver, res, strnlen(res, 1024) + 1); + } + + struct mach_header_64* mh = (struct mach_header_64*)data; + struct load_command* cmd = (struct load_command*)(data + + sizeof(struct mach_header_64)); + + uint64_t rom_buf_size = align_64k_high(high_virt_addr) - low_virt_addr; + rom_buf = g_malloc0(rom_buf_size); + for (unsigned int index = 0; index < mh->ncmds; index++) { + switch (cmd->cmd) { + case LC_SEGMENT_64: { + struct segment_command_64 *segCmd = + (struct segment_command_64 *)cmd; + memcpy(rom_buf + (segCmd->vmaddr - low_virt_addr), + data + segCmd->fileoff, segCmd->filesize); + break; + } + case LC_UNIXTHREAD: { + // grab just the entry point PC + uint64_t* ptrPc = (uint64_t*)((char*)cmd + 0x110); + // 0x110 for arm64 only. + *pc = vtop_bases(*ptrPc, phys_base, virt_base); + break; + } + } + cmd = (struct load_command*)((char*)cmd + cmd->cmdsize); + } + hwaddr low_phys_addr = vtop_bases(low_virt_addr, phys_base, virt_base); + allocate_and_copy(mem, as, name, low_phys_addr, rom_buf_size, rom_buf); + + if (data) { + g_free(data); + } + if (rom_buf) { + g_free(rom_buf); + } +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/xnu_cpacr.c b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_cpacr.c new file mode 100644 index 0000000..18a85b3 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_cpacr.c @@ -0,0 +1,86 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/arm/xnu_cpacr.h" +#include "hw/loader.h" + +static CpacrIntCtx ctx = {0}; + +static void cpacr_a32_s_int_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ctx.wfn_a32_s(env, ri, ctx.val); +} + +static void cpacr_a32_s_int_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + cpacr_a32_s_int_write(env, ri, ctx.val); +} + +static void cpacr_a32_ns_int_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ctx.wfn_a32_ns(env, ri, ctx.val); +} + +static void cpacr_a32_ns_int_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + cpacr_a32_ns_int_write(env, ri, ctx.val); +} + +static void cpacr_a64_intercept_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ctx.wfn_a64(env, ri, ctx.val); +} + +static void cpacr_a64_intercept_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + cpacr_a64_intercept_write(env, ri, ctx.val); +} + +void xnu_cpacr_intercept_write_const_val(ARMCPU *cpu, uint64_t val) +{ + ctx.val = val; + uint32_t key = ENCODE_AA64_CP_REG(19, 1, 0, 3, 0, 2); + ARMCPRegInfo *ri = (ARMCPRegInfo *)get_arm_cp_reginfo(cpu->cp_regs, key); + ctx.wfn_a64 = ri->writefn; + ri->writefn = cpacr_a64_intercept_write; + ri->resetfn = cpacr_a64_intercept_reset; + key = ENCODE_CP_REG(15, 0, 1, 1, 0, 0, 2); + ri = (ARMCPRegInfo *)get_arm_cp_reginfo(cpu->cp_regs, key); + ctx.wfn_a32_ns = ri->writefn; + ri->writefn = cpacr_a32_ns_int_write; + ri->resetfn = cpacr_a32_ns_int_reset; + key = ENCODE_CP_REG(15, 0, 0, 1, 0, 0, 2); + ri = (ARMCPRegInfo *)get_arm_cp_reginfo(cpu->cp_regs, key); + ctx.wfn_a32_s = ri->writefn; + ri->writefn = cpacr_a32_s_int_write; + ri->resetfn = cpacr_a32_s_int_reset; +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/xnu_dtb.c b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_dtb.c new file mode 100644 index 0000000..e539a24 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_dtb.c @@ -0,0 +1,335 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/arm/xnu.h" +#include "hw/loader.h" +#include "hw/arm/xnu_dtb.h" + +static uint64_t align_4_high_num(uint64_t num) +{ + return (num + (4 - 1)) & ~(4 - 1); +} + +static void *align_4_high_ptr(void *ptr) +{ + uint64_t num = align_4_high_num((uint64_t)ptr); + return (void *)num; +} + + +static DTBProp *read_dtb_prop(uint8_t **dtb_blob) +{ + if ((NULL == dtb_blob) || (NULL == *dtb_blob)) { + abort(); + } + *dtb_blob = align_4_high_ptr(*dtb_blob); + DTBProp *prop = g_new0(DTBProp, 1); + memcpy(&prop->name[0], *dtb_blob, DTB_PROP_NAME_LEN); + *dtb_blob += DTB_PROP_NAME_LEN; + //zero out this flag which sometimes appears in the DT + //normally done by iboot + prop->length = *(uint32_t *)*dtb_blob & ~DT_PROP_FLAG_PLACEHOLDER; + *dtb_blob += sizeof(uint32_t); + if (0 != prop->length) { + prop->value = g_malloc0(prop->length); + if (NULL == prop->value) { + abort(); + } + memcpy(&prop->value[0], *dtb_blob, prop->length); + *dtb_blob += prop->length; + } + + return prop; +} + +static void delete_prop(DTBProp *prop) +{ + if (NULL == prop) { + return; + } + + if (NULL != prop->value) { + g_free(prop->value); + } + + g_free(prop); +} + +static DTBNode *read_dtb_node(uint8_t **dtb_blob) +{ + if ((NULL == dtb_blob) || (NULL == *dtb_blob)) { + abort(); + } + + uint32_t i = 0; + + *dtb_blob = align_4_high_ptr(*dtb_blob); + DTBNode *node = g_new0(DTBNode, 1); + node->prop_count = *(uint32_t *)*dtb_blob; + *dtb_blob += sizeof(uint32_t); + node->child_node_count = *(uint32_t *)*dtb_blob; + *dtb_blob += sizeof(uint32_t); + + if (0 == node->prop_count) { + abort(); + } + for (i = 0; i < node->prop_count; i++) { + DTBProp *prop = read_dtb_prop(dtb_blob); + node->props = g_list_append(node->props, prop); + } + for (i = 0; i < node->child_node_count; i++) { + DTBNode *child = read_dtb_node(dtb_blob); + node->child_nodes = g_list_append(node->child_nodes, child); + } + return node; +} + +void delete_dtb_node(DTBNode *node) +{ + if (NULL == node) { + return; + } + if (NULL != node->props) { + g_list_free_full(node->props, (GDestroyNotify)delete_prop); + } + if (NULL != node->child_nodes) { + g_list_free_full(node->child_nodes, (GDestroyNotify)delete_dtb_node); + } + g_free(node); +} + +DTBNode *load_dtb(uint8_t *dtb_blob) +{ + DTBNode *root = read_dtb_node(&dtb_blob); + return root; +} + +static void save_prop(DTBProp *prop, uint8_t **buf) +{ + if ((NULL == prop) || (NULL == buf) || (NULL ==*buf)) { + abort(); + } + + *buf = align_4_high_ptr(*buf); + memcpy(*buf, &prop->name[0], DTB_PROP_NAME_LEN); + *buf += DTB_PROP_NAME_LEN; + memcpy(*buf, &prop->length, sizeof(uint32_t)); + *buf += sizeof(uint32_t); + memcpy(*buf, prop->value, prop->length); + *buf += prop->length; +} + +static void save_node(DTBNode *node, uint8_t **buf) +{ + if ((NULL == node) || (NULL == buf) || (NULL ==*buf)) { + abort(); + } + + *buf = align_4_high_ptr(*buf); + + memcpy(*buf, &node->prop_count, sizeof(uint32_t)); + *buf += sizeof(uint32_t); + memcpy(*buf, &node->child_node_count, sizeof(uint32_t)); + *buf += sizeof(uint32_t); + g_list_foreach(node->props, (GFunc)save_prop, buf); + g_list_foreach(node->child_nodes, (GFunc)save_node, buf); +} + +void remove_dtb_prop(DTBNode *node, DTBProp *prop) +{ + if ((NULL == node) || (NULL == prop)) { + abort(); + } + GList *iter; + bool found = false; + for (iter = node->props; iter != NULL; iter = iter->next) { + if (prop == iter->data) { + found = true; + break; + } + } + if (!found) { + abort(); + return; + } + delete_prop(prop); + node->props = g_list_delete_link(node->props, iter); + + //sanity + if (0 == node->prop_count) { + abort(); + } + + node->prop_count--; +} + +void add_dtb_prop(DTBNode *n, const char *name, uint32_t size, uint8_t *val) +{ + if ((NULL == n) || (NULL == name) || (NULL == val)) { + abort(); + } + DTBProp *prop = g_new0(DTBProp, 1); + memcpy(&prop->name[0], name, DTB_PROP_NAME_LEN); + prop->length = size; + prop->value = g_malloc0(size); + memcpy(&prop->value[0], val, size); + n->props = g_list_append(n->props, prop); + n->prop_count++; +} + +void save_dtb(uint8_t *buf, DTBNode *root) +{ + if ((NULL == root) || (NULL == buf)) { + abort(); + } + + //TODO: handle cases where the buffer is not 4 bytes aligned + //though this is never expected to happen and the code is simpler this + //way + if (align_4_high_ptr(buf) != buf) { + abort(); + } + + save_node(root, &buf); +} + +static uint64_t get_dtb_prop_size(DTBProp *prop) +{ + uint64_t size = 0; + + if (NULL == prop) { + abort(); + } + + size = align_4_high_num(sizeof(prop->name) + sizeof(prop->length) + + prop->length); + return size; +} + +uint64_t get_dtb_node_buffer_size(DTBNode *node) +{ + uint64_t size = 0; + DTBProp *prop = NULL; + DTBNode *child = NULL; + GList *iter = NULL; + + if (NULL == node) { + abort(); + } + + size += sizeof(node->prop_count) + sizeof(node->child_node_count); + + for (iter = node->props; iter != NULL; iter = iter->next) { + prop = (DTBProp *)iter->data; + if (NULL == prop) { + abort(); + } + size += get_dtb_prop_size(prop); + } + for (iter = node->child_nodes; iter != NULL; iter = iter->next) { + child = (DTBNode *)iter->data; + if (NULL == child) { + abort(); + } + size += get_dtb_node_buffer_size(child); + } + return size; +} + +DTBProp *get_dtb_prop(DTBNode *node, const char *name) +{ + if ((NULL == node) || (NULL == name)) { + abort(); + } + + GList *iter = NULL; + DTBProp *prop = NULL; + + for (iter = node->props; iter != NULL; iter = iter->next) { + prop = (DTBProp *)iter->data; + + if (NULL == prop) { + abort(); + } + + if (0 == strncmp((const char *)&prop->name[0], name, + DTB_PROP_NAME_LEN)) { + return prop; + } + } + return NULL; +} + +DTBNode *get_dtb_child_node_by_name(DTBNode *node, const char *name) +{ + if ((NULL == node) || (NULL == name)) { + abort(); + } + + GList *iter = NULL; + DTBProp *prop = NULL; + DTBNode *child = NULL; + + for (iter = node->child_nodes; iter != NULL; iter = iter->next) { + child = (DTBNode *)iter->data; + + if (NULL == child) { + abort(); + } + + prop = get_dtb_prop(child, "name"); + + if (NULL == prop) { + abort(); + } + + if (0 == strncmp((const char *)prop->value, name, prop->length)) { + return child; + } + } + return NULL; +} + +void overwrite_dtb_prop_val(DTBProp *prop, uint8_t chr) +{ + uint64_t i = 0; + uint8_t *ptr = prop->value; + for (i = 0; i < prop->length - 1; i++) { + ptr[i] = chr; + } +} + +void overwrite_dtb_prop_name(DTBProp *prop, uint8_t chr) +{ + uint64_t i = 0; + uint8_t *ptr = &prop->name[0]; + for (i = 0; i < DTB_PROP_NAME_LEN; i++) { + ptr[i] = chr; + } +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/xnu_fb_cfg.c b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_fb_cfg.c new file mode 100644 index 0000000..eabe984 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_fb_cfg.c @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/arm/xnu.h" +#include "hw/loader.h" +#include "hw/arm/xnu_file_mmio_dev.h" +#include "hw/display/xnu_ramfb.h" +#include "include/hw/qdev-properties.h" + +void xnu_define_ramfb_device(AddressSpace* as, hwaddr ramfb_pa) +{ + + DeviceState *fb_dev; + fb_dev = qdev_new(TYPE_XNU_RAMFB_DEVICE); + qdev_prop_set_uint64(fb_dev, "as", (hwaddr)as); + qdev_prop_set_uint64(fb_dev, "fb_pa", ramfb_pa); + qdev_prop_set_uint32(fb_dev, "fb_size", RAMFB_SIZE); + qdev_prop_set_uint32(fb_dev, "display_cfg.height", V_HEIGHT); + qdev_prop_set_uint32(fb_dev, "display_cfg.width", V_WIDTH); + qdev_prop_set_uint32(fb_dev, "display_cfg.linesize", V_LINESIZE); + sysbus_realize_and_unref(SYS_BUS_DEVICE(fb_dev), &error_fatal); +} + +void xnu_get_video_bootargs(void *opaque, hwaddr ramfb_pa) +{ + + video_boot_args* v_bootargs = (video_boot_args*)opaque; + v_bootargs->v_baseAddr = ramfb_pa; + v_bootargs->v_depth = V_DEPTH; + v_bootargs->v_display = V_DISPLAY; + v_bootargs->v_height = V_HEIGHT; + v_bootargs->v_width = V_WIDTH; + v_bootargs->v_rowBytes = V_LINESIZE; + +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/xnu_file_mmio_dev.c b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_file_mmio_dev.c new file mode 100644 index 0000000..5d025c3 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_file_mmio_dev.c @@ -0,0 +1,106 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/arm/xnu.h" +#include "hw/loader.h" +#include "hw/arm/xnu_file_mmio_dev.h" + +static uint64_t xnu_file_mmio_dev_read(void *opaque, + hwaddr addr, unsigned size) +{ + FileMmioDev *file_dev = opaque; + uint64_t ret = 0; + + if (addr + size > file_dev->size) { + abort(); + } + + if (size > sizeof(ret)) { + abort(); + } + + if (addr != lseek(file_dev->fd, addr, SEEK_SET)) { + abort(); + } + + if (size != read(file_dev->fd, &ret, size)) { + abort(); + } + + return ret; +} + +static void xnu_file_mmio_dev_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + FileMmioDev *file_dev = opaque; + + if (addr + size > file_dev->size) { + abort(); + } + + if (addr != lseek(file_dev->fd, addr, SEEK_SET)) { + abort(); + } + + if (size != write(file_dev->fd, &val, size)) { + abort(); + } + +} + +const MemoryRegionOps xnu_file_mmio_dev_ops = { + .read = xnu_file_mmio_dev_read, + .write = xnu_file_mmio_dev_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +void xnu_file_mmio_dev_create(MemoryRegion *sysmem, FileMmioDev *file_dev, + const char *name, const char *filename) +{ + MemoryRegion *iomem = g_new(MemoryRegion, 1); + struct stat st; + + if (-1 == lstat(filename, &st)) { + abort(); + } + + file_dev->size = st.st_size; + + memory_region_init_io(iomem, NULL, &xnu_file_mmio_dev_ops, file_dev, + name, file_dev->size); + memory_region_add_subregion(sysmem, file_dev->pa, iomem); + + //TODO; think about using O_SYNC + //or maybe use fsync() from time to time + file_dev->fd = open(filename, O_RDWR); + if (-1 == file_dev->fd) { + abort(); + } +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/xnu_mem.c b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_mem.c new file mode 100644 index 0000000..5e4a62f --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_mem.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "exec/address-spaces.h" +#include "hw/misc/unimp.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/platform-bus.h" +#include "exec/memory.h" +#include "qemu-common.h" +#include "exec/hwaddr.h" +#include "hw/boards.h" +#include "hw/arm/boot.h" +#include "cpu.h" +#include "hw/arm/xnu_mem.h" + +hwaddr g_virt_base = 0; +hwaddr g_phys_base = 0; + +hwaddr vtop_bases(hwaddr va, hwaddr phys_base, hwaddr virt_base) +{ + if ((0 == virt_base) || (0 == phys_base)) { + abort(); + } + return va - virt_base + phys_base; +} + +hwaddr ptov_bases(hwaddr pa, hwaddr phys_base, hwaddr virt_base) +{ + if ((0 == virt_base) || (0 == phys_base)) { + abort(); + } + return pa - phys_base + virt_base; +} + +hwaddr vtop_static(hwaddr va) +{ + return vtop_bases(va, g_phys_base, g_virt_base); +} + +hwaddr ptov_static(hwaddr pa) +{ + return ptov_bases(pa, g_phys_base, g_virt_base); +} + +hwaddr vtop_mmu(hwaddr va, CPUState *cs) +{ + hwaddr phys_addr; + MemTxAttrs attrs = {}; + + phys_addr = arm_cpu_get_phys_page_attrs_debug(cs, va, &attrs); + if (-1 == phys_addr) { + abort(); + } + + return phys_addr; +} + +uint8_t get_highest_different_bit_index(hwaddr addr1, hwaddr addr2) +{ + if ((addr1 == addr2) || (0 == addr1) || (0 == addr2)) { + abort(); + } + return (64 - __builtin_clzll(addr1 ^ addr2)); +} + +hwaddr align_64k_low(hwaddr addr) +{ + return addr & ~0xffffull; +} + +hwaddr align_64k_high(hwaddr addr) +{ + return (addr + 0xffffull) & ~0xffffull; +} + +uint8_t get_lowest_non_zero_bit_index(hwaddr addr) +{ + if (0 == addr) { + abort(); + } + return __builtin_ctzll(addr); +} + +hwaddr get_low_bits_mask_for_bit_index(uint8_t bit_index) +{ + if (bit_index >= 64) { + abort(); + } + return (1 << bit_index) - 1; +} + +void allocate_ram(MemoryRegion *top, const char *name, hwaddr addr, + hwaddr size) +{ + MemoryRegion *sec = g_new(MemoryRegion, 1); + memory_region_init_ram(sec, NULL, name, size, &error_fatal); + memory_region_add_subregion(top, addr, sec); +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/xnu_pagetable.c b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_pagetable.c new file mode 100644 index 0000000..cfce447 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_pagetable.c @@ -0,0 +1,230 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/arm/xnu_pagetable.h" +#include "hw/loader.h" +#include "qemu/osdep.h" +#include "target/arm/idau.h" +#include "trace.h" +#include "cpu.h" +#include "internals.h" +#include "exec/gdbstub.h" +#include "exec/helper-proto.h" +#include "qemu/host-utils.h" +#include "sysemu/arch_init.h" +#include "sysemu/sysemu.h" +#include "qemu/bitops.h" +#include "qemu/crc32c.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "arm_ldst.h" +#include "hw/semihosting/semihost.h" + +#define PHYS_ADDR_SIZE (40) +#define TG_16K_SIZE (14) +#define PAGE_MASK_16K (~(((uint64_t)1 << TG_16K_SIZE) - 1)) +#define TE_PHYS_ADDR_MASK ((((uint64_t)1 << PHYS_ADDR_SIZE) - 1) & \ + PAGE_MASK_16K) + +#define TG_16KB (1) +#define TG_16KB_LEVEL0_INDEX (47) +#define TG_16KB_LEVEL0_SIZE (1) +#define TG_16KB_LEVEL1_INDEX (36) +#define TG_16KB_LEVEL1_SIZE (11) +#define TG_16KB_LEVEL2_INDEX (25) +#define TG_16KB_LEVEL2_SIZE (11) +#define TG_16KB_LEVEL3_INDEX (14) +#define TG_16KB_LEVEL3_SIZE (11) + +#define TCR_IPS_INDEX (32) +#define TCR_IPS_SIZE (3) +#define TCR_IPS_40_ADDR_SIZE (2) +#define TCR_TG1_INDEX (30) +#define TCR_TG1_SIZE (2) +#define TCR_T1SZ_INDEX (16) +#define TCR_T1SZ_SIZE (6) +#define TCR_TG0_INDEX (14) +#define TCR_TG0_SIZE (2) +#define TCR_T0SZ_INDEX (0) +#define TCR_T0SZ_SIZE (6) + +#define TE_ACCESS_PERMS_INDEX (6) +#define TE_ACCESS_PERMS_SIZE (2) +#define TE_ACCESS_PERMS_MASK ((((uint64_t)1 << TE_ACCESS_PERMS_SIZE) - 1) << \ + TE_ACCESS_PERMS_INDEX) +#define TE_ACCESS_PERMS_ZERO_MASK (~TE_ACCESS_PERMS_MASK) +#define TE_ACCESS_PERMS_KERN_RW (0) +#define TE_XN_INDEX (53) +#define TE_XN_SIZE (2) +#define TE_XN_MASK ((((uint64_t)1 << TE_XN_SIZE) - 1) << TE_XN_INDEX) +#define TE_XN_ZERO_MASK (~TE_XN_MASK) +#define TE_XN_KERN_EXE ((uint64_t)2 << TE_XN_INDEX) +#define TE_TYPE_INDEX (0) +#define TE_TYPE_SIZE (2) +#define TE_TYPE_TABLE_DESC (3) +#define TE_TYPE_L3_BLOCK (3) + +hwaddr pt_tte_el1(ARMCPU *cpu, AddressSpace *as, hwaddr va, bool make_exe) +{ + CPUARMState *env = &cpu->env; + uint64_t tcr = env->cp15.tcr_el[1].raw_tcr; + uint64_t tcr_ips = extract64(tcr, TCR_IPS_INDEX, TCR_IPS_SIZE); + uint64_t tcr_tg1 = extract64(tcr, TCR_TG1_INDEX, TCR_TG1_SIZE); + uint64_t tcr_t1sz = extract64(tcr, TCR_T1SZ_INDEX, TCR_T1SZ_SIZE); + uint64_t tcr_tg0 = extract64(tcr, TCR_TG0_INDEX, TCR_TG0_SIZE); + uint64_t tcr_t0sz = extract64(tcr, TCR_T0SZ_INDEX, TCR_T0SZ_SIZE); + + hwaddr tt = 0; + hwaddr te = 0; + uint64_t tg = 0; + uint64_t tsz = 0; + + //currently only support 40bit addresses configuration + if (TCR_IPS_40_ADDR_SIZE != tcr_ips) { + abort(); + } + //fprintf(stderr, "pt_tte_el1: tcr: 0x%016llx tcr_ips: 0x%016llx tcr_tg1: 0x%016llx tcr_t1sz: 0x%016llx tcr_tg0: %016llx tcr_t0sz: 0x%016llx va: 0x%016llx\n", + // tcr, tcr_ips, tcr_tg1, tcr_t1sz, tcr_tg0, tcr_t0sz, va); + + if (extract64(va, 63, 1) == 1) { + uint64_t one_bits = extract64(va, 64 - tcr_t1sz, tcr_t1sz); + uint64_t one_bits_verify = (1 << tcr_t1sz) - 1; + //fprintf(stderr, "90 pt_tte_el1: te: 0x%016llx\n", te); + if ((one_bits & one_bits_verify) != one_bits_verify) { + fprintf(stderr, "9 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + tt = env->cp15.ttbr1_el[1]; + tg = tcr_tg1; + tsz = tcr_t1sz; + } else { + uint64_t zero_bits = extract64(va, 64 - tcr_t0sz, tcr_t0sz); + //fprintf(stderr, "91 pt_tte_el1: te: 0x%016lx\n", te); + if (0 != zero_bits) { + fprintf(stderr, "10 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + tt = env->cp15.ttbr0_el[1]; + tg = tcr_tg0; + tsz = tcr_t0sz; + } + + //currently only support parsing 16kg granule page tables + if (TG_16KB != tg) { + fprintf(stderr, "8 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + + //currently only support level 1 base entries + if ((tsz < (64 - TG_16KB_LEVEL0_INDEX)) || + (tsz >= (64 - TG_16KB_LEVEL1_INDEX))) { + fprintf(stderr, "7 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + + uint64_t l1_index_size = 64 - tsz - TG_16KB_LEVEL1_INDEX; + uint64_t l1_idx = extract64(va, TG_16KB_LEVEL1_INDEX, l1_index_size); + uint64_t l2_idx = extract64(va, TG_16KB_LEVEL2_INDEX, TG_16KB_LEVEL2_SIZE); + uint64_t l3_idx = extract64(va, TG_16KB_LEVEL3_INDEX, TG_16KB_LEVEL3_SIZE); + + address_space_rw(as, (tt + (sizeof(hwaddr) * l1_idx)), + MEMTXATTRS_UNSPECIFIED, (uint8_t *)&te, sizeof(te), 0); + if (0 == te) { + fprintf(stderr, "6 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + + uint64_t te_type = extract64(te, TE_TYPE_INDEX, TE_TYPE_SIZE); + //currently only support table description level1 entries + if (TE_TYPE_TABLE_DESC != te_type) { + fprintf(stderr, "5 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + + //layer 2 + tt = te & TE_PHYS_ADDR_MASK; + address_space_rw(as, (tt + (sizeof(hwaddr) * l2_idx)), + MEMTXATTRS_UNSPECIFIED, (uint8_t *)&te, sizeof(te), 0); + if (0 == te) { + fprintf(stderr, "4 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + + te_type = extract64(te, TE_TYPE_INDEX, TE_TYPE_SIZE); + //currently only support table description level2 entries + if (TE_TYPE_TABLE_DESC != te_type) { + fprintf(stderr, "3 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + + //layer 3 + tt = te & TE_PHYS_ADDR_MASK; + hwaddr l3_te_addr = tt + (sizeof(hwaddr) * l3_idx); + address_space_rw(as, l3_te_addr, MEMTXATTRS_UNSPECIFIED, (uint8_t *)&te, + sizeof(te), 0); + if (0 == te) { + fprintf(stderr, "2 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + + te_type = extract64(te, TE_TYPE_INDEX, TE_TYPE_SIZE); + //sanity - l3 entries can only be block entries or invalid entries + if (TE_TYPE_L3_BLOCK != te_type) { + fprintf(stderr, "1 pt_tte_el1: te: 0x%016llx\n", te); + abort(); + } + + //fprintf(stderr, "pt_tte_el1: te: 0x%016llx\n", te); + + if (make_exe) { + //fprintf(stderr, "pt_tte_el1: TE_ACCESS_PERMS_ZERO_MASK: 0x%016llx\n", TE_ACCESS_PERMS_ZERO_MASK); + //fprintf(stderr, "pt_tte_el1: TE_XN_ZERO_MASK: 0x%016llx\n", TE_XN_ZERO_MASK); + //fprintf(stderr, "pt_tte_el1: TE_ACCESS_PERMS_KERN_RW: 0x%016llx\n", TE_ACCESS_PERMS_KERN_RW); + //fprintf(stderr, "pt_tte_el1: TE_XN_KERN_EXE: 0x%016llx\n", TE_XN_KERN_EXE); + te &= TE_ACCESS_PERMS_ZERO_MASK & TE_XN_ZERO_MASK; + te |= TE_ACCESS_PERMS_KERN_RW | TE_XN_KERN_EXE; + address_space_rw(as, l3_te_addr, MEMTXATTRS_UNSPECIFIED, + (uint8_t *)&te, sizeof(te), 1); + tlb_flush(CPU(cpu)); + } + + //fprintf(stderr, "pt_tte_el1: te: 0x%016llx\n", te); + + uint64_t page_offset = extract64(va, 0, TG_16K_SIZE); + return (te & TE_PHYS_ADDR_MASK) + page_offset; +} + +void va_make_exec(ARMCPU *cpu, AddressSpace *as, hwaddr va, hwaddr size) +{ + hwaddr curr_va = va & PAGE_MASK_16K; + while (curr_va < va + size) { + pt_tte_el1(cpu, as, curr_va, true); + curr_va += ((uint64_t)1 << TG_16K_SIZE); + } +} diff --git a/xnu-qemu-arm64-5.1.0/hw/arm/xnu_trampoline_hook.c b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_trampoline_hook.c new file mode 100644 index 0000000..2975543 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/arm/xnu_trampoline_hook.c @@ -0,0 +1,521 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/arm/xnu_trampoline_hook.h" +#include "hw/arm/xnu_mem.h" +#include "hw/arm/xnu_pagetable.h" +#include "hw/loader.h" +#include "qemu/osdep.h" +#include "target/arm/idau.h" +#include "trace.h" +#include "cpu.h" +#include "internals.h" +#include "exec/gdbstub.h" +#include "exec/helper-proto.h" +#include "qemu/host-utils.h" +#include "sysemu/arch_init.h" +#include "sysemu/sysemu.h" +#include "qemu/bitops.h" +#include "qemu/crc32c.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "arm_ldst.h" +#include "hw/semihosting/semihost.h" +#include "sysemu/hw_accel.h" + +#define TRAMPOLINE_CODE_INSTS (1024) +#define TRAMPOLINE_CODE_SIZE (TRAMPOLINE_CODE_INSTS * 4) + +#define PAGE_4K_BITS (12) +#define PAGE_4K_MASK (((uint64_t)1 << PAGE_4K_BITS) - 1) +#define PAGE_4K_ALIGN_MASK (~(PAGE_4K_MASK)) + +#define ADRP_IMMLO_SIZE (2) +#define ADRP_IMMLO_MASK (((uint32_t)1 << ADRP_IMMLO_SIZE) - 1) +#define ADRP_IMMLO_SHIFT (29) + +#define ADRP_IMMHI_SIZE (19) +#define ADRP_IMMHI_MASK (((uint32_t)1 << ADRP_IMMHI_SIZE) - 1) +#define ADRP_IMMHI_SHIFT (5) + +#define ADRP_RD_SIZE (5) +#define ADRP_RD_MASK (((uint32_t)1 << ADRP_RD_SIZE) - 1) +#define ADRP_RD_SHIFT (0) + +#define ADD_RN_SIZE (5) +#define ADD_RN_MASK (((uint32_t)1 << ADD_RN_SIZE) - 1) +#define ADD_RN_SHIFT (5) + +#define ADD_RD_SIZE (5) +#define ADD_RD_MASK (((uint32_t)1 << ADD_RD_SIZE) - 1) +#define ADD_RD_SHIFT (0) + +#define ADD_IMM_SIZE (12) +#define ADD_IMM_MASK (((uint32_t)1 << ADD_IMM_SIZE) - 1) +#define ADD_IMM_SHIFT (10) + +#define SUB_RN_SIZE (5) +#define SUB_RN_MASK (((uint32_t)1 << SUB_RN_SIZE) - 1) +#define SUB_RN_SHIFT (5) + +#define SUB_RD_SIZE (5) +#define SUB_RD_MASK (((uint32_t)1 << SUB_RD_SIZE) - 1) +#define SUB_RD_SHIFT (0) + +#define SUB_IMM_SIZE (12) +#define SUB_IMM_MASK (((uint32_t)1 << SUB_IMM_SIZE) - 1) +#define SUB_IMM_SHIFT (10) + +#define STR_64_FP_RN_SIZE (5) +#define STR_64_FP_RN_MASK (((uint32_t)1 << STR_64_FP_RN_SIZE) - 1) +#define STR_64_FP_RN_SHIFT (5) + +#define STR_64_FP_RT_SIZE (5) +#define STR_64_FP_RT_MASK (((uint32_t)1 << STR_64_FP_RT_SIZE) - 1) +#define STR_64_FP_RT_SHIFT (0) + +#define STR_64_FP_IMM_SIZE (12) +#define STR_64_FP_IMM_MASK (((uint32_t)1 << STR_64_FP_IMM_SIZE) - 1) +#define STR_64_FP_IMM_SHIFT (10) + +#define LDR_64_FP_RN_SIZE (5) +#define LDR_64_FP_RN_MASK (((uint32_t)1 << LDR_64_FP_RN_SIZE) - 1) +#define LDR_64_FP_RN_SHIFT (5) + +#define LDR_64_FP_RT_SIZE (5) +#define LDR_64_FP_RT_MASK (((uint32_t)1 << LDR_64_FP_RT_SIZE) - 1) +#define LDR_64_FP_RT_SHIFT (0) + +#define LDR_64_FP_IMM_SIZE (12) +#define LDR_64_FP_IMM_MASK (((uint32_t)1 << LDR_64_FP_IMM_SIZE) - 1) +#define LDR_64_FP_IMM_SHIFT (10) + +#define STP_XT1_SIZE (5) +#define STP_XT1_MASK (((uint32_t)1 << STP_XT1_SIZE) - 1) +#define STP_XT1_SHIFT (0) + +#define STP_XT2_SIZE (5) +#define STP_XT2_MASK (((uint32_t)1 << STP_XT2_SIZE) - 1) +#define STP_XT2_SHIFT (10) + +#define STP_RN_SIZE (5) +#define STP_RN_MASK (((uint32_t)1 << ADD_RN_SIZE) - 1) +#define STP_RN_SHIFT (5) + +#define STP_IMM_SIZE (7) +#define STP_IMM_MASK (((uint32_t)1 << STP_IMM_SIZE) - 1) +#define STP_IMM_SHIFT (15) + +#define LDP_XT1_SIZE (5) +#define LDP_XT1_MASK (((uint32_t)1 << LDP_XT1_SIZE) - 1) +#define LDP_XT1_SHIFT (0) + +#define LDP_XT2_SIZE (5) +#define LDP_XT2_MASK (((uint32_t)1 << LDP_XT2_SIZE) - 1) +#define LDP_XT2_SHIFT (10) + +#define LDP_RN_SIZE (5) +#define LDP_RN_MASK (((uint32_t)1 << LDP_RN_SIZE) - 1) +#define LDP_RN_SHIFT (5) + +#define LDP_IMM_SIZE (7) +#define LDP_IMM_MASK (((uint32_t)1 << LDP_IMM_SIZE) - 1) +#define LDP_IMM_SHIFT (15) + +#define BR_RN_SIZE (5) +#define BR_RN_MASK (((uint32_t)1 << BR_RN_SIZE) - 1) +#define BR_RN_SHIFT (5) + +#define BLR_RN_SIZE (5) +#define BLR_RN_MASK (((uint32_t)1 << BLR_RN_SIZE) - 1) +#define BLR_RN_SHIFT (5) + +static AddressSpace *xnu_hook_tr_as = NULL; +static ARMCPU *xnu_hook_tr_cpu = NULL; + +static uint32_t get_adrp_inst(hwaddr source, hwaddr target, uint8_t reg_id) +{ + //general adrp inst + uint32_t adrp_inst = 0x90000000; + + adrp_inst |= (reg_id & ADRP_RD_MASK) << ADRP_RD_SHIFT; + + hwaddr source_page = source & PAGE_4K_ALIGN_MASK; + hwaddr target_page = target & PAGE_4K_ALIGN_MASK; + + hwaddr adrp_inst_diff_imm = ((target_page - source_page) >> PAGE_4K_BITS); + + adrp_inst |= (adrp_inst_diff_imm & ADRP_IMMLO_MASK) << ADRP_IMMLO_SHIFT; + adrp_inst |= ((adrp_inst_diff_imm >> ADRP_IMMLO_SIZE) & + ADRP_IMMHI_MASK) << ADRP_IMMHI_SHIFT; + + return adrp_inst; +} + +static uint32_t get_add_inst(uint8_t xd, uint8_t xn, hwaddr imm) +{ + //general add inst + uint32_t add_inst = 0x91000000; + + add_inst |= (xn & ADD_RN_MASK) << ADD_RN_SHIFT; + add_inst |= (xd & ADD_RD_MASK) << ADD_RD_SHIFT; + add_inst |= (imm & ADD_IMM_MASK) << ADD_IMM_SHIFT; + + return add_inst; +} + +static uint32_t get_sub_inst(uint8_t xd, uint8_t xn, hwaddr imm) +{ + //general sub inst + uint32_t sub_inst = 0xD1000000; + + sub_inst |= (xn & SUB_RN_MASK) << SUB_RN_SHIFT; + sub_inst |= (xd & SUB_RD_MASK) << SUB_RD_SHIFT; + sub_inst |= (imm & SUB_IMM_MASK) << SUB_IMM_SHIFT; + + return sub_inst; +} + +static uint32_t get_str_64_fp_inst(uint8_t dt, uint8_t xn, hwaddr imm) +{ + //general str inst + uint32_t str_inst = 0xFD000000; + + //has to be devided by 8 + if (imm % 8 != 0) { + abort(); + } + + imm = imm / 8; + + str_inst |= (xn & STR_64_FP_RN_MASK) << STR_64_FP_RN_SHIFT; + str_inst |= (dt & STR_64_FP_RT_MASK) << STR_64_FP_RT_SHIFT; + str_inst |= (imm & STR_64_FP_IMM_MASK) << STR_64_FP_IMM_SHIFT; + + return str_inst; +} + +static uint32_t get_ldr_64_fp_inst(uint8_t dt, uint8_t xn, hwaddr imm) +{ + //general ldr inst + uint32_t ldr_inst = 0xFD400000; + + //has to be devided by 8 + if (imm % 8 != 0) { + abort(); + } + + imm = imm / 8; + + ldr_inst |= (xn & LDR_64_FP_RN_MASK) << LDR_64_FP_RN_SHIFT; + ldr_inst |= (dt & LDR_64_FP_RT_MASK) << LDR_64_FP_RT_SHIFT; + ldr_inst |= (imm & LDR_64_FP_IMM_MASK) << LDR_64_FP_IMM_SHIFT; + + return ldr_inst; +} + +static uint32_t get_stp_inst(uint8_t xt1, uint8_t xt2, uint8_t rn, hwaddr imm) +{ + //general stp inst + uint32_t stp_inst = 0xA9000000; + + //has to be devided by 8 + if (imm % 8 != 0) { + abort(); + } + + imm = imm / 8; + + if ((imm & STP_IMM_MASK) != imm) { + abort(); + } + + stp_inst |= (xt1 & STP_XT1_MASK) << STP_XT1_SHIFT; + stp_inst |= (xt2 & STP_XT2_MASK) << STP_XT2_SHIFT; + stp_inst |= (rn & STP_RN_MASK) << STP_RN_SHIFT; + stp_inst |= (imm & STP_IMM_MASK) << STP_IMM_SHIFT; + + return stp_inst; +} + +static uint32_t get_ldp_inst(uint8_t xt1, uint8_t xt2, uint8_t rn, hwaddr imm) +{ + //general ldp inst + uint32_t ldp_inst = 0xA9400000; + + //has to be devided by 8 + if (imm % 8 != 0) { + abort(); + } + + imm = imm / 8; + + if ((imm & LDP_IMM_MASK) != imm) { + abort(); + } + + ldp_inst |= (xt1 & LDP_XT1_MASK) << LDP_XT1_SHIFT; + ldp_inst |= (xt2 & LDP_XT2_MASK) << LDP_XT2_SHIFT; + ldp_inst |= (rn & LDP_RN_MASK) << LDP_RN_SHIFT; + ldp_inst |= (imm & LDP_IMM_MASK) << LDP_IMM_SHIFT; + + return ldp_inst; +} + +static uint32_t get_br_inst(uint8_t reg_id) +{ + //general br inst + uint32_t br_inst = 0xD61F0000; + + br_inst |= (reg_id & BR_RN_MASK) << BR_RN_SHIFT; + + return br_inst; +} + +static uint32_t get_blr_inst(uint8_t reg_id) +{ + //general blr inst + uint32_t blr_inst = 0xD63F0000; + + blr_inst |= (reg_id & BLR_RN_MASK) << BLR_RN_SHIFT; + + return blr_inst; +} + +void xnu_hook_tr_install(hwaddr va, hwaddr pa, hwaddr cb_va, hwaddr tr_buf_va, + hwaddr tr_buf_pa, uint8_t scratch_reg) +{ + //must run setup before installing hook + if ((NULL == xnu_hook_tr_as) || (NULL == xnu_hook_tr_cpu)) { + abort(); + } + + if ((0 == va) || (0 == pa) || (0 == cb_va) || (0 == tr_buf_va) || + (0 == tr_buf_pa)) { + abort(); + } + + uint32_t backup_insts[3] = {0}; + uint32_t new_insts[3] = {0}; + uint32_t tr_insts[TRAMPOLINE_CODE_INSTS] = {0}; + uint64_t i = 0; + + address_space_rw(xnu_hook_tr_as, pa, MEMTXATTRS_UNSPECIFIED, + (uint8_t *)&backup_insts[0], sizeof(backup_insts), 0); + + new_insts[0] = get_adrp_inst(va, tr_buf_va, scratch_reg); + new_insts[1] = get_add_inst(scratch_reg, scratch_reg, + tr_buf_va & PAGE_4K_MASK); + new_insts[2] = get_br_inst(scratch_reg); + + address_space_rw(xnu_hook_tr_as, pa, MEMTXATTRS_UNSPECIFIED, + (uint8_t *)&new_insts[0], sizeof(new_insts), 1); + + //31 is treated as sp in aarch64 + tr_insts[i++] = get_add_inst(scratch_reg, 31, 0); + tr_insts[i++] = get_sub_inst(scratch_reg ,scratch_reg, 0x200); + + tr_insts[i++] = get_stp_inst(0, 1, scratch_reg, 0); + tr_insts[i++] = get_stp_inst(2, 3, scratch_reg, 0x10); + tr_insts[i++] = get_stp_inst(4, 5, scratch_reg, 0x20); + tr_insts[i++] = get_stp_inst(6, 7, scratch_reg, 0x30); + tr_insts[i++] = get_stp_inst(8, 9, scratch_reg, 0x40); + tr_insts[i++] = get_stp_inst(10, 11, scratch_reg, 0x50); + tr_insts[i++] = get_stp_inst(12, 13, scratch_reg, 0x60); + tr_insts[i++] = get_stp_inst(14, 15, scratch_reg, 0x70); + tr_insts[i++] = get_stp_inst(16, 17, scratch_reg, 0x80); + tr_insts[i++] = get_stp_inst(18, 19, scratch_reg, 0x90); + tr_insts[i++] = get_stp_inst(20, 21, scratch_reg, 0xa0); + tr_insts[i++] = get_stp_inst(22, 23, scratch_reg, 0x30); + tr_insts[i++] = get_stp_inst(24, 25, scratch_reg, 0xb0); + tr_insts[i++] = get_stp_inst(26, 27, scratch_reg, 0xc0); + tr_insts[i++] = get_stp_inst(28, 29, scratch_reg, 0xd0); + tr_insts[i++] = get_stp_inst(0, 30, scratch_reg, 0xe0); + + tr_insts[i++] = get_str_64_fp_inst(0, scratch_reg, 0xf0); + tr_insts[i++] = get_str_64_fp_inst(1, scratch_reg, 0xf8); + tr_insts[i++] = get_str_64_fp_inst(2, scratch_reg, 0x100); + tr_insts[i++] = get_str_64_fp_inst(3, scratch_reg, 0x108); + tr_insts[i++] = get_str_64_fp_inst(4, scratch_reg, 0x110); + tr_insts[i++] = get_str_64_fp_inst(5, scratch_reg, 0x118); + tr_insts[i++] = get_str_64_fp_inst(6, scratch_reg, 0x120); + tr_insts[i++] = get_str_64_fp_inst(7, scratch_reg, 0x128); + tr_insts[i++] = get_str_64_fp_inst(8, scratch_reg, 0x130); + tr_insts[i++] = get_str_64_fp_inst(9, scratch_reg, 0x138); + tr_insts[i++] = get_str_64_fp_inst(10, scratch_reg, 0x140); + tr_insts[i++] = get_str_64_fp_inst(11, scratch_reg, 0x148); + tr_insts[i++] = get_str_64_fp_inst(12, scratch_reg, 0x150); + tr_insts[i++] = get_str_64_fp_inst(13, scratch_reg, 0x158); + tr_insts[i++] = get_str_64_fp_inst(14, scratch_reg, 0x160); + tr_insts[i++] = get_str_64_fp_inst(15, scratch_reg, 0x168); + tr_insts[i++] = get_str_64_fp_inst(16, scratch_reg, 0x170); + tr_insts[i++] = get_str_64_fp_inst(17, scratch_reg, 0x178); + tr_insts[i++] = get_str_64_fp_inst(18, scratch_reg, 0x180); + tr_insts[i++] = get_str_64_fp_inst(19, scratch_reg, 0x188); + tr_insts[i++] = get_str_64_fp_inst(20, scratch_reg, 0x190); + tr_insts[i++] = get_str_64_fp_inst(21, scratch_reg, 0x198); + tr_insts[i++] = get_str_64_fp_inst(22, scratch_reg, 0x1a0); + tr_insts[i++] = get_str_64_fp_inst(23, scratch_reg, 0x1a8); + tr_insts[i++] = get_str_64_fp_inst(24, scratch_reg, 0x1b0); + tr_insts[i++] = get_str_64_fp_inst(25, scratch_reg, 0x1b8); + tr_insts[i++] = get_str_64_fp_inst(26, scratch_reg, 0x1c0); + tr_insts[i++] = get_str_64_fp_inst(27, scratch_reg, 0x1c8); + tr_insts[i++] = get_str_64_fp_inst(28, scratch_reg, 0x1d0); + tr_insts[i++] = get_str_64_fp_inst(29, scratch_reg, 0x1d8); + tr_insts[i++] = get_str_64_fp_inst(30, scratch_reg, 0x1e0); + tr_insts[i++] = get_str_64_fp_inst(31, scratch_reg, 0x1e8); + + tr_insts[i++] = get_sub_inst(31 ,31, 0x200); + + tr_insts[i] = get_adrp_inst(tr_buf_va + (i * 4), cb_va, scratch_reg); + i++; + tr_insts[i++] = get_add_inst(scratch_reg, scratch_reg, + cb_va & PAGE_4K_MASK); + tr_insts[i++] = get_blr_inst(scratch_reg); + + tr_insts[i++] = get_add_inst(scratch_reg, 31, 0); + + tr_insts[i++] = get_ldp_inst(0, 1, scratch_reg, 0); + tr_insts[i++] = get_ldp_inst(2, 3, scratch_reg, 0x10); + tr_insts[i++] = get_ldp_inst(4, 5, scratch_reg, 0x20); + tr_insts[i++] = get_ldp_inst(6, 7, scratch_reg, 0x30); + tr_insts[i++] = get_ldp_inst(8, 9, scratch_reg, 0x40); + tr_insts[i++] = get_ldp_inst(10, 11, scratch_reg, 0x50); + tr_insts[i++] = get_ldp_inst(12, 13, scratch_reg, 0x60); + tr_insts[i++] = get_ldp_inst(14, 15, scratch_reg, 0x70); + tr_insts[i++] = get_ldp_inst(16, 17, scratch_reg, 0x80); + tr_insts[i++] = get_ldp_inst(18, 19, scratch_reg, 0x90); + tr_insts[i++] = get_ldp_inst(20, 21, scratch_reg, 0xa0); + tr_insts[i++] = get_ldp_inst(22, 23, scratch_reg, 0x30); + tr_insts[i++] = get_ldp_inst(24, 25, scratch_reg, 0xb0); + tr_insts[i++] = get_ldp_inst(26, 27, scratch_reg, 0xc0); + tr_insts[i++] = get_ldp_inst(28, 29, scratch_reg, 0xd0); + tr_insts[i++] = get_ldp_inst(0, 30, scratch_reg, 0xe0); + + tr_insts[i++] = get_ldr_64_fp_inst(0, scratch_reg, 0xf0); + tr_insts[i++] = get_ldr_64_fp_inst(1, scratch_reg, 0xf8); + tr_insts[i++] = get_ldr_64_fp_inst(2, scratch_reg, 0x100); + tr_insts[i++] = get_ldr_64_fp_inst(3, scratch_reg, 0x108); + tr_insts[i++] = get_ldr_64_fp_inst(4, scratch_reg, 0x110); + tr_insts[i++] = get_ldr_64_fp_inst(5, scratch_reg, 0x118); + tr_insts[i++] = get_ldr_64_fp_inst(6, scratch_reg, 0x120); + tr_insts[i++] = get_ldr_64_fp_inst(7, scratch_reg, 0x128); + tr_insts[i++] = get_ldr_64_fp_inst(8, scratch_reg, 0x130); + tr_insts[i++] = get_ldr_64_fp_inst(9, scratch_reg, 0x138); + tr_insts[i++] = get_ldr_64_fp_inst(10, scratch_reg, 0x140); + tr_insts[i++] = get_ldr_64_fp_inst(11, scratch_reg, 0x148); + tr_insts[i++] = get_ldr_64_fp_inst(12, scratch_reg, 0x150); + tr_insts[i++] = get_ldr_64_fp_inst(13, scratch_reg, 0x158); + tr_insts[i++] = get_ldr_64_fp_inst(14, scratch_reg, 0x160); + tr_insts[i++] = get_ldr_64_fp_inst(15, scratch_reg, 0x168); + tr_insts[i++] = get_ldr_64_fp_inst(16, scratch_reg, 0x170); + tr_insts[i++] = get_ldr_64_fp_inst(17, scratch_reg, 0x178); + tr_insts[i++] = get_ldr_64_fp_inst(18, scratch_reg, 0x180); + tr_insts[i++] = get_ldr_64_fp_inst(19, scratch_reg, 0x188); + tr_insts[i++] = get_ldr_64_fp_inst(20, scratch_reg, 0x190); + tr_insts[i++] = get_ldr_64_fp_inst(21, scratch_reg, 0x198); + tr_insts[i++] = get_ldr_64_fp_inst(22, scratch_reg, 0x1a0); + tr_insts[i++] = get_ldr_64_fp_inst(23, scratch_reg, 0x1a8); + tr_insts[i++] = get_ldr_64_fp_inst(24, scratch_reg, 0x1b0); + tr_insts[i++] = get_ldr_64_fp_inst(25, scratch_reg, 0x1b8); + tr_insts[i++] = get_ldr_64_fp_inst(26, scratch_reg, 0x1c0); + tr_insts[i++] = get_ldr_64_fp_inst(27, scratch_reg, 0x1c8); + tr_insts[i++] = get_ldr_64_fp_inst(28, scratch_reg, 0x1d0); + tr_insts[i++] = get_ldr_64_fp_inst(29, scratch_reg, 0x1d8); + tr_insts[i++] = get_ldr_64_fp_inst(30, scratch_reg, 0x1e0); + tr_insts[i++] = get_ldr_64_fp_inst(31, scratch_reg, 0x1e8); + + tr_insts[i++] = get_add_inst(31 ,31, 0x200); + + tr_insts[i] = get_adrp_inst(tr_buf_va + (i * 4), + va + sizeof(backup_insts), scratch_reg); + i++; + tr_insts[i++] = get_add_inst(scratch_reg, scratch_reg, + (va + sizeof(backup_insts)) & PAGE_4K_MASK); + tr_insts[i++] = backup_insts[0]; + tr_insts[i++] = backup_insts[1]; + tr_insts[i++] = backup_insts[2]; + tr_insts[i++] = get_br_inst(scratch_reg); + + if (i >= TRAMPOLINE_CODE_INSTS) { + abort(); + } + + address_space_rw(xnu_hook_tr_as, tr_buf_pa, MEMTXATTRS_UNSPECIFIED, + (uint8_t *)&tr_insts[0], sizeof(tr_insts), 1); + + va_make_exec(xnu_hook_tr_cpu, xnu_hook_tr_as, tr_buf_va, + TRAMPOLINE_CODE_SIZE); +} + +void xnu_hook_tr_copy_install(hwaddr va, hwaddr pa, hwaddr buf_va, + hwaddr buf_pa, uint8_t *code, uint64_t code_size, + uint64_t buf_size, uint8_t scratch_reg) +{ + //must run setup before installing hook + if ((NULL == xnu_hook_tr_as) || (NULL == xnu_hook_tr_cpu)) { + abort(); + } + + if ((0 == va) || (0 == pa) || (0 == buf_va) || (0 == buf_pa) || + (NULL == code) || (0 == code_size) || (0 == buf_size)) { + abort(); + } + + if ((code_size + TRAMPOLINE_CODE_SIZE) >= buf_size) { + abort(); + } + + address_space_rw(xnu_hook_tr_as, (buf_pa + TRAMPOLINE_CODE_SIZE), + MEMTXATTRS_UNSPECIFIED, (uint8_t *)code, code_size, 1); + va_make_exec(xnu_hook_tr_cpu, xnu_hook_tr_as, buf_va, buf_size); + xnu_hook_tr_install(va, pa, buf_va + TRAMPOLINE_CODE_SIZE, buf_va, buf_pa, + scratch_reg); +} + +void xnu_hook_tr_setup(AddressSpace *as, ARMCPU *cpu) +{ + //allow setup only once + if ((NULL != xnu_hook_tr_as) || (NULL != xnu_hook_tr_cpu)) { + abort(); + } + + //must setup with a non NULL AddressSpace + if (NULL == as) { + abort(); + } + + //must setup with a non NULL CPU + if (NULL == cpu) { + abort(); + } + + xnu_hook_tr_cpu = cpu; + xnu_hook_tr_as = as; +} diff --git a/xnu-qemu-arm64-5.1.0/hw/display/xnu_ramfb.c b/xnu-qemu-arm64-5.1.0/hw/display/xnu_ramfb.c new file mode 100644 index 0000000..b20609f --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/hw/display/xnu_ramfb.c @@ -0,0 +1,141 @@ +#include "qemu/osdep.h" +#include "hw/loader.h" +#include "hw/qdev-properties.h" +#include "hw/display/xnu_ramfb.h" +#include "ui/console.h" + +#define XNU_RAMFB(obj) \ + OBJECT_CHECK(xnu_ramfb_state, (obj), TYPE_XNU_RAMFB_DEVICE) + +typedef struct display_cfg{ + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t linesize; +} xnu_display_cfg; + +typedef struct xnu_ramfb_state { + SysBusDevice parent_obj; + xnu_display_cfg display_cfg; + QemuConsole* con; + uint8_t* qemu_fb_ptr; //Pointer that will sent to display callbacks + hwaddr fb_pa; + uint32_t fb_size; + hwaddr as; +} xnu_ramfb_state; + +void xnu_ramfb_display_update(void *opaque) +{ + DisplaySurface *ds = NULL; + xnu_ramfb_state *xnu_ramfb = XNU_RAMFB(opaque); + uint32_t format = xnu_ramfb->display_cfg.format; + uint32_t width = xnu_ramfb->display_cfg.width; + uint32_t height = xnu_ramfb->display_cfg.height; + uint32_t linesize = xnu_ramfb->display_cfg.linesize; + QemuConsole *con = xnu_ramfb->con; + hwaddr as = xnu_ramfb->as; + hwaddr fb_pa = xnu_ramfb->fb_pa; + uint32_t fb_size = xnu_ramfb->fb_size; + uint8_t* qemu_fb_ptr = xnu_ramfb->qemu_fb_ptr; + + assert(qemu_fb_ptr != 0); + assert(fb_pa != 0); + + address_space_rw((AddressSpace*) as, fb_pa, MEMTXATTRS_UNSPECIFIED, + qemu_fb_ptr, fb_size, FALSE); + ds = qemu_create_displaysurface_from( + width, height, format, linesize, qemu_fb_ptr); + if (ds) { + dpy_gfx_replace_surface(con, ds); + } + dpy_gfx_update_full(con); +} + +void xnu_display_prolog(xnu_ramfb_state* xnu_fb_state) +{ + //currently empty + return; +} + +void xnu_ramfb_setup(xnu_ramfb_state* xnu_fb_state) +{ + uint8_t* fb_ptr; + xnu_fb_state->display_cfg.format = PIXMAN_LE_r8g8b8; + + if (xnu_fb_state->fb_size == 0){ + fprintf(stderr, + "xnu_ram_fb: size for the framebuffer is zero, aborting...\n"); + abort(); + } + fb_ptr = g_malloc0(xnu_fb_state->fb_size); + if (fb_ptr == NULL){ + fprintf(stderr, + "xnu_ram_fb: failed to allocate memory for the framebuffer.\n"); + abort(); + } + xnu_fb_state->qemu_fb_ptr = fb_ptr; + + xnu_display_prolog(xnu_fb_state); +} + +void xnu_ramfb_free(uint8_t* qemu_fb_ptr) +{ + g_free(qemu_fb_ptr); +} + +static const GraphicHwOps wrapper_ops = { + .gfx_update = xnu_ramfb_display_update, +}; + +static void xnu_ramfb_realizefn(DeviceState *dev, Error **errp) +{ + xnu_ramfb_state *xnu_ramfb = XNU_RAMFB(dev); + xnu_ramfb->con = graphic_console_init(dev, 0, &wrapper_ops, dev); + xnu_ramfb_setup(xnu_ramfb); +} + +static void xnu_ramfb_unrealizefn(DeviceState *dev, Error **errp) +{ + xnu_ramfb_state *xnu_ramfb = XNU_RAMFB(dev); + graphic_console_close(xnu_ramfb->con); + xnu_ramfb_free(xnu_ramfb->qemu_fb_ptr); +} + +static Property xnu_ramfb_properties[] = { + DEFINE_PROP_UINT64("as", xnu_ramfb_state, as, 0), + DEFINE_PROP_UINT64("fb_pa", xnu_ramfb_state, fb_pa, 0), + DEFINE_PROP_UINT32("fb_size", xnu_ramfb_state, fb_size, 0), + DEFINE_PROP_UINT32("display_cfg.width", xnu_ramfb_state, + display_cfg.width, 0), + DEFINE_PROP_UINT32("display_cfg.height", xnu_ramfb_state, + display_cfg.height, 0), + DEFINE_PROP_UINT32("display_cfg.linesize", xnu_ramfb_state, + display_cfg.linesize, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xnu_ramfb_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + dc->realize = xnu_ramfb_realizefn; + dc->unrealize = xnu_ramfb_unrealizefn; + dc->props = xnu_ramfb_properties; + dc->desc = "xnu ram framebuffer"; + dc->user_creatable = true; +} + +static const TypeInfo xnu_ramfb_info = { + .name = TYPE_XNU_RAMFB_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(xnu_ramfb_state), + .class_init = xnu_ramfb_class_initfn, +}; + +static void xnu_ramfb_register_types(void) +{ + type_register_static(&xnu_ramfb_info); +} + +type_init(xnu_ramfb_register_types) diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/fds.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/fds.h new file mode 100644 index 0000000..83a415c --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/fds.h @@ -0,0 +1,67 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_GUEST_SERVICES_FDS_H +#define HW_ARM_GUEST_SERVICES_FDS_H + +#ifndef OUT_OF_TREE_BUILD +#include "qemu/osdep.h" +#else +#include "sys/types.h" +#include "sys/socket.h" +#endif + +#define MAX_FD_COUNT (256) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +extern int32_t guest_svcs_errno; +#pragma GCC diagnostic pop +extern int32_t guest_svcs_fds[MAX_FD_COUNT]; + +#define VERIFY_FD(s) \ + if ((s < 0) || (s >= MAX_FD_COUNT) || (-1 == guest_svcs_fds[s])) return -1; + +typedef struct __attribute__((packed)) { + int32_t fd; +} qc_close_args_t; + +typedef struct __attribute__((packed)) { + int32_t fd; + int32_t cmd; + union { + int32_t flags; + }; +} qc_fcntl_args_t; + +#ifndef OUT_OF_TREE_BUILD +int32_t qc_handle_close(CPUState *cpu, int32_t fd); +int32_t qc_handle_fcntl_getfl(CPUState *cpu, int32_t fd); +int32_t qc_handle_fcntl_setfl(CPUState *cpu, int32_t fd, int32_t flags); +#else +int qc_close(int fd); +int qc_fcntl(int fd, int cmd, ...); +#endif + +#endif // HW_ARM_GUEST_SERVICES_FDS_H diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/file.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/file.h new file mode 100644 index 0000000..bd88591 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/file.h @@ -0,0 +1,69 @@ +/* + * QEMU Host file guest access + * + * Copyright (c) 2020 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_GUEST_SERVICES_FILE_H +#define HW_ARM_GUEST_SERVICES_FILE_H + +#ifndef OUT_OF_TREE_BUILD +#include "qemu/osdep.h" +#else +#include "sys/types.h" +#endif + +#define MAX_FILE_FDS (8) +#define MAX_FILE_TRANSACTION_LEN (0x2000) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +extern int32_t guest_svcs_errno; +#pragma GCC diagnostic pop + +typedef struct __attribute__((packed)) { + uint64_t buffer_guest_ptr; + uint64_t length; + uint64_t offset; + uint64_t index; +} qc_write_file_args_t, qc_read_file_args_t; + +typedef struct __attribute__((packed)) { + uint64_t index; +} qc_size_file_args_t; + +#ifndef OUT_OF_TREE_BUILD +void qc_file_open(uint64_t index, const char *filename); + +int64_t qc_handle_write_file(CPUState *cpu, uint64_t buffer_guest_ptr, + uint64_t length, uint64_t offset, uint64_t index); +int64_t qc_handle_read_file(CPUState *cpu, uint64_t buffer_guest_ptr, + uint64_t length, uint64_t offset, uint64_t index); +int64_t qc_handle_size_file(uint64_t index); +#else +int64_t qc_write_file(void *buffer_guest_ptr, uint64_t length, + uint64_t offset, uint64_t index); +int64_t qc_read_file(void *buffer_guest_ptr, uint64_t length, + uint64_t offset, uint64_t index); +int64_t qc_size_file(uint64_t index); +#endif + +#endif diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/general.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/general.h new file mode 100644 index 0000000..3b07d40 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/general.h @@ -0,0 +1,88 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_GUEST_SERVICES_GENERAL_H +#define HW_ARM_GUEST_SERVICES_GENERAL_H + +#include "hw/arm/guest-services/socket.h" +#include "hw/arm/guest-services/fds.h" +#include "hw/arm/guest-services/file.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +extern int32_t guest_svcs_errno; +#pragma GCC diagnostic pop + +typedef enum { + // File Descriptors API + QC_CLOSE = 0x100, + QC_FCNTL, + + // Socket API + QC_SOCKET = 0x110, + QC_ACCEPT, + QC_BIND, + QC_CONNECT, + QC_LISTEN, + QC_RECV, + QC_SEND, + QC_WRITE_FILE, + QC_READ_FILE, + QC_SIZE_FILE, +} qemu_call_number_t; + +typedef struct __attribute__((packed)) { + // Request + qemu_call_number_t call_number; + union { + // File Descriptors API + qc_close_args_t close; + qc_fcntl_args_t fcntl; + // Socket API + qc_socket_args_t socket; + qc_accept_args_t accept; + qc_bind_args_t bind; + qc_connect_args_t connect; + qc_listen_args_t listen; + qc_recv_args_t recv; + qc_send_args_t send; + qc_write_file_args_t write_file; + qc_read_file_args_t read_file; + qc_size_file_args_t size_file; + } args; + + // Response + int64_t retval; + int64_t error; +} qemu_call_t; + +#ifndef OUT_OF_TREE_BUILD +uint64_t qemu_call_status(CPUARMState *env, const ARMCPRegInfo *ri); +void qemu_call(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value); +#else +uint64_t qemu_call_status(qemu_call_t *qcall); +void qemu_call(qemu_call_t *qcall); +#endif + +#endif // HW_ARM_GUEST_SERVICES_GENERAL_H diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/socket.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/socket.h new file mode 100644 index 0000000..ff98bd8 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/guest-services/socket.h @@ -0,0 +1,96 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_GUEST_SERVICES_SOCKET_H +#define HW_ARM_GUEST_SERVICES_SOCKET_H + +#ifndef OUT_OF_TREE_BUILD +#include "qemu/osdep.h" +#else +#include "sys/types.h" +#include "sys/socket.h" +#endif + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +extern int32_t guest_svcs_errno; +#pragma GCC diagnostic pop + +#define MAX_BUF_SIZE (4096) + +typedef struct __attribute__((packed)) { + int32_t domain; + int32_t type; + int32_t protocol; +} qc_socket_args_t; + +typedef struct __attribute__((packed)) { + int32_t socket; + struct sockaddr *addr; + socklen_t *addrlen; +} qc_accept_args_t; + +typedef struct __attribute__((packed)) { + int32_t socket; + struct sockaddr *addr; + socklen_t addrlen; +} qc_bind_args_t, qc_connect_args_t; + +typedef struct __attribute__((packed)) { + int32_t socket; + int32_t backlog; +} qc_listen_args_t; + +typedef struct __attribute__((packed)) { + int32_t socket; + void *buffer; + size_t length; + int flags; +} qc_recv_args_t, qc_send_args_t; + +#ifndef OUT_OF_TREE_BUILD +int32_t qc_handle_socket(CPUState *cpu, int32_t domain, int32_t type, + int32_t protocol); +int32_t qc_handle_accept(CPUState *cpu, int32_t sckt, struct sockaddr *addr, + socklen_t *addrlen); +int32_t qc_handle_bind(CPUState *cpu, int32_t sckt, struct sockaddr *addr, + socklen_t addrlen); +int32_t qc_handle_connect(CPUState *cpu, int32_t sckt, struct sockaddr *addr, + socklen_t addrlen); +int32_t qc_handle_listen(CPUState *cpu, int32_t sckt, int32_t backlog); +int32_t qc_handle_recv(CPUState *cpu, int32_t sckt, void *buffer, + size_t length, int32_t flags); +int32_t qc_handle_send(CPUState *cpu, int32_t sckt, void *buffer, + size_t length, int32_t flags); +#else +int qc_socket(int domain, int type, int protocol); +int qc_accept(int sckt, struct sockaddr *addr, socklen_t *addrlen); +int qc_bind(int sckt, const struct sockaddr *addr, socklen_t addrlen); +int qc_connect(int sckt, const struct sockaddr *addr, socklen_t addrlen); +int qc_listen(int sckt, int backlog); +ssize_t qc_recv(int sckt, void *buffer, size_t length, int flags); +ssize_t qc_send(int sckt, const void *buffer, size_t length, int flags); +#endif + +#endif // HW_ARM_GUEST_SERVICES_SOCKET_H diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/j273_macos11.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/j273_macos11.h new file mode 100644 index 0000000..3b9e07a --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/j273_macos11.h @@ -0,0 +1,117 @@ +/* + * iPhone 6s plus - n66 - S8000 + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_J273_H +#define HW_ARM_J273_H + +#include "qemu-common.h" +#include "exec/hwaddr.h" +#include "hw/boards.h" +#include "hw/arm/boot.h" +#include "hw/arm/xnu.h" +#include "exec/memory.h" +#include "cpu.h" +#include "sysemu/kvm.h" + +#define MAX_CUSTOM_HOOKS (30) + +#define CUSTOM_HOOKS_GLOBALS_SIZE (0x400) + +#define TYPE_J273 "macos11-j273-a12z" + +#define TYPE_J273_MACHINE MACHINE_TYPE_NAME(TYPE_J273) + +#define J273_MACHINE(obj) \ + OBJECT_CHECK(J273MachineState, (obj), TYPE_J273_MACHINE) + +#define J273_CPREG_VAR_NAME(name) cpreg_##name +#define J273_CPREG_VAR_DEF(name) uint64_t J273_CPREG_VAR_NAME(name) + +typedef struct { + MachineClass parent; +} J273MachineClass; + +typedef struct { + MachineState parent; + uint64_t hook_funcs_count; + hwaddr extra_data_pa; + hwaddr kpc_pa; + hwaddr kbootargs_pa; + hwaddr uart_mmio_pa; + ARMCPU *cpu; + KernelTrHookParams hook; + KernelTrHookParams hook_funcs[MAX_CUSTOM_HOOKS]; + struct arm_boot_info bootinfo; + char ramdisk_filename[1024]; + char kernel_filename[1024]; + char dtb_filename[1024]; + char hook_funcs_cfg[1024 * 1024]; + char driver_filename[1024]; + char qc_file_0_filename[1024]; + char qc_file_1_filename[1024]; + char qc_file_log_filename[1024]; + char kern_args[1024]; + uint16_t tunnel_port; + FileMmioDev ramdisk_file_dev; + bool use_ramfb; + J273_CPREG_VAR_DEF(ARM64_REG_EHID1); + J273_CPREG_VAR_DEF(ARM64_REG_EHID10); + J273_CPREG_VAR_DEF(ARM64_REG_EHID4); + J273_CPREG_VAR_DEF(ARM64_REG_HID11); + J273_CPREG_VAR_DEF(ARM64_REG_HID3); + J273_CPREG_VAR_DEF(ARM64_REG_HID5); + J273_CPREG_VAR_DEF(ARM64_REG_HID4); + J273_CPREG_VAR_DEF(ARM64_REG_HID8); + J273_CPREG_VAR_DEF(ARM64_REG_HID7); + J273_CPREG_VAR_DEF(ARM64_REG_LSU_ERR_STS); + J273_CPREG_VAR_DEF(PMC0); + J273_CPREG_VAR_DEF(PMC1); + J273_CPREG_VAR_DEF(PMCR1); + J273_CPREG_VAR_DEF(PMSR); + J273_CPREG_VAR_DEF(L2ACTLR_EL1); + /* EL2 REGS */ + J273_CPREG_VAR_DEF(ARM64_REG_MIGSTS_EL1); + J273_CPREG_VAR_DEF(ARM64_REG_KERNELKEYLO_EL1); + J273_CPREG_VAR_DEF(ARM64_REG_KERNELKEYHI_EL1); + J273_CPREG_VAR_DEF(ARM64_REG_VMSA_LOCK_EL1); + J273_CPREG_VAR_DEF(APRR_EL0); + J273_CPREG_VAR_DEF(APRR_EL1); + J273_CPREG_VAR_DEF(CTRR_LOCK); + J273_CPREG_VAR_DEF(CTRR_A_LWR_EL1); + J273_CPREG_VAR_DEF(CTRR_A_UPR_EL1); + J273_CPREG_VAR_DEF(CTRR_CTL_EL1); + J273_CPREG_VAR_DEF(APRR_MASK_EN_EL1); + J273_CPREG_VAR_DEF(APRR_MASK_EL0); + J273_CPREG_VAR_DEF(ACC_CTRR_A_LWR_EL2); + J273_CPREG_VAR_DEF(ACC_CTRR_A_UPR_EL2); + J273_CPREG_VAR_DEF(ACC_CTRR_CTL_EL2); + J273_CPREG_VAR_DEF(ACC_CTRR_LOCK_EL2); + J273_CPREG_VAR_DEF(ARM64_REG_CYC_CFG); + J273_CPREG_VAR_DEF(ARM64_REG_CYC_OVRD); + J273_CPREG_VAR_DEF(IPI_SR); + J273_CPREG_VAR_DEF(UPMCR0); + J273_CPREG_VAR_DEF(UPMPCM); +} J273MachineState; + +#endif diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu.h new file mode 100644 index 0000000..b5e696d --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu.h @@ -0,0 +1,157 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_XNU_H +#define HW_ARM_XNU_H + +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "hw/arm/xnu_mem.h" +#include "hw/arm/xnu_trampoline_hook.h" +#include "hw/arm/xnu_dtb.h" +#include "hw/arm/xnu_cpacr.h" +#include "hw/arm/xnu_pagetable.h" +#include "hw/arm/xnu_trampoline_hook.h" +#include "hw/arm/xnu_file_mmio_dev.h" +#include "hw/arm/xnu_fb_cfg.h" + +// pexpert/pexpert/arm64/boot.h +#define xnu_arm64_kBootArgsRevision2 2 /* added boot_args.bootFlags */ +#define xnu_arm64_kBootArgsVersion2 2 +#define xnu_arm64_BOOT_LINE_LENGTH 256 + +#define LC_SEGMENT_64 0x19 +#define LC_UNIXTHREAD 0x5 + +struct segment_command_64 +{ + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t /*vm_prot_t*/ maxprot; + uint32_t /*vm_prot_t*/ initprot; + uint32_t nsects; + uint32_t flags; +}; + +struct mach_header_64 { + uint32_t magic; /* mach magic number identifier */ + uint32_t /*cpu_type_t*/ cputype; /* cpu specifier */ + uint32_t /*cpu_subtype_t*/ cpusubtype; /* machine specifier */ + uint32_t filetype; /* type of file */ + uint32_t ncmds; /* number of load commands */ + uint32_t sizeofcmds; /* the size of all the load commands */ + uint32_t flags; /* flags */ + uint32_t reserved; /* reserved */ +}; + +struct load_command { + uint32_t cmd; /* type of load command */ + uint32_t cmdsize; /* total size of command in bytes */ +}; + +typedef struct xnu_arm64_video_boot_args { + unsigned long v_baseAddr; /* Base address of video memory */ + unsigned long v_display; /* Display Code (if Applicable */ + unsigned long v_rowBytes; /* Number of bytes per pixel row */ + unsigned long v_width; /* Width */ + unsigned long v_height; /* Height */ + unsigned long v_depth; /* Pixel Depth and other parameters */ +} video_boot_args; + +typedef struct xnu_arm64_monitor_boot_args { + uint64_t version; /* structure version - this is version 2 */ + uint64_t virtBase; /* virtual base of memory assigned to the monitor */ + uint64_t physBase; /* physical address corresponding to the virtual base */ + uint64_t memSize; /* size of memory assigned to the monitor */ + uint64_t kernArgs; /* physical address of the kernel boot_args structure */ + uint64_t kernEntry; /* kernel entrypoint */ + uint64_t kernPhysBase; /* physical base of the kernel's address space */ + uint64_t kernPhysSlide; /* offset from kernPhysBase to kernel load address */ + uint64_t kernVirtSlide; /* virtual slide applied to kernel at load time */ +} monitor_boot_args; + +struct xnu_arm64_boot_args { + uint16_t Revision; /* Revision of boot_args structure */ + uint16_t Version; /* Version of boot_args structure */ + uint64_t virtBase; /* Virtual base of memory */ + uint64_t physBase; /* Physical base of memory */ + uint64_t memSize; /* Size of memory */ + uint64_t topOfKernelData; /* Highest physical address used in kernel data area */ + video_boot_args Video; /* Video Information */ + uint32_t machineType; /* Machine Type */ + uint64_t deviceTreeP; /* Base of flattened device tree */ + uint32_t deviceTreeLength; /* Length of flattened tree */ + char CommandLine[xnu_arm64_BOOT_LINE_LENGTH]; /* Passed in command line */ + uint64_t bootFlags; /* Additional flags specified by the bootloader */ + uint64_t memSizeActual; /* Actual size of memory */ +}; + +void macho_file_highest_lowest_base(const char *filename, hwaddr phys_base, + hwaddr *virt_base, hwaddr *lowest, + hwaddr *highest); + +void macho_tz_setup_bootargs(const char *name, AddressSpace *as, + MemoryRegion *mem, hwaddr bootargs_addr, + hwaddr virt_base, hwaddr phys_base, + hwaddr mem_size, hwaddr kern_args, + hwaddr kern_entry, hwaddr kern_phys_base); + +void macho_setup_bootargs(const char *name, AddressSpace *as, + MemoryRegion *mem, hwaddr bootargs_pa, + hwaddr virt_base, hwaddr phys_base, hwaddr mem_size, + hwaddr top_of_kernel_data_pa, hwaddr dtb_va, + hwaddr dtb_size, video_boot_args v_bootargs, + char *kern_args); + +void arm_load_macho(char *filename, AddressSpace *as, MemoryRegion *mem, + const char *name, hwaddr phys_base, hwaddr virt_base, + hwaddr low_virt_addr, hwaddr high_virt_addr, hwaddr *pc, + char *darwin_ver); + +void macho_map_raw_file(const char *filename, AddressSpace *as, MemoryRegion *mem, + const char *name, hwaddr file_pa, uint64_t *size); + +void macho_load_raw_file(const char *filename, AddressSpace *as, MemoryRegion *mem, + const char *name, hwaddr file_pa, uint64_t *size); + +void macho_load_dtb(char *filename, AddressSpace *as, MemoryRegion *mem, + const char *name, hwaddr dtb_pa, uint64_t *size, + hwaddr ramdisk_addr, hwaddr ramdisk_size, + hwaddr *uart_mmio_pa); + +#define MAX_CUSTOM_HOOKS (30) + +#define CUSTOM_HOOKS_GLOBALS_SIZE (0x400) + +typedef struct { + uint8_t hook_code[HOOK_CODE_ALLOC_SIZE]; + uint8_t hook_funcs_code[MAX_CUSTOM_HOOKS][HOOK_CODE_ALLOC_SIZE]; + uint8_t ramfb[RAMFB_SIZE]; + uint8_t hook_globals[CUSTOM_HOOKS_GLOBALS_SIZE]; +} __attribute__((packed)) AllocatedData; +#endif diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_cpacr.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_cpacr.h new file mode 100644 index 0000000..45220eb --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_cpacr.h @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_XNU_CPACR_H +#define HW_ARM_XNU_CPACR_H + +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "cpu.h" + +typedef struct { + uint64_t val; + CPWriteFn *wfn_a64; + CPWriteFn *wfn_a32_ns; + CPWriteFn *wfn_a32_s; +} CpacrIntCtx; + +void xnu_cpacr_intercept_write_const_val(ARMCPU *cpu, uint64_t val); + +#endif diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_dtb.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_dtb.h new file mode 100644 index 0000000..5ae6fa1 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_dtb.h @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_XNU_DTB_H +#define HW_ARM_XNU_DTB_H + +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "hw/arm/xnu_mem.h" + +#define DT_PROP_FLAG_PLACEHOLDER (0x80000000) + +#define DTB_PROP_NAME_LEN (32) + +typedef struct { + uint8_t name[DTB_PROP_NAME_LEN]; + uint32_t length; + uint8_t *value; +} DTBProp; + +typedef struct { + uint32_t prop_count; + uint32_t child_node_count; + GList *props; + GList *child_nodes; +} DTBNode; + +DTBNode *load_dtb(uint8_t *dtb_blob); +void delete_dtb_node(DTBNode *node); +void save_dtb(uint8_t *buf, DTBNode *root); +void remove_dtb_prop(DTBNode *node, DTBProp *prop); +void add_dtb_prop(DTBNode *n, const char *name, uint32_t size, uint8_t *val); +uint64_t get_dtb_node_buffer_size(DTBNode *node); +DTBProp *get_dtb_prop(DTBNode *node, const char *name); +DTBNode *get_dtb_child_node_by_name(DTBNode *node, const char *name); +void overwrite_dtb_prop_val(DTBProp *prop, uint8_t chr); +void overwrite_dtb_prop_name(DTBProp *prop, uint8_t chr); + +#endif diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_fb_cfg.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_fb_cfg.h new file mode 100644 index 0000000..0adb763 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_fb_cfg.h @@ -0,0 +1,17 @@ +#ifndef HW_ARM_XNU_RAMFB_CFG_H +#define HW_ARM_XNU_RAMFB_CFG_H + +#include "qemu/osdep.h" + +#define RAMFB_SIZE 0x2D4C00 + +#define V_DEPTH 16 +#define V_HEIGHT 800 +#define V_WIDTH 600 +#define V_DISPLAY 0 +#define V_LINESIZE (V_WIDTH * 3) + +void xnu_define_ramfb_device(AddressSpace* as, hwaddr ramfb_pa); +void xnu_get_video_bootargs(void *opaque, hwaddr ramfb_pa); + +#endif \ No newline at end of file diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_file_mmio_dev.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_file_mmio_dev.h new file mode 100644 index 0000000..8864b37 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_file_mmio_dev.h @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_FILE_MMIO_DEV_H +#define HW_ARM_FILE_MMIO_DEV_H + +#include "qemu-common.h" +#include "hw/arm/boot.h" + +typedef struct { + hwaddr pa; + hwaddr size; + int fd; +} FileMmioDev; + +void xnu_file_mmio_dev_create(MemoryRegion *sysmem, FileMmioDev *file_dev, + const char *name, const char *filename); + +#endif diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_mem.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_mem.h new file mode 100644 index 0000000..8b2ff6e --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_mem.h @@ -0,0 +1,50 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_XNU_MEM_H +#define HW_ARM_XNU_MEM_H + +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "target/arm/cpu.h" + +extern hwaddr g_virt_base; +extern hwaddr g_phys_base; + +hwaddr vtop_static(hwaddr va); +hwaddr ptov_static(hwaddr pa); +hwaddr vtop_mmu(hwaddr va, CPUState *cs); + +hwaddr align_64k_low(hwaddr addr); +hwaddr align_64k_high(hwaddr addr); + +hwaddr vtop_bases(hwaddr va, hwaddr phys_base, hwaddr virt_base); +hwaddr ptov_bases(hwaddr pa, hwaddr phys_base, hwaddr virt_base); + +uint8_t get_highest_different_bit_index(hwaddr addr1, hwaddr addr2); +uint8_t get_lowest_non_zero_bit_index(hwaddr addr); +hwaddr get_low_bits_mask_for_bit_index(uint8_t bit_index); + +void allocate_ram(MemoryRegion *top, const char *name, hwaddr addr, + hwaddr size); +#endif diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_pagetable.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_pagetable.h new file mode 100644 index 0000000..2bc6fbc --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_pagetable.h @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_XNU_PAGETABLE_H +#define HW_ARM_XNU_PAGETABLE_H + +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "cpu.h" + +hwaddr pt_tte_el1(ARMCPU *cpu, AddressSpace *as, hwaddr va, bool make_exe); +void va_make_exec(ARMCPU *cpu, AddressSpace *as, hwaddr va, hwaddr size); + +#endif diff --git a/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_trampoline_hook.h b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_trampoline_hook.h new file mode 100644 index 0000000..650af10 --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/arm/xnu_trampoline_hook.h @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2019 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_XNU_TRAMPOLINE_HOOK_H +#define HW_ARM_XNU_TRAMPOLINE_HOOK_H + +#include "qemu-common.h" +#include "hw/arm/boot.h" +#include "cpu.h" + +#define HOOK_CODE_ALLOC_SIZE (1 << 20) + +typedef struct { + hwaddr va; + hwaddr pa; + hwaddr buf_va; + hwaddr buf_pa; + uint64_t buf_size; + uint8_t *code; + uint64_t code_size; + uint8_t scratch_reg; +} KernelTrHookParams; + +void xnu_hook_tr_copy_install(hwaddr va, hwaddr pa, hwaddr buf_va, + hwaddr buf_pa, uint8_t *code, uint64_t code_size, + uint64_t buf_size, uint8_t scratch_reg); +void xnu_hook_tr_install(hwaddr va, hwaddr pa, hwaddr cb_va, hwaddr tr_buf_va, + hwaddr tr_buf_pa, uint8_t scratch_reg); +void xnu_hook_tr_setup(AddressSpace *as, ARMCPU *cpu); + +#endif diff --git a/xnu-qemu-arm64-5.1.0/include/hw/display/xnu_ramfb.h b/xnu-qemu-arm64-5.1.0/include/hw/display/xnu_ramfb.h new file mode 100644 index 0000000..3ce5f1a --- /dev/null +++ b/xnu-qemu-arm64-5.1.0/include/hw/display/xnu_ramfb.h @@ -0,0 +1,12 @@ +#ifndef XNU_RAMFB_H +#define XNU_RAMFB_H + +typedef struct xnu_ramfb_state xnu_ramfb_state; +void xnu_ramfb_display_update(void *opaque); +void xnu_ramfb_setup(xnu_ramfb_state* xnu_fb_state); +void xnu_ramfb_free(uint8_t* qemu_fb_ptr); +void xnu_display_prolog(xnu_ramfb_state* xnu_fb_state); + +#define TYPE_XNU_RAMFB_DEVICE "xnu_ramfb" + +#endif /* XNU_RAMFB_H */ diff --git a/xnu-qemu-arm64-5.1.0/target/arm/helper.c b/xnu-qemu-arm64-5.1.0/target/arm/helper.c index 455c92b..6cb6926 100644 --- a/xnu-qemu-arm64-5.1.0/target/arm/helper.c +++ b/xnu-qemu-arm64-5.1.0/target/arm/helper.c @@ -8486,7 +8486,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, case 4: case 5: /* min_EL EL2 */ - mask = PL2_RW; + mask = PL1_RW; break; case 6: /* min_EL EL3 */