historical/m0-applesillicon.git/xnu-qemu-arm64-5.1.0/hw/arm/j273_macos11 backup.c
2024-01-16 11:20:27 -06:00

997 lines
36 KiB
C

/*
* 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)