chainload: BIOS: do not rely on 0x7c00 being free
diff --git a/common/protos/chainload.c b/common/protos/chainload.c
index 5e0040dd..c5c70eef 100644
--- a/common/protos/chainload.c
+++ b/common/protos/chainload.c
@@ -21,7 +21,7 @@
#if defined (BIOS)
__attribute__((noinline, section(".realmode")))
-noreturn static void spinup(uint8_t drive) {
+noreturn static void spinup(uint8_t drive, void *buf) {
struct idtr real_mode_idt;
real_mode_idt.limit = 0x3ff;
real_mode_idt.ptr = 0;
@@ -30,6 +30,14 @@ noreturn static void spinup(uint8_t drive) {
"cli\n\t"
"cld\n\t"
+ // Safe stack location
+ "mov $0x7c00, %%esp\n\t"
+
+ // move buffer to final location
+ "mov $0x7c00, %%edi\n\t"
+ "mov $512, %%ecx\n\t"
+ "rep movsb\n\t"
+
"lidt (%%eax)\n\t"
"pushl $0x08\n\t"
@@ -65,7 +73,7 @@ noreturn static void spinup(uint8_t drive) {
".code32\n\t"
:
- : "a" (&real_mode_idt), "d" (drive)
+ : "a" (&real_mode_idt), "d" (drive), "S"(buf)
: "memory"
);
@@ -177,15 +185,17 @@ load:
void bios_chainload_volume(struct volume *p) {
vga_textmode_init(false);
- volume_read(p, (void *)0x7c00, 0, 512);
+ void *buf = ext_mem_alloc(512);
+
+ volume_read(p, buf, 0, 512);
- volatile uint16_t *boot_sig = (volatile uint16_t *)0x7dfe;
+ uint16_t *boot_sig = (uint16_t *)(buf + 0x1fe);
if (*boot_sig != 0xaa55) {
return;
}
- spinup(p->drive);
+ spinup(p->drive, buf);
}
#elif defined (UEFI)
