Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bac900779 |
No files matched your search
@@ -7,3 +7,4 @@
|
||||
|
||||
CONFIG_ARM_VIRT=y
|
||||
CONFIG_SBSA_REF=y
|
||||
CONFIG_IPHONE_6SPLUS=y
|
||||
@@ -42,3 +42,4 @@ CONFIG_FSL_IMX6UL=y
|
||||
CONFIG_SEMIHOSTING=y
|
||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||
CONFIG_ALLWINNER_H3=y
|
||||
CONFIG_IPHONE_6SPLUS=y
|
||||
@@ -548,3 +548,7 @@ config ARMSSE
|
||||
select UNIMP
|
||||
select SSE_COUNTER
|
||||
select SSE_TIMER
|
||||
|
||||
config IPHONE_6SPLUS
|
||||
bool
|
||||
select IPHONE_6SPLUS
|
||||
@@ -0,0 +1,296 @@
|
||||
#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/iphone6splus.h"
|
||||
|
||||
#define N66_PHYS_BASE (0x40000000)
|
||||
|
||||
#define N66_CPREG_FUNCS(name) \
|
||||
static uint64_t n66_cpreg_read_##name(CPUARMState *env, \
|
||||
const ARMCPRegInfo *ri) \
|
||||
{ \
|
||||
N66MachineState *nms = (N66MachineState *)ri->opaque; \
|
||||
return nms->N66_CPREG_VAR_NAME(name); \
|
||||
} \
|
||||
static void n66_cpreg_write_##name(CPUARMState *env, const ARMCPRegInfo *ri, \
|
||||
uint64_t value) \
|
||||
{ \
|
||||
N66MachineState *nms = (N66MachineState *)ri->opaque; \
|
||||
nms->N66_CPREG_VAR_NAME(name) = value; \
|
||||
}
|
||||
|
||||
#define N66_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 = n66_cpreg_read_##p_name, \
|
||||
.writefn = n66_cpreg_write_##p_name }
|
||||
|
||||
N66_CPREG_FUNCS(ARM64_REG_HID11)
|
||||
N66_CPREG_FUNCS(ARM64_REG_HID3)
|
||||
N66_CPREG_FUNCS(ARM64_REG_HID5)
|
||||
N66_CPREG_FUNCS(ARM64_REG_HID4)
|
||||
N66_CPREG_FUNCS(ARM64_REG_HID8)
|
||||
N66_CPREG_FUNCS(ARM64_REG_HID7)
|
||||
N66_CPREG_FUNCS(ARM64_REG_LSU_ERR_STS)
|
||||
N66_CPREG_FUNCS(PMC0)
|
||||
N66_CPREG_FUNCS(PMC1)
|
||||
N66_CPREG_FUNCS(PMCR1)
|
||||
N66_CPREG_FUNCS(PMSR)
|
||||
|
||||
// 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 n66_cp_reginfo_tcg[] = {
|
||||
// Apple-specific registers
|
||||
N66_CPREG_DEF(ARM64_REG_HID11, 3, 0, 15, 13, 0, PL1_RW),
|
||||
N66_CPREG_DEF(ARM64_REG_HID3, 3, 0, 15, 3, 0, PL1_RW),
|
||||
N66_CPREG_DEF(ARM64_REG_HID5, 3, 0, 15, 5, 0, PL1_RW),
|
||||
N66_CPREG_DEF(ARM64_REG_HID4, 3, 0, 15, 4, 0, PL1_RW),
|
||||
N66_CPREG_DEF(ARM64_REG_HID8, 3, 0, 15, 8, 0, PL1_RW),
|
||||
N66_CPREG_DEF(ARM64_REG_HID7, 3, 0, 15, 7, 0, PL1_RW),
|
||||
N66_CPREG_DEF(ARM64_REG_LSU_ERR_STS, 3, 3, 15, 0, 0, PL1_RW),
|
||||
N66_CPREG_DEF(PMC0, 3, 2, 15, 0, 0, PL1_RW),
|
||||
N66_CPREG_DEF(PMC1, 3, 2, 15, 1, 0, PL1_RW),
|
||||
N66_CPREG_DEF(PMCR1, 3, 1, 15, 1, 0, PL1_RW),
|
||||
N66_CPREG_DEF(PMSR, 3, 1, 15, 13, 0, PL1_RW),
|
||||
REGINFO_SENTINEL,
|
||||
};
|
||||
|
||||
static void n66_add_cpregs(N66MachineState *nms)
|
||||
{
|
||||
ARMCPU *cpu = nms->cpu;
|
||||
|
||||
nms->N66_CPREG_VAR_NAME(ARM64_REG_HID11) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(ARM64_REG_HID3) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(ARM64_REG_HID5) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(ARM64_REG_HID8) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(ARM64_REG_HID7) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(ARM64_REG_LSU_ERR_STS) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(PMC0) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(PMC1) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(PMCR1) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(PMSR) = 0;
|
||||
nms->N66_CPREG_VAR_NAME(L2ACTLR_EL1) = 0;
|
||||
|
||||
define_arm_cp_regs_with_opaque(cpu, n66_cp_reginfo_tcg, nms);
|
||||
}
|
||||
|
||||
static void n66_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};
|
||||
N66MachineState *nms = N66_MACHINE(machine);
|
||||
|
||||
//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, N66_PHYS_BASE,
|
||||
&virt_base, &kernel_low, &kernel_high);
|
||||
|
||||
g_virt_base = virt_base;
|
||||
g_phys_base = N66_PHYS_BASE;
|
||||
phys_ptr = N66_PHYS_BASE;
|
||||
|
||||
//now account for the loaded kernel
|
||||
arm_load_macho(nms->kernel_filename, nsas, sysmem, "kernel.n66",
|
||||
N66_PHYS_BASE, virt_base, kernel_low,
|
||||
kernel_high, &phys_pc);
|
||||
nms->kpc_pa = phys_pc;
|
||||
used_ram_for_blobs += (align_64k_high(kernel_high) - kernel_low);
|
||||
|
||||
phys_ptr = align_64k_high(vtop_static(kernel_high));
|
||||
|
||||
// TODO load other stuff
|
||||
|
||||
//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;
|
||||
|
||||
// TODO ramfb
|
||||
|
||||
//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 - N66_PHYS_BASE + remaining_mem_size;
|
||||
macho_setup_bootargs("k_bootargs.n66", nsas, sysmem, kbootargs_pa,
|
||||
virt_base, N66_PHYS_BASE, mem_size,
|
||||
top_of_kernel_data_pa, dtb_va, dtb_size,
|
||||
v_bootargs, nms->kern_args);
|
||||
|
||||
allocate_ram(sysmem, "n66.ram", allocated_ram_pa, remaining_mem_size);
|
||||
}
|
||||
|
||||
static void n66_memory_setup(MachineState *machine,
|
||||
MemoryRegion *sysmem,
|
||||
MemoryRegion *secure_sysmem,
|
||||
AddressSpace *nsas)
|
||||
{
|
||||
n66_ns_memory_setup(machine, sysmem, nsas);
|
||||
}
|
||||
|
||||
static void n66_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 n66_cpu_reset(void *opaque)
|
||||
{
|
||||
N66MachineState *nms = N66_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;
|
||||
}
|
||||
|
||||
static void n66_machine_init(MachineState *machine)
|
||||
{
|
||||
N66MachineState *nms = N66_MACHINE(machine);
|
||||
MemoryRegion *sysmem;
|
||||
MemoryRegion *secure_sysmem;
|
||||
AddressSpace *nsas;
|
||||
ARMCPU *cpu;
|
||||
CPUState *cs;
|
||||
DeviceState *cpudev;
|
||||
|
||||
n66_cpu_setup(machine, &sysmem, &secure_sysmem, &cpu, &nsas);
|
||||
|
||||
nms->cpu = cpu;
|
||||
|
||||
n66_memory_setup(machine, sysmem, secure_sysmem, nsas);
|
||||
|
||||
// TODO finish
|
||||
|
||||
n66_add_cpregs(nms);
|
||||
|
||||
// TODO finish
|
||||
|
||||
qemu_register_reset(n66_cpu_reset, nms);
|
||||
}
|
||||
|
||||
static void n66_set_kernel_filename(Object *obj, const char *value,
|
||||
Error **errp)
|
||||
{
|
||||
N66MachineState *nms = N66_MACHINE(obj);
|
||||
|
||||
g_strlcpy(nms->kernel_filename, value, sizeof(nms->kernel_filename));
|
||||
}
|
||||
|
||||
static char *n66_get_kernel_filename(Object *obj, Error **errp)
|
||||
{
|
||||
N66MachineState *nms = N66_MACHINE(obj);
|
||||
return g_strdup(nms->kernel_filename);
|
||||
}
|
||||
|
||||
static void n66_set_kern_args(Object *obj, const char *value,
|
||||
Error **errp)
|
||||
{
|
||||
N66MachineState *nms = N66_MACHINE(obj);
|
||||
|
||||
g_strlcpy(nms->kern_args, value, sizeof(nms->kern_args));
|
||||
}
|
||||
|
||||
static char *n66_get_kern_args(Object *obj, Error **errp)
|
||||
{
|
||||
N66MachineState *nms = N66_MACHINE(obj);
|
||||
return g_strdup(nms->kern_args);
|
||||
}
|
||||
|
||||
static void n66_instance_init(Object *obj)
|
||||
{
|
||||
object_property_add_str(obj, "kernel-filename", n66_get_kernel_filename, n66_set_kernel_filename);
|
||||
object_property_set_description(obj, "kernel-filename", "Set the kernel filename");
|
||||
|
||||
object_property_add_str(obj, "kern-cmd-args", n66_get_kern_args, n66_set_kern_args);
|
||||
object_property_set_description(obj, "kern-cmd-args", "Set the XNU kernel cmd args");
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void n66_machine_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(klass);
|
||||
mc->desc = "iPhone 6s plus (n66 - s8000)";
|
||||
mc->init = n66_machine_init;
|
||||
mc->max_cpus = 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 n66_machine_info = {
|
||||
.name = TYPE_N66_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(N66MachineState),
|
||||
.class_size = sizeof(N66MachineClass),
|
||||
.class_init = n66_machine_class_init,
|
||||
.instance_init = n66_instance_init,
|
||||
};
|
||||
|
||||
static void n66_machine_types(void)
|
||||
{
|
||||
type_register_static(&n66_machine_info);
|
||||
}
|
||||
|
||||
type_init(n66_machine_types)
|
||||
@@ -58,5 +58,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.
|
||||
arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c'))
|
||||
arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
|
||||
arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
|
||||
arm_ss.add(when: 'CONFIG_IPHONE_6SPLUS', if_true: files('iphone6splus.c', 'xnu.c', 'xnu_mem.c'))
|
||||
|
||||
hw_arch += {'arm': arm_ss}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
#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_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)
|
||||
{
|
||||
uint8_t *data = NULL;
|
||||
gsize len;
|
||||
uint8_t* rom_buf = NULL;
|
||||
|
||||
if (!g_file_get_contents(filename, (char **)&data, &len, NULL)) {
|
||||
abort();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#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);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef HW_ARM_N66_H
|
||||
#define HW_ARM_N66_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 TYPE_N66 "iPhone6splus-n66-s8000"
|
||||
|
||||
#define TYPE_N66_MACHINE MACHINE_TYPE_NAME(TYPE_N66)
|
||||
|
||||
#define N66_MACHINE(obj) \
|
||||
OBJECT_CHECK(N66MachineState, (obj), TYPE_N66_MACHINE)
|
||||
|
||||
#define N66_CPREG_VAR_NAME(name) cpreg_##name
|
||||
#define N66_CPREG_VAR_DEF(name) uint64_t N66_CPREG_VAR_NAME(name)
|
||||
|
||||
typedef struct {
|
||||
MachineClass parent;
|
||||
} N66MachineClass;
|
||||
|
||||
typedef struct {
|
||||
MachineState parent;
|
||||
hwaddr extra_data_pa;
|
||||
hwaddr kpc_pa;
|
||||
hwaddr kbootargs_pa;
|
||||
ARMCPU *cpu;
|
||||
char kernel_filename[1024];
|
||||
char kern_args[1024];
|
||||
N66_CPREG_VAR_DEF(ARM64_REG_HID11);
|
||||
N66_CPREG_VAR_DEF(ARM64_REG_HID3);
|
||||
N66_CPREG_VAR_DEF(ARM64_REG_HID5);
|
||||
N66_CPREG_VAR_DEF(ARM64_REG_HID4);
|
||||
N66_CPREG_VAR_DEF(ARM64_REG_HID8);
|
||||
N66_CPREG_VAR_DEF(ARM64_REG_HID7);
|
||||
N66_CPREG_VAR_DEF(ARM64_REG_LSU_ERR_STS);
|
||||
N66_CPREG_VAR_DEF(PMC0);
|
||||
N66_CPREG_VAR_DEF(PMC1);
|
||||
N66_CPREG_VAR_DEF(PMCR1);
|
||||
N66_CPREG_VAR_DEF(PMSR);
|
||||
N66_CPREG_VAR_DEF(L2ACTLR_EL1);
|
||||
} N66MachineState;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
#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"
|
||||
|
||||
// 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;
|
||||
|
||||
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_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);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#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
|
||||
Reference in new issue
Block a user