[bootloader] Added dual boot

This commit is contained in:
M4x1m3
2022-02-27 00:05:30 +01:00
parent 85ef57f7ed
commit 5a7b076ebe
13 changed files with 226 additions and 32 deletions

View File

@@ -1,8 +1,10 @@
bootloader_src += $(addprefix bootloader/,\
boot.cpp \
main.cpp \
kernel_header.cpp \
userland_header.cpp \
slot.cpp \
interface.cpp \
jump_to_firmware.s \
trampoline.cpp \

52
bootloader/boot.cpp Normal file
View File

@@ -0,0 +1,52 @@
#include <bootloader/boot.h>
#include <bootloader/slot.h>
#include <ion.h>
#include <bootloader/interface.h>
#include <assert.h>
namespace Bootloader {
BootMode Boot::mode() {
// We use the exam mode driver as storage for the boot mode
uint8_t mode = Ion::ExamMode::FetchExamMode();
if (mode > 3)
return Unknown;
return (BootMode) mode;
}
void Boot::setMode(BootMode mode) {
BootMode currentMode = Boot::mode();
if (currentMode == mode)
return;
assert(mode != BootMode::Unknown);
int8_t deltaMode = (int8_t)mode - (int8_t)currentMode;
deltaMode = deltaMode < 0 ? deltaMode + 4 : deltaMode;
assert(deltaMode > 0);
Ion::ExamMode::IncrementExamMode(deltaMode);
}
[[ noreturn ]] void Boot::boot() {
assert(mode() != BootMode::Unknown);
if (mode() == BootMode::SlotA)
Slot::A().boot();
else if (mode() == BootMode::SlotB)
Slot::B().boot();
for(;;);
}
[[ noreturn ]] void Boot::bootloader() {
Bootloader::Interface::draw();
for(;;) {
Ion::USB::enable();
while (!Ion::USB::isEnumerated());
Ion::USB::DFU(false);
}
}
}

28
bootloader/boot.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef BOOTLOADER_BOOT_H
#define BOOTLOADER_BOOT_H
#include <stdint.h>
namespace Bootloader {
enum BootMode: uint8_t {
SlotA = 0,
SlotB = 1,
// These modes exists so that you can launch the bootloader from a running slot
// They mean "Launch bootloader then go back to slot X"
SlotABootloader = 2,
SlotBBootloader = 3,
Unknown
};
class Boot {
public:
static BootMode mode();
static void setMode(BootMode mode);
[[ noreturn ]] static void boot();
[[ norteurn ]] static void bootloader();
};
}
#endif

View File

@@ -2,7 +2,9 @@
#include <assert.h>
#include <ion.h>
#include "interface.h"
#include <bootloader/interface.h>
#include <bootloader/slot.h>
#include <bootloader/boot.h>
#include "computer.h"
#include "cable.h"
@@ -42,6 +44,36 @@ void Interface::draw() {
KDContext * ctx = KDIonContext::sharedContext();
drawImage(ctx, ImageStore::Computer, 70);
drawImage(ctx, ImageStore::Cable, 172);
ctx->drawString("Slot A:", KDPoint(0, 0), KDFont::SmallFont, KDColorWhite, KDColorBlack);
ctx->drawString("Slot B:", KDPoint(0, 13), KDFont::SmallFont, KDColorWhite, KDColorBlack);
ctx->drawString("Current:", KDPoint(0, 26), KDFont::SmallFont, KDColorWhite, KDColorBlack);
if (Boot::mode() == BootMode::SlotA) {
ctx->drawString("Slot A", KDPoint(63, 26), KDFont::SmallFont, KDColorWhite, KDColorBlack);
} else if (Boot::mode() == BootMode::SlotB) {
ctx->drawString("Slot B", KDPoint(63, 26), KDFont::SmallFont, KDColorWhite, KDColorBlack);
}
Slot slots[2] = {Slot::A(), Slot::B()};
for(uint8_t i = 0; i < 2; i++) {
Slot slot = slots[i];
if (slot.kernelHeader()->isValid() && slot.userlandHeader()->isValid()) {
if (slot.userlandHeader()->isOmega()) {
ctx->drawString("Omega", KDPoint(56, i*13), KDFont::SmallFont, KDColorWhite, KDColorBlack);
ctx->drawString(slot.userlandHeader()->omegaVersion(), KDPoint(112, i*13), KDFont::SmallFont, KDColorWhite, KDColorBlack);
} else {
ctx->drawString("Epsilon", KDPoint(56, i*13), KDFont::SmallFont, KDColorWhite, KDColorBlack);
ctx->drawString(slot.userlandHeader()->version(), KDPoint(112, i*13), KDFont::SmallFont, KDColorWhite, KDColorBlack);
}
ctx->drawString(slot.kernelHeader()->patchLevel(), KDPoint(168, i*13), KDFont::SmallFont, KDColorWhite, KDColorBlack);
} else {
ctx->drawString("Invalid", KDPoint(56, i*13), KDFont::SmallFont, KDColorWhite, KDColorBlack);
}
}
}
}

View File

@@ -1,13 +1,7 @@
#include <bootloader/kernel_header.h>
extern "C" void jump_to_firmware(const uint32_t* stackPtr, const void(*startPtr)(void));
namespace Bootloader {
const KernelHeader* s_kernelHeaderA = reinterpret_cast<const struct KernelHeader*>(0x90000000);
const KernelHeader* s_kernelHeaderB = reinterpret_cast<const struct KernelHeader*>(0x90400000);
const char * KernelHeader::version() const {
return m_version;
}
@@ -20,10 +14,12 @@ const bool KernelHeader::isValid() const {
return m_header == Magic && m_footer == Magic;
}
[[ noreturn ]] void KernelHeader::boot() const {
jump_to_firmware(m_stackPointer, m_startPointer);
for(;;);
const uint32_t* KernelHeader::stackPointer() const {
return m_stackPointer;
}
const void(*KernelHeader::startPointer() const)() {
return m_startPointer;
}
}

View File

@@ -10,7 +10,9 @@ public:
const char * version() const;
const char * patchLevel() const;
const bool isValid() const;
[[ noreturn ]] void boot() const;
const uint32_t* stackPointer() const;
const void(*startPointer() const)();
private:
KernelHeader();
@@ -25,9 +27,6 @@ private:
const void(*m_startPointer)();
};
extern const KernelHeader* s_kernelHeaderA;
extern const KernelHeader* s_kernelHeaderB;
}
#endif

View File

@@ -1,10 +1,9 @@
#include <ion.h>
#include <bootloader/kernel_header.h>
#include <assert.h>
#include <ion/src/device/shared/drivers/board.h>
#include "interface.h"
#include <bootloader/boot.h>
void ion_main(int argc, const char * const argv[]) {
// Clear the screen
@@ -12,18 +11,27 @@ void ion_main(int argc, const char * const argv[]) {
// Initialize the backlight
Ion::Backlight::init();
if (Bootloader::Boot::mode() == Bootloader::BootMode::Unknown)
Bootloader::Boot::setMode(Bootloader::BootMode::SlotA);
if (Bootloader::Boot::mode() == Bootloader::BootMode::SlotABootloader) {
Bootloader::Boot::setMode(Bootloader::BootMode::SlotA);
Bootloader::Boot::bootloader();
} else if (Bootloader::Boot::mode() == Bootloader::BootMode::SlotBBootloader) {
Bootloader::Boot::setMode(Bootloader::BootMode::SlotB);
Bootloader::Boot::bootloader();
}
uint64_t scan = Ion::Keyboard::scan();
if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::Four)) {
Bootloader::Interface::draw();
while (true) {
Ion::USB::enable();
while (!Ion::USB::isEnumerated()) {
}
Ion::USB::DFU(false);
}
Bootloader::Boot::bootloader();
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::One)) {
Bootloader::Boot::setMode(Bootloader::BootMode::SlotA);
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::Two)) {
Bootloader::Boot::setMode(Bootloader::BootMode::SlotB);
}
Ion::Device::Board::bootloaderMPU();
Bootloader::s_kernelHeaderA->boot();
Bootloader::Boot::boot();
}

28
bootloader/slot.cpp Normal file
View File

@@ -0,0 +1,28 @@
#include <bootloader/slot.h>
extern "C" void jump_to_firmware(const uint32_t* stackPtr, const void(*startPtr)(void));
namespace Bootloader {
const Slot Slot::A() {
return Slot(0x90000000);
}
const Slot Slot::B() {
return Slot(0x90400000);
}
const KernelHeader* Slot::kernelHeader() const {
return m_kernelHeader;
}
const UserlandHeader* Slot::userlandHeader() const {
return m_userlandHeader;
}
[[ noreturn ]] void Slot::boot() const {
jump_to_firmware(kernelHeader()->stackPointer(), kernelHeader()->startPointer());
for(;;);
}
}

33
bootloader/slot.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef BOOTLOADER_SLOT_H
#define BOOTLOADER_SLOT_H
#include <stdint.h>
#include "kernel_header.h"
#include "userland_header.h"
namespace Bootloader {
class Slot {
public:
Slot(uint32_t address) :
m_kernelHeader(reinterpret_cast<KernelHeader*>(address)),
m_userlandHeader(reinterpret_cast<UserlandHeader*>(address + 64 * 1024)) { }
const KernelHeader* kernelHeader() const;
const UserlandHeader* userlandHeader() const;
[[ noreturn ]] void boot() const;
static const Slot A();
static const Slot B();
private:
const KernelHeader* m_kernelHeader;
const UserlandHeader* m_userlandHeader;
};
}
#endif

View File

@@ -3,7 +3,7 @@
#include <ion/src/device/shared/drivers/flash.h>
#include <ion/src/device/n0110/drivers/power.h>
#include "trampoline.h"
#include <bootloader/trampoline.h>
namespace Bootloader {

View File

@@ -17,4 +17,9 @@ const bool UserlandHeader::isOmega() const {
return m_ohm_header == OmegaMagic && m_ohm_footer == OmegaMagic;
}
const char * UserlandHeader::omegaVersion() const {
return m_omegaVersion;
}
}

View File

@@ -12,6 +12,7 @@ public:
const char * version() const;
const bool isValid() const;
const bool isOmega() const;
const char * omegaVersion() const;
private:
UserlandHeader();

View File

@@ -1,12 +1,14 @@
/* Same as flash.ld but everything is linked in internal flash */
MEMORY {
INTERNAL_FLASH (rx) : ORIGIN = 0x00200000, LENGTH = 64K
INTERNAL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
SRAM (rw) : ORIGIN = 0x20000000, LENGTH = 256K
}
STACK_SIZE = 32K;
TRAMPOLINES_OFFSET = 0xE000;
FLASH_SECOND_SECTOR_OFFSET = 16K;
FLASH_SECOND_SECTOR_SIZE = 16K;
SECTIONS {
.isr_vector_table ORIGIN(INTERNAL_FLASH) : {
@@ -30,6 +32,20 @@ SECTIONS {
KEEP(*(.header))
} >INTERNAL_FLASH
.rodata : {
. = ALIGN(4);
*(.rodata)
*(.rodata.*)
} >INTERNAL_FLASH
.exam_mode_buffer ORIGIN(INTERNAL_FLASH) + FLASH_SECOND_SECTOR_OFFSET : {
_exam_mode_buffer_start = .;
KEEP(*(.exam_mode_buffer))
/* Note: We don't increment "." here, we set it. */
. = ORIGIN(INTERNAL_FLASH) + FLASH_SECOND_SECTOR_OFFSET + FLASH_SECOND_SECTOR_SIZE;
_exam_mode_buffer_end = .;
} >INTERNAL_FLASH
.text : {
. = ALIGN(4);
*(.text)
@@ -43,12 +59,6 @@ SECTIONS {
_init_array_end = .;
} >INTERNAL_FLASH
.rodata : {
. = ALIGN(4);
*(.rodata)
*(.rodata.*)
} >INTERNAL_FLASH
.data : {
/* The data section is written to Flash but linked as if it were in RAM.
*