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 <marcan@marcan.st>
This commit is contained in:
Hector Martin 2022-03-09 20:44:33 +09:00
parent 0a8a593cdc
commit e386e17550
4 changed files with 151 additions and 0 deletions

View file

@ -61,6 +61,8 @@ OBJECTS := \
aic.o \ aic.o \
asc.o \ asc.o \
bootlogo_128.o bootlogo_256.o \ bootlogo_128.o bootlogo_256.o \
chainload.o \
chainload_asm.o \
chickens.o \ chickens.o \
clk.o \ clk.o \
cpufreq.o \ cpufreq.o \

118
src/chainload.c Normal file
View file

@ -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;
}

11
src/chainload.h Normal file
View file

@ -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

20
src/chainload_asm.S Normal file
View file

@ -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: