From e386e175507224560d03278adeba42c48a28ecc8 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 9 Mar 2022 20:44:33 +0900 Subject: [PATCH] chainload: Add new m1n1-side chainloader (raw images only) This basically duplicates the chainload.py logic, minus the mach-o handling. Signed-off-by: Hector Martin --- Makefile | 2 + src/chainload.c | 118 ++++++++++++++++++++++++++++++++++++++++++++ src/chainload.h | 11 +++++ src/chainload_asm.S | 20 ++++++++ 4 files changed, 151 insertions(+) create mode 100644 src/chainload.c create mode 100644 src/chainload.h create mode 100644 src/chainload_asm.S diff --git a/Makefile b/Makefile index cf41cc7c..a2f9fbef 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,8 @@ OBJECTS := \ aic.o \ asc.o \ bootlogo_128.o bootlogo_256.o \ + chainload.o \ + chainload_asm.o \ chickens.o \ clk.o \ cpufreq.o \ diff --git a/src/chainload.c b/src/chainload.c new file mode 100644 index 00000000..319b8877 --- /dev/null +++ b/src/chainload.c @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: MIT */ + +#include "chainload.h" +#include "adt.h" +#include "malloc.h" +#include "memory.h" +#include "nvme.h" +#include "string.h" +#include "types.h" +#include "utils.h" +#include "xnuboot.h" + +extern u8 _chainload_stub_start[]; +extern u8 _chainload_stub_end[]; + +int chainload_image(void *image, size_t size, char **vars, size_t var_cnt) +{ + u64 new_base = (u64)_base; + size_t image_size = size; + + printf("chainload: Preparing image...\n"); + + // m1n1 variables + for (size_t i = 0; i < var_cnt; i++) + image_size += strlen(vars[i]) + 1; + + // pad to end payload + image_size += 4; + image_size = ALIGN_UP(image_size, SZ_16K); + size_t kernel_size = image_size; + + // SEPFW + size_t sepfw_off = image_size; + + int anode = adt_path_offset(adt, "/chosen/memory-map"); + if (anode < 0) { + printf("chainload: /chosen/memory-map not found\n"); + return -1; + } + u64 sepfw[2]; + if (ADT_GETPROP_ARRAY(adt, anode, "SEPFW", sepfw) < 0) { + printf("chainload: Failed to find SEPFW\n"); + return -1; + } + + image_size += sepfw[1]; + image_size = ALIGN_UP(image_size, SZ_16K); + + // Bootargs + size_t bootargs_off = image_size; + const size_t bootargs_size = SZ_16K; + image_size += bootargs_size; + + printf("chainload: Total image size: 0x%lx\n", image_size); + + size_t stub_size = _chainload_stub_end - _chainload_stub_start; + + void *new_image = malloc(image_size + stub_size); + + // Copy m1n1 + memcpy(new_image, image, size); + + // Add vars + u8 *p = new_image + size; + for (size_t i = 0; i < var_cnt; i++) { + size_t len = strlen(vars[i]); + + memcpy(p, vars[i], len); + p[len] = '\n'; + p += len + 1; + } + + // Add end padding + memset(p, 0, 4); + + // Copy SEPFW + memcpy(new_image + sepfw_off, (void *)sepfw[0], sepfw[1]); + + // Adjust ADT SEPFW address + sepfw[0] = new_base + sepfw_off; + if (adt_setprop(adt, anode, "SEPFW", &sepfw, sizeof(sepfw)) < 0) { + printf("chainload: Failed to set SEPFW prop\n"); + free(new_image); + return -1; + } + + // Copy bootargs + struct boot_args *new_boot_args = new_image + bootargs_off; + *new_boot_args = cur_boot_args; + new_boot_args->top_of_kernel_data = new_base + kernel_size; + + // Copy chainload stub + void *stub = new_image + image_size; + memcpy(stub, _chainload_stub_start, stub_size); + dc_cvau_range(stub, stub_size); + ic_ivau_range(stub, stub_size); + + // Set up next stage + next_stage.entry = stub; + next_stage.args[0] = new_base + bootargs_off; + next_stage.args[1] = (u64)new_image; + next_stage.args[2] = new_base; + next_stage.args[3] = image_size; + next_stage.args[4] = new_base + 0x800; // m1n1 entrypoint + next_stage.restore_logo = false; + + return 0; +} + +int chainload_load(const char *spec, char **vars, size_t var_cnt) +{ + UNUSED(spec); + UNUSED(vars); + UNUSED(var_cnt); + + printf("Chainloading files not supported in this build!\n"); + return -1; +} diff --git a/src/chainload.h b/src/chainload.h new file mode 100644 index 00000000..206f482b --- /dev/null +++ b/src/chainload.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: MIT */ + +#ifndef __CHAINLOAD_H__ +#define __CHAINLOAD_H__ + +#include "types.h" + +int chainload_image(void *base, size_t size, char **vars, size_t var_cnt); +int chainload_load(const char *spec, char **vars, size_t var_cnt); + +#endif diff --git a/src/chainload_asm.S b/src/chainload_asm.S new file mode 100644 index 00000000..361ec8f4 --- /dev/null +++ b/src/chainload_asm.S @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: MIT */ + +.text + +.globl _chainload_stub_start +.globl _chainload_stub_end +.type _chainload_stub_start, @function + +_chainload_stub_start: +1: + ldp x5, x6, [x1], #16 + stp x5, x6, [x2] + dc cvau, x2 + ic ivau, x2 + add x2, x2, #16 + sub x3, x3, #16 + cbnz x3, 1b + + br x4 +_chainload_stub_end: