From f4ca3a19fd1f1e3f8ae0c578da6703e219f101aa Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Sun, 25 Aug 2024 15:30:10 +0800 Subject: [PATCH] Add support for different boot-args revisions. Boot-args version 1 (iOS 12), and version 3 (iOS 18, macOS 15). Signed-off-by: Nick Chan --- src/firmware.c | 36 ++++++++++++++++------------ src/firmware.h | 4 ++++ src/memory.c | 2 +- src/startup.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++--- src/utils.h | 1 + src/xnuboot.h | 24 +++++++++++++++---- 6 files changed, 109 insertions(+), 23 deletions(-) diff --git a/src/firmware.c b/src/firmware.c index cf14bd34..eeaf8597 100644 --- a/src/firmware.c +++ b/src/firmware.c @@ -58,7 +58,7 @@ int firmware_set_fdt(void *fdt, int node, const char *prop, const struct fw_vers return 0; } -static void parse_version(const char *s, u32 *out) +void firmware_parse_version(const char *s, u32 *out) { memset(out, 0, sizeof(*out) * IBOOT_VER_COMP); @@ -86,21 +86,9 @@ static void detect_firmware(struct fw_version_info *info, const char *ver) info->iboot = ver; } -// Note: semi-open range -bool firmware_sfw_in_range(enum fw_version lower_bound, enum fw_version upper_bound) +bool firmware_iboot_in_range(u32 min[IBOOT_VER_COMP], u32 max[IBOOT_VER_COMP], + u32 this[IBOOT_VER_COMP]) { - u32 min[IBOOT_VER_COMP] = {0}; - u32 max[IBOOT_VER_COMP] = {UINT32_MAX}; - u32 this[IBOOT_VER_COMP] = {0}; - - if (lower_bound > V_UNKNOWN && lower_bound < NUM_FW_VERSIONS) - parse_version(fw_versions[lower_bound].iboot, min); - - if (upper_bound > V_UNKNOWN && upper_bound < NUM_FW_VERSIONS) - parse_version(fw_versions[upper_bound].iboot, max); - - parse_version(system_firmware.iboot, this); - int i; for (i = 0; i < IBOOT_VER_COMP; i++) if (this[i] != min[i]) @@ -116,6 +104,24 @@ bool firmware_sfw_in_range(enum fw_version lower_bound, enum fw_version upper_bo return this[i] < max[i]; } +// Note: semi-open range +bool firmware_sfw_in_range(enum fw_version lower_bound, enum fw_version upper_bound) +{ + u32 min[IBOOT_VER_COMP] = {0}; + u32 max[IBOOT_VER_COMP] = {UINT32_MAX}; + u32 this[IBOOT_VER_COMP] = {0}; + + if (lower_bound > V_UNKNOWN && lower_bound < NUM_FW_VERSIONS) + firmware_parse_version(fw_versions[lower_bound].iboot, min); + + if (upper_bound > V_UNKNOWN && upper_bound < NUM_FW_VERSIONS) + firmware_parse_version(fw_versions[upper_bound].iboot, max); + + firmware_parse_version(system_firmware.iboot, this); + + return firmware_iboot_in_range(min, max, this); +} + int firmware_init(void) { int node = adt_path_offset(adt, "/chosen"); diff --git a/src/firmware.h b/src/firmware.h index dbc4f7aa..610da564 100644 --- a/src/firmware.h +++ b/src/firmware.h @@ -5,6 +5,7 @@ #include "types.h" +/* macOS */ enum fw_version { V_UNKNOWN = 0, V12_1, @@ -48,6 +49,9 @@ extern const struct fw_version_info fw_versions[NUM_FW_VERSIONS]; int firmware_init(void); int firmware_set_fdt(void *fdt, int node, const char *prop, const struct fw_version_info *ver); +bool firmware_iboot_in_range(u32 min[IBOOT_VER_COMP], u32 max[IBOOT_VER_COMP], + u32 this[IBOOT_VER_COMP]); bool firmware_sfw_in_range(enum fw_version lower_bound, enum fw_version upper_bound); +void firmware_parse_version(const char *s, u32 *out); #endif diff --git a/src/memory.c b/src/memory.c index 733cbafa..afccc8de 100644 --- a/src/memory.c +++ b/src/memory.c @@ -411,7 +411,7 @@ static void mmu_add_default_mappings(void) * With SPRR enabled, this becomes RW. * This range includes all real RAM, including carveouts */ - mmu_add_mapping(ram_base, ram_base, cur_boot_args.mem_size_actual, MAIR_IDX_NORMAL, PERM_RWX); + mmu_add_mapping(ram_base, ram_base, mem_size_actual, MAIR_IDX_NORMAL, PERM_RWX); /* Unmap carveout regions */ mcc_unmap_carveouts(); diff --git a/src/startup.c b/src/startup.c index b7670543..70bf2589 100644 --- a/src/startup.c +++ b/src/startup.c @@ -1,7 +1,9 @@ /* SPDX-License-Identifier: MIT */ +#include "adt.h" #include "chickens.h" #include "exception.h" +#include "firmware.h" #include "smp.h" #include "string.h" #include "types.h" @@ -59,8 +61,13 @@ void pan_fixup(void) sysop("isb"); } +u64 boot_flags, mem_size_actual; void dump_boot_args(struct boot_args *ba) { + if (ba->revision > 3) { + printf("Unsupported boot_args revision %hu\n!", ba->revision); + } + printf(" revision: %d\n", ba->revision); printf(" version: %d\n", ba->version); printf(" virt_base: 0x%lx\n", ba->virt_base); @@ -78,11 +85,61 @@ void dump_boot_args(struct boot_args *ba) printf(" machine_type: %d\n", ba->machine_type); printf(" devtree: %p\n", ba->devtree); printf(" devtree_size: 0x%x\n", ba->devtree_size); - printf(" cmdline: %s\n", ba->cmdline); - printf(" boot_flags: 0x%lx\n", ba->boot_flags); - printf(" mem_size_act: 0x%lx\n", ba->mem_size_actual); + int node = adt_path_offset(adt, "/chosen"); + + if (node < 0) { + printf("ADT: no /chosen found\n"); + return; + } + + /* This is called very early - before firmware information is initialized */ + u32 len; + const char *p = adt_getprop(adt, node, "firmware-version", &len); + if (!p) { + printf("ADT: failed to find firmware-version\n"); + return; + } + + uint16_t version = ba->revision; + u32 iboot_min[IBOOT_VER_COMP] = {0}; + u32 iboot_version[IBOOT_VER_COMP] = {0}; + u32 iboot_ba_v1_max[IBOOT_VER_COMP] = {5539}; /* iOS 13 = 5540 */ + + firmware_parse_version(p, iboot_version); + if (firmware_iboot_in_range(iboot_min, iboot_ba_v1_max, iboot_version)) + version = 1; + + switch (version) { + case 1: + printf(" cmdline: %s\n", ba->rv1.cmdline); + printf(" boot_flags: 0x%lx\n", ba->rv1.boot_flags); + printf(" mem_size_act: 0x%lx\n", ba->rv1.mem_size_actual); + boot_flags = ba->rv1.boot_flags; + mem_size_actual = ba->rv1.mem_size_actual; + break; + case 2: + printf(" cmdline: %s\n", ba->rv2.cmdline); + printf(" boot_flags: 0x%lx\n", ba->rv2.boot_flags); + printf(" mem_size_act: 0x%lx\n", ba->rv2.mem_size_actual); + boot_flags = ba->rv2.boot_flags; + mem_size_actual = ba->rv2.mem_size_actual; + break; + case 3: + default: + printf(" cmdline: %s\n", ba->rv3.cmdline); + printf(" boot_flags: 0x%lx\n", ba->rv3.boot_flags); + printf(" mem_size_act: 0x%lx\n", ba->rv3.mem_size_actual); + boot_flags = ba->rv3.boot_flags; + mem_size_actual = ba->rv3.mem_size_actual; + break; + } + if (!mem_size_actual) { + mem_size_actual = ALIGN_UP(ba->phys_base + ba->mem_size - 0x800000000, BIT(30)); + printf("Correcting mem_size_actual to 0x%lx\n", mem_size_actual); + } } +extern void get_device_info(void); void _start_c(void *boot_args, void *base) { UNUSED(base); @@ -105,6 +162,8 @@ void _start_c(void *boot_args, void *base) } uart_puts("Initializing"); + get_device_info(); + printf("CPU init (MIDR: 0x%lx)...\n", mrs(MIDR_EL1)); const char *type = init_cpu(); printf(" CPU: %s\n\n", type); diff --git a/src/utils.h b/src/utils.h index b055f29f..4060641d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -452,6 +452,7 @@ extern bool is_mac, has_dcp; extern bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr; extern struct vector_args next_stage; +extern u64 boot_flags, mem_size_actual; void cpu_sleep(bool deep) __attribute__((noreturn)); void deep_wfi(void); diff --git a/src/xnuboot.h b/src/xnuboot.h index 32623b3e..f713f031 100644 --- a/src/xnuboot.h +++ b/src/xnuboot.h @@ -3,7 +3,9 @@ #ifndef XNUBOOT_H #define XNUBOOT_H -#define CMDLINE_LENGTH 608 +#define CMDLINE_LENGTH_RV1 256 +#define CMDLINE_LENGTH_RV2 608 +#define CMDLINE_LENGTH_RV3 1024 struct boot_video { u64 base; @@ -25,9 +27,23 @@ struct boot_args { u32 machine_type; void *devtree; u32 devtree_size; - char cmdline[CMDLINE_LENGTH]; - u64 boot_flags; - u64 mem_size_actual; + union { + struct { + char cmdline[CMDLINE_LENGTH_RV1]; + u64 boot_flags; + u64 mem_size_actual; + } rv1; + struct { + char cmdline[CMDLINE_LENGTH_RV2]; + u64 boot_flags; + u64 mem_size_actual; + } rv2; + struct { + char cmdline[CMDLINE_LENGTH_RV3]; + u64 boot_flags; + u64 mem_size_actual; + } rv3; + }; }; extern u64 boot_args_addr;