@@ -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+
924970static 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+
948996static 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+
10011070void arm_load_kernel (ARMCPU * cpu , struct arm_boot_info * info )
10021071{
10031072 CPUState * cs ;
0 commit comments