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 <towinchenmi@gmail.com>
This commit is contained in:
Nick Chan 2024-08-25 15:30:10 +08:00 committed by Hector Martin
parent 869d2ae35c
commit f4ca3a19fd
6 changed files with 109 additions and 23 deletions

View file

@ -58,7 +58,7 @@ int firmware_set_fdt(void *fdt, int node, const char *prop, const struct fw_vers
return 0; 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); 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; info->iboot = ver;
} }
// Note: semi-open range bool firmware_iboot_in_range(u32 min[IBOOT_VER_COMP], u32 max[IBOOT_VER_COMP],
bool firmware_sfw_in_range(enum fw_version lower_bound, enum fw_version upper_bound) 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; int i;
for (i = 0; i < IBOOT_VER_COMP; i++) for (i = 0; i < IBOOT_VER_COMP; i++)
if (this[i] != min[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]; 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 firmware_init(void)
{ {
int node = adt_path_offset(adt, "/chosen"); int node = adt_path_offset(adt, "/chosen");

View file

@ -5,6 +5,7 @@
#include "types.h" #include "types.h"
/* macOS */
enum fw_version { enum fw_version {
V_UNKNOWN = 0, V_UNKNOWN = 0,
V12_1, V12_1,
@ -48,6 +49,9 @@ extern const struct fw_version_info fw_versions[NUM_FW_VERSIONS];
int firmware_init(void); int firmware_init(void);
int firmware_set_fdt(void *fdt, int node, const char *prop, const struct fw_version_info *ver); 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); 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 #endif

View file

@ -411,7 +411,7 @@ static void mmu_add_default_mappings(void)
* With SPRR enabled, this becomes RW. * With SPRR enabled, this becomes RW.
* This range includes all real RAM, including carveouts * 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 */ /* Unmap carveout regions */
mcc_unmap_carveouts(); mcc_unmap_carveouts();

View file

@ -1,7 +1,9 @@
/* SPDX-License-Identifier: MIT */ /* SPDX-License-Identifier: MIT */
#include "adt.h"
#include "chickens.h" #include "chickens.h"
#include "exception.h" #include "exception.h"
#include "firmware.h"
#include "smp.h" #include "smp.h"
#include "string.h" #include "string.h"
#include "types.h" #include "types.h"
@ -59,8 +61,13 @@ void pan_fixup(void)
sysop("isb"); sysop("isb");
} }
u64 boot_flags, mem_size_actual;
void dump_boot_args(struct boot_args *ba) 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(" revision: %d\n", ba->revision);
printf(" version: %d\n", ba->version); printf(" version: %d\n", ba->version);
printf(" virt_base: 0x%lx\n", ba->virt_base); 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(" machine_type: %d\n", ba->machine_type);
printf(" devtree: %p\n", ba->devtree); printf(" devtree: %p\n", ba->devtree);
printf(" devtree_size: 0x%x\n", ba->devtree_size); printf(" devtree_size: 0x%x\n", ba->devtree_size);
printf(" cmdline: %s\n", ba->cmdline); int node = adt_path_offset(adt, "/chosen");
printf(" boot_flags: 0x%lx\n", ba->boot_flags);
printf(" mem_size_act: 0x%lx\n", ba->mem_size_actual); 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) void _start_c(void *boot_args, void *base)
{ {
UNUSED(base); UNUSED(base);
@ -105,6 +162,8 @@ void _start_c(void *boot_args, void *base)
} }
uart_puts("Initializing"); uart_puts("Initializing");
get_device_info();
printf("CPU init (MIDR: 0x%lx)...\n", mrs(MIDR_EL1)); printf("CPU init (MIDR: 0x%lx)...\n", mrs(MIDR_EL1));
const char *type = init_cpu(); const char *type = init_cpu();
printf(" CPU: %s\n\n", type); printf(" CPU: %s\n\n", type);

View file

@ -452,6 +452,7 @@ extern bool is_mac, has_dcp;
extern bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr; extern bool cpufeat_actlr_el2, cpufeat_fast_ipi, cpufeat_mmu_sprr;
extern struct vector_args next_stage; extern struct vector_args next_stage;
extern u64 boot_flags, mem_size_actual;
void cpu_sleep(bool deep) __attribute__((noreturn)); void cpu_sleep(bool deep) __attribute__((noreturn));
void deep_wfi(void); void deep_wfi(void);

View file

@ -3,7 +3,9 @@
#ifndef XNUBOOT_H #ifndef XNUBOOT_H
#define 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 { struct boot_video {
u64 base; u64 base;
@ -25,9 +27,23 @@ struct boot_args {
u32 machine_type; u32 machine_type;
void *devtree; void *devtree;
u32 devtree_size; u32 devtree_size;
char cmdline[CMDLINE_LENGTH]; union {
u64 boot_flags; struct {
u64 mem_size_actual; 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; extern u64 boot_args_addr;