mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-10 01:34:12 +00:00
Rework kboot/chainload flow to shut down before calling the next stage
Next stage boots now exit back to main() after replying to the proxy command, allowing shutdown functions to be called. Introduces a new P_VECTOR proxy op, distinct from P_CALL. The Python side is reworked to remain compatible with older versions that do not support this. Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
bcece01769
commit
7dfe24ee2c
11 changed files with 104 additions and 44 deletions
|
@ -127,11 +127,6 @@ if args.el1:
|
||||||
|
|
||||||
print(f"Jumping to stub at 0x{stub.addr:x}")
|
print(f"Jumping to stub at 0x{stub.addr:x}")
|
||||||
|
|
||||||
try:
|
|
||||||
p.mmu_shutdown()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
p.reboot(stub.addr, new_base + bootargs_off, image_addr, new_base, image_size)
|
p.reboot(stub.addr, new_base + bootargs_off, image_addr, new_base, image_size)
|
||||||
|
|
||||||
iface.nop()
|
iface.nop()
|
||||||
|
|
|
@ -206,6 +206,9 @@ class UartInterface:
|
||||||
raise UartRemoteError("Reply error: Unknown error (%d)"%status)
|
raise UartRemoteError("Reply error: Unknown error (%d)"%status)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def wait_boot(self):
|
||||||
|
self.reply(self.REQ_BOOT)
|
||||||
|
|
||||||
def nop(self):
|
def nop(self):
|
||||||
self.cmd(self.REQ_NOP)
|
self.cmd(self.REQ_NOP)
|
||||||
self.reply(self.REQ_NOP)
|
self.reply(self.REQ_NOP)
|
||||||
|
@ -259,12 +262,15 @@ class UartInterface:
|
||||||
class ProxyError(RuntimeError):
|
class ProxyError(RuntimeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ProxyCMDError(ProxyError):
|
class ProxyReplyError(ProxyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ProxyRemoteError(ProxyError):
|
class ProxyRemoteError(ProxyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ProxyCommandError(ProxyRemoteError):
|
||||||
|
pass
|
||||||
|
|
||||||
class AlignmentError(Exception):
|
class AlignmentError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -283,6 +289,7 @@ class M1N1Proxy:
|
||||||
P_GET_EXC_COUNT = 0x008
|
P_GET_EXC_COUNT = 0x008
|
||||||
P_EL0_CALL = 0x009
|
P_EL0_CALL = 0x009
|
||||||
P_EL1_CALL = 0x00a
|
P_EL1_CALL = 0x00a
|
||||||
|
P_VECTOR = 0x00b
|
||||||
|
|
||||||
GUARD_OFF = 0
|
GUARD_OFF = 0
|
||||||
GUARD_SKIP = 1
|
GUARD_SKIP = 1
|
||||||
|
@ -401,10 +408,10 @@ class M1N1Proxy:
|
||||||
if reboot:
|
if reboot:
|
||||||
return
|
return
|
||||||
if rop != opcode:
|
if rop != opcode:
|
||||||
raise ProxyCMDError("Reply opcode mismatch: Expected 0x%08x, got 0x%08x"%(opcode,rop))
|
raise ProxyReplyError("Reply opcode mismatch: Expected 0x%08x, got 0x%08x"%(opcode,rop))
|
||||||
if status != self.S_OK:
|
if status != self.S_OK:
|
||||||
if status == self.S_BADCMD:
|
if status == self.S_BADCMD:
|
||||||
raise ProxyRemoteError("Reply error: Bad Command")
|
raise ProxyCommandError("Reply error: Bad Command")
|
||||||
else:
|
else:
|
||||||
raise ProxyRemoteError("Reply error: Unknown error (%d)"%status)
|
raise ProxyRemoteError("Reply error: Unknown error (%d)"%status)
|
||||||
return retval
|
return retval
|
||||||
|
@ -441,11 +448,18 @@ class M1N1Proxy:
|
||||||
def reboot(self, addr, *args, el1=False):
|
def reboot(self, addr, *args, el1=False):
|
||||||
if len(args) > 4:
|
if len(args) > 4:
|
||||||
raise ValueError("Too many arguments")
|
raise ValueError("Too many arguments")
|
||||||
self.request(self.P_EL1_CALL if el1 else self.P_CALL, addr, *args, reboot=True)
|
if el1:
|
||||||
def vector(self, addr, *args, el1=False):
|
self.request(self.P_EL1_CALL, addr, *args, no_reply=True)
|
||||||
if len(args) > 4:
|
else:
|
||||||
raise ValueError("Too many arguments")
|
try:
|
||||||
self.request(self.P_EL1_CALL if el1 else self.P_CALL, addr, *args, no_reply=True)
|
self.request(self.P_VECTOR, addr, *args)
|
||||||
|
self.iface.wait_boot()
|
||||||
|
except ProxyCommandError: # old m1n1 does not support P_VECTOR
|
||||||
|
try:
|
||||||
|
self.mmu_shutdown()
|
||||||
|
except ProxyCommandError: # older m1n1 does not support MMU
|
||||||
|
pass
|
||||||
|
self.request(self.P_CALL, addr, *args, reboot=True)
|
||||||
def get_bootargs(self):
|
def get_bootargs(self):
|
||||||
return self.request(self.P_GET_BOOTARGS)
|
return self.request(self.P_GET_BOOTARGS)
|
||||||
def get_base(self):
|
def get_base(self):
|
||||||
|
@ -643,7 +657,7 @@ class M1N1Proxy:
|
||||||
self.request(self.P_FREE, ptr)
|
self.request(self.P_FREE, ptr)
|
||||||
|
|
||||||
def kboot_boot(self, kernel):
|
def kboot_boot(self, kernel):
|
||||||
self.request(self.P_KBOOT_BOOT, kernel, no_reply=True)
|
self.request(self.P_KBOOT_BOOT, kernel)
|
||||||
def kboot_set_bootargs(self, bootargs):
|
def kboot_set_bootargs(self, bootargs):
|
||||||
self.request(self.P_KBOOT_SET_BOOTARGS, bootargs)
|
self.request(self.P_KBOOT_SET_BOOTARGS, bootargs)
|
||||||
def kboot_set_initrd(self, base, size):
|
def kboot_set_initrd(self, base, size):
|
||||||
|
|
15
src/kboot.c
15
src/kboot.c
|
@ -27,8 +27,6 @@ static size_t initrd_size = 0;
|
||||||
return -1; \
|
return -1; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
typedef void (*kernel_entry)(void *devtree, u64 rsv1, u64 rsv2, u64 rsv3);
|
|
||||||
|
|
||||||
static int dt_set_chosen(void)
|
static int dt_set_chosen(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -291,12 +289,13 @@ int kboot_prepare_dt(void *fdt)
|
||||||
|
|
||||||
int kboot_boot(void *kernel)
|
int kboot_boot(void *kernel)
|
||||||
{
|
{
|
||||||
mmu_shutdown();
|
printf("Preparing to boot kernel at %p with fdt at %p\n", kernel, dt);
|
||||||
exception_shutdown();
|
|
||||||
|
|
||||||
printf("Booting kernel at %p with fdt at %p\n", kernel, dt);
|
next_stage.entry = kernel;
|
||||||
|
next_stage.args[0] = (u64)dt;
|
||||||
|
next_stage.args[1] = 0;
|
||||||
|
next_stage.args[2] = 0;
|
||||||
|
next_stage.args[3] = 0;
|
||||||
|
|
||||||
((kernel_entry)kernel)(dt, 0, 0, 0);
|
return 0;
|
||||||
|
|
||||||
panic("kernel returned\n");
|
|
||||||
}
|
}
|
||||||
|
|
44
src/main.c
44
src/main.c
|
@ -3,6 +3,7 @@
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
|
|
||||||
#include "adt.h"
|
#include "adt.h"
|
||||||
|
#include "exception.h"
|
||||||
#include "fb.h"
|
#include "fb.h"
|
||||||
#include "heapblock.h"
|
#include "heapblock.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
@ -19,6 +20,8 @@
|
||||||
|
|
||||||
#include "../build/build_tag.h"
|
#include "../build/build_tag.h"
|
||||||
|
|
||||||
|
struct vector_args next_stage;
|
||||||
|
|
||||||
void print_info(void)
|
void print_info(void)
|
||||||
{
|
{
|
||||||
printf("Device info:\n");
|
printf("Device info:\n");
|
||||||
|
@ -42,6 +45,24 @@ void print_info(void)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void run_actions(void)
|
||||||
|
{
|
||||||
|
printf("Checking for payloads...\n");
|
||||||
|
|
||||||
|
if (payload_run() == 0) {
|
||||||
|
printf("Valid payload found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("No valid payload found\n");
|
||||||
|
|
||||||
|
usb_init();
|
||||||
|
|
||||||
|
printf("Running proxy...\n");
|
||||||
|
|
||||||
|
uartproxy_run();
|
||||||
|
}
|
||||||
|
|
||||||
void m1n1_main(void)
|
void m1n1_main(void)
|
||||||
{
|
{
|
||||||
printf("\n\nm1n1 v%s\n", BUILD_TAG);
|
printf("\n\nm1n1 v%s\n", BUILD_TAG);
|
||||||
|
@ -62,17 +83,24 @@ void m1n1_main(void)
|
||||||
wdt_disable();
|
wdt_disable();
|
||||||
pmgr_init();
|
pmgr_init();
|
||||||
|
|
||||||
printf("Checking for payloads...\n");
|
printf("Initialization complete.\n");
|
||||||
|
|
||||||
payload_run();
|
run_actions();
|
||||||
|
|
||||||
printf("No valid payload found\n");
|
if (!next_stage.entry) {
|
||||||
|
panic("Nothing to do!\n");
|
||||||
|
}
|
||||||
|
|
||||||
usb_init();
|
printf("Preparing to run next stage at %p...\n", next_stage.entry);
|
||||||
|
|
||||||
printf("Running proxy...\n");
|
mmu_shutdown();
|
||||||
uartproxy_run();
|
exception_shutdown();
|
||||||
|
usb_shutdown();
|
||||||
|
|
||||||
while (1)
|
printf("Vectoring to next stage...\n");
|
||||||
;
|
|
||||||
|
next_stage.entry(next_stage.args[0], next_stage.args[1], next_stage.args[2],
|
||||||
|
next_stage.args[3]);
|
||||||
|
|
||||||
|
panic("Next stage returned!\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,7 @@ static void *load_one_payload(void *start, size_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void payload_run(void)
|
int payload_run(void)
|
||||||
{
|
{
|
||||||
void *p = _payload_start;
|
void *p = _payload_start;
|
||||||
|
|
||||||
|
@ -178,10 +178,11 @@ void payload_run(void)
|
||||||
|
|
||||||
if (kboot_prepare_dt(fdt)) {
|
if (kboot_prepare_dt(fdt)) {
|
||||||
printf("Failed to prepare FDT!");
|
printf("Failed to prepare FDT!");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
kboot_boot(kernel);
|
return kboot_boot(kernel);
|
||||||
printf("Failed to boot kernel!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
#ifndef __PAYLOAD_H__
|
#ifndef __PAYLOAD_H__
|
||||||
#define __PAYLOAD_H__
|
#define __PAYLOAD_H__
|
||||||
|
|
||||||
void payload_run(void);
|
int payload_run(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
17
src/proxy.c
17
src/proxy.c
|
@ -10,6 +10,7 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "pmgr.h"
|
#include "pmgr.h"
|
||||||
#include "smp.h"
|
#include "smp.h"
|
||||||
|
#include "string.h"
|
||||||
#include "tunables.h"
|
#include "tunables.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
|
@ -23,8 +24,6 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
|
||||||
{
|
{
|
||||||
enum exc_guard_t guard_save = exc_guard;
|
enum exc_guard_t guard_save = exc_guard;
|
||||||
|
|
||||||
callfunc *f;
|
|
||||||
|
|
||||||
reply->opcode = request->opcode;
|
reply->opcode = request->opcode;
|
||||||
reply->status = S_OK;
|
reply->status = S_OK;
|
||||||
reply->retval = 0;
|
reply->retval = 0;
|
||||||
|
@ -33,11 +32,12 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
|
||||||
break;
|
break;
|
||||||
case P_EXIT:
|
case P_EXIT:
|
||||||
return 0;
|
return 0;
|
||||||
case P_CALL:
|
case P_CALL: {
|
||||||
f = (callfunc *)request->args[0];
|
generic_func *f = (generic_func *)request->args[0];
|
||||||
reply->retval =
|
reply->retval =
|
||||||
f(request->args[1], request->args[2], request->args[3], request->args[4]);
|
f(request->args[1], request->args[2], request->args[3], request->args[4]);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case P_GET_BOOTARGS:
|
case P_GET_BOOTARGS:
|
||||||
reply->retval = boot_args_addr;
|
reply->retval = boot_args_addr;
|
||||||
break;
|
break;
|
||||||
|
@ -68,15 +68,17 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
|
||||||
exc_count = 0;
|
exc_count = 0;
|
||||||
break;
|
break;
|
||||||
case P_EL0_CALL:
|
case P_EL0_CALL:
|
||||||
f = (callfunc *)request->args[0];
|
|
||||||
reply->retval = el0_call((void *)request->args[0], request->args[1], request->args[2],
|
reply->retval = el0_call((void *)request->args[0], request->args[1], request->args[2],
|
||||||
request->args[3], request->args[4]);
|
request->args[3], request->args[4]);
|
||||||
break;
|
break;
|
||||||
case P_EL1_CALL:
|
case P_EL1_CALL:
|
||||||
f = (callfunc *)request->args[0];
|
|
||||||
reply->retval = el1_call((void *)request->args[0], request->args[1], request->args[2],
|
reply->retval = el1_call((void *)request->args[0], request->args[1], request->args[2],
|
||||||
request->args[3], request->args[4]);
|
request->args[3], request->args[4]);
|
||||||
break;
|
break;
|
||||||
|
case P_VECTOR:
|
||||||
|
next_stage.entry = (generic_func *)request->args[0];
|
||||||
|
memcpy(next_stage.args, &request->args[1], 4 * sizeof(u64));
|
||||||
|
return 0;
|
||||||
|
|
||||||
case P_WRITE64:
|
case P_WRITE64:
|
||||||
exc_guard = GUARD_SKIP;
|
exc_guard = GUARD_SKIP;
|
||||||
|
@ -301,7 +303,8 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case P_KBOOT_BOOT:
|
case P_KBOOT_BOOT:
|
||||||
kboot_boot((void *)request->args[0]);
|
if (kboot_boot((void *)request->args[0]) == 0)
|
||||||
|
return 0;
|
||||||
break;
|
break;
|
||||||
case P_KBOOT_SET_BOOTARGS:
|
case P_KBOOT_SET_BOOTARGS:
|
||||||
kboot_set_bootargs((void *)request->args[0]);
|
kboot_set_bootargs((void *)request->args[0]);
|
||||||
|
|
|
@ -17,6 +17,7 @@ typedef enum {
|
||||||
P_GET_EXC_COUNT,
|
P_GET_EXC_COUNT,
|
||||||
P_EL0_CALL,
|
P_EL0_CALL,
|
||||||
P_EL1_CALL,
|
P_EL1_CALL,
|
||||||
|
P_VECTOR,
|
||||||
|
|
||||||
P_WRITE64 = 0x100, // Generic register functions
|
P_WRITE64 = 0x100, // Generic register functions
|
||||||
P_WRITE32,
|
P_WRITE32,
|
||||||
|
@ -107,8 +108,6 @@ typedef enum {
|
||||||
#define S_OK 0
|
#define S_OK 0
|
||||||
#define S_BADCMD -1
|
#define S_BADCMD -1
|
||||||
|
|
||||||
typedef u64(callfunc)(u64, u64, u64, u64);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u64 opcode;
|
u64 opcode;
|
||||||
u64 args[6];
|
u64 args[6];
|
||||||
|
|
11
src/usb.c
11
src/usb.c
|
@ -178,3 +178,14 @@ void usb_init(void)
|
||||||
printf("USB%d: initialized at %p\n", i, iodev_usb[i].opaque);
|
printf("USB%d: initialized at %p\n", i, iodev_usb[i].opaque);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usb_shutdown(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < USB_INSTANCES; i++) {
|
||||||
|
if (!iodev_usb[i].opaque)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
printf("USB%d: shutdown\n", i);
|
||||||
|
usb_dwc3_shutdown(iodev_usb[i].opaque);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,5 +9,6 @@
|
||||||
dwc3_dev_t *usb_bringup(u32 idx);
|
dwc3_dev_t *usb_bringup(u32 idx);
|
||||||
|
|
||||||
void usb_init(void);
|
void usb_init(void);
|
||||||
|
void usb_shutdown(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -335,4 +335,13 @@ static inline int poll32(u64 addr, u32 mask, u32 target, u32 timeout)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef u64(generic_func)(u64, u64, u64, u64);
|
||||||
|
|
||||||
|
struct vector_args {
|
||||||
|
generic_func *entry;
|
||||||
|
u64 args[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct vector_args next_stage;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue