Skip to content

Commit 0c6a460

Browse files
committed
arm: boot: macho: pass in boot_args
1 parent 72b770d commit 0c6a460

1 file changed

Lines changed: 72 additions & 3 deletions

File tree

hw/arm/boot.c

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,52 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
921921
return size;
922922
}
923923

924+
// pexpert/pexpert/arm64/boot.h
925+
#define xnu_arm64_kBootArgsRevision2 2 /* added boot_args.bootFlags */
926+
#define xnu_arm64_kBootArgsVersion2 2
927+
#define xnu_arm64_BOOT_LINE_LENGTH 256
928+
struct xnu_arm64_Boot_Video {
929+
unsigned long v_baseAddr; /* Base address of video memory */
930+
unsigned long v_display; /* Display Code (if Applicable */
931+
unsigned long v_rowBytes; /* Number of bytes per pixel row */
932+
unsigned long v_width; /* Width */
933+
unsigned long v_height; /* Height */
934+
unsigned long v_depth; /* Pixel Depth and other parameters */
935+
};
936+
937+
struct xnu_arm64_boot_args {
938+
uint16_t Revision; /* Revision of boot_args structure */
939+
uint16_t Version; /* Version of boot_args structure */
940+
uint64_t virtBase; /* Virtual base of memory */
941+
uint64_t physBase; /* Physical base of memory */
942+
uint64_t memSize; /* Size of memory */
943+
uint64_t topOfKernelData; /* Highest physical address used in kernel data area */
944+
struct xnu_arm64_Boot_Video Video; /* Video Information */
945+
uint32_t machineType; /* Machine Type */
946+
uint64_t deviceTreeP; /* Base of flattened device tree */
947+
uint32_t deviceTreeLength; /* Length of flattened tree */
948+
char CommandLine[xnu_arm64_BOOT_LINE_LENGTH]; /* Passed in command line */
949+
uint64_t bootFlags; /* Additional flags specified by the bootloader */
950+
uint64_t memSizeActual; /* Actual size of memory */
951+
};
952+
953+
static size_t macho_setup_bootargs(struct arm_boot_info *info, AddressSpace *as,
954+
uint64_t bootargs_addr, uint64_t virt_base, uint64_t phys_base, uint64_t top_of_kernel_data) {
955+
struct xnu_arm64_boot_args boot_args;
956+
memset(&boot_args, 0, sizeof(boot_args));
957+
boot_args.Revision = xnu_arm64_kBootArgsRevision2;
958+
boot_args.Version = xnu_arm64_kBootArgsVersion2;
959+
boot_args.virtBase = virt_base;
960+
boot_args.physBase = phys_base;
961+
boot_args.memSize = info->ram_size;
962+
boot_args.topOfKernelData = top_of_kernel_data + 0x10000 /* 16k space for the boot args itself */;
963+
// todo: video, machine type, device tree, cmdline, flags
964+
boot_args.deviceTreeP = 0xdeaddeaddeaddeadull;
965+
boot_args.memSizeActual = info->ram_size;
966+
rom_add_blob_fixed_as("xnu_boot_args", &boot_args, sizeof(boot_args), bootargs_addr, as);
967+
return sizeof(boot_args);
968+
}
969+
924970
static void macho_highest_lowest(struct mach_header_64* mh, uint64_t *lowaddr, uint64_t *highaddr) {
925971
struct load_command* cmd = (struct load_command*)((uint8_t*)mh + sizeof(struct mach_header_64));
926972
// iterate through all the segments once to find highest and lowest addresses
@@ -945,6 +991,8 @@ static void macho_highest_lowest(struct mach_header_64* mh, uint64_t *lowaddr, u
945991
*highaddr = high_addr_temp;
946992
}
947993

994+
#define VAtoPA(addr) (((addr) & 0x3fffffff) + mem_base + kernel_load_offset)
995+
948996
static uint64_t arm_load_macho(struct arm_boot_info *info, uint64_t *pentry, AddressSpace *as)
949997
{
950998
hwaddr kernel_load_offset = 0x00000000;
@@ -963,6 +1011,7 @@ static uint64_t arm_load_macho(struct arm_boot_info *info, uint64_t *pentry, Add
9631011
uint64_t pc = 0;
9641012
uint64_t low_addr_temp;
9651013
uint64_t high_addr_temp;
1014+
uint64_t virt_base = 0;
9661015
macho_highest_lowest(mh, &low_addr_temp, &high_addr_temp);
9671016
uint64_t rom_buf_size = high_addr_temp - low_addr_temp;
9681017
rom_buf = g_malloc0(rom_buf_size);
@@ -971,21 +1020,39 @@ static uint64_t arm_load_macho(struct arm_boot_info *info, uint64_t *pentry, Add
9711020
case LC_SEGMENT_64: {
9721021
struct segment_command_64* segCmd = (struct segment_command_64*)cmd;
9731022
memcpy(rom_buf + (segCmd->vmaddr - low_addr_temp), data + segCmd->fileoff, segCmd->filesize);
1023+
if (virt_base == 0) {
1024+
virt_base = segCmd->vmaddr;
1025+
}
9741026
break;
9751027
}
9761028
case LC_UNIXTHREAD: {
9771029
// grab just the entry point PC
9781030
uint64_t* ptrPc = (uint64_t*)((char*)cmd + 0x110); // for arm64 only.
979-
pc = (*ptrPc & 0x3fffffff) + mem_base + kernel_load_offset;
1031+
pc = VAtoPA(*ptrPc);
9801032
break;
9811033
}
9821034
}
9831035
cmd = (struct load_command*)((char*)cmd + cmd->cmdsize);
9841036
}
985-
hwaddr rom_base = (low_addr_temp & 0x3fffffff) + mem_base + kernel_load_offset;
1037+
hwaddr rom_base = VAtoPA(low_addr_temp);
9861038
rom_add_blob_fixed_as("macho", rom_buf, rom_buf_size, rom_base, as);
987-
*pentry = pc;
9881039
ret = true;
1040+
1041+
// fixup boot args
1042+
// note: device tree and args must follow kernel and be included in the kernel data size.
1043+
// macho_setup_bootargs takes care of adding the size for the args
1044+
// osfmk/arm64/arm_vm_init.c:arm_vm_prot_init
1045+
uint64_t bootargs_addr = VAtoPA(high_addr_temp);
1046+
macho_setup_bootargs(info, as, bootargs_addr, virt_base, VAtoPA(virt_base), VAtoPA(high_addr_temp));
1047+
1048+
// write bootloader
1049+
uint32_t fixupcontext[FIXUP_MAX];
1050+
fixupcontext[FIXUP_ARGPTR] = bootargs_addr;
1051+
fixupcontext[FIXUP_ENTRYPOINT] = pc;
1052+
write_bootloader("bootloader", info->loader_start,
1053+
bootloader_aarch64, fixupcontext, as);
1054+
*pentry = info->loader_start;
1055+
9891056
fprintf(stderr, "%llx %llx %llx\n", low_addr_temp, high_addr_temp, pc);
9901057
fprintf(stderr, "%llx\n", *(uint64_t*)rom_buf);
9911058
out:
@@ -998,6 +1065,8 @@ static uint64_t arm_load_macho(struct arm_boot_info *info, uint64_t *pentry, Add
9981065
return ret? high_addr_temp - low_addr_temp : -1;
9991066
}
10001067

1068+
#undef VAtoPA
1069+
10011070
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
10021071
{
10031072
CPUState *cs;

0 commit comments

Comments
 (0)