historical/m0-applesillicon.git/xnu-qemu-arm64-5.1.0.diff
2024-01-16 11:20:27 -06:00

4590 lines
160 KiB
Diff

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 <aronsky@gmail.com>
+ *
+ * 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 <stdarg.h>
+
+#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 <jonyafek@me.com>
+ *
+ * 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 <aronsky@gmail.com>
+ *
+ * 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 <aronsky@gmail.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <aronsky@gmail.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <aronsky@gmail.com>
+ *
+ * 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 <aronsky@gmail.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 <jonyafek@me.com>
+ *
+ * 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 */