diff --git a/bootloader/Makefile b/bootloader/Makefile index c59461600..4a3209618 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -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 \ diff --git a/bootloader/boot.cpp b/bootloader/boot.cpp new file mode 100644 index 000000000..268ee125b --- /dev/null +++ b/bootloader/boot.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include + +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); + } +} + +} diff --git a/bootloader/boot.h b/bootloader/boot.h new file mode 100644 index 000000000..23967f87c --- /dev/null +++ b/bootloader/boot.h @@ -0,0 +1,28 @@ +#ifndef BOOTLOADER_BOOT_H +#define BOOTLOADER_BOOT_H + +#include + +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 \ No newline at end of file diff --git a/bootloader/interface.cpp b/bootloader/interface.cpp index 3bab7e3d8..7146e5b93 100644 --- a/bootloader/interface.cpp +++ b/bootloader/interface.cpp @@ -2,7 +2,9 @@ #include #include -#include "interface.h" +#include +#include +#include #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); + } + } + } } diff --git a/bootloader/kernel_header.cpp b/bootloader/kernel_header.cpp index 9c771dd8f..7dac97a06 100644 --- a/bootloader/kernel_header.cpp +++ b/bootloader/kernel_header.cpp @@ -1,13 +1,7 @@ #include -extern "C" void jump_to_firmware(const uint32_t* stackPtr, const void(*startPtr)(void)); - namespace Bootloader { - -const KernelHeader* s_kernelHeaderA = reinterpret_cast(0x90000000); -const KernelHeader* s_kernelHeaderB = reinterpret_cast(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; +} } diff --git a/bootloader/kernel_header.h b/bootloader/kernel_header.h index 32d47347d..017036b62 100644 --- a/bootloader/kernel_header.h +++ b/bootloader/kernel_header.h @@ -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 diff --git a/bootloader/main.cpp b/bootloader/main.cpp index b6d0fffb9..9f237bf0c 100644 --- a/bootloader/main.cpp +++ b/bootloader/main.cpp @@ -1,10 +1,9 @@ #include -#include #include #include -#include "interface.h" +#include 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(); } diff --git a/bootloader/slot.cpp b/bootloader/slot.cpp new file mode 100644 index 000000000..4430807a0 --- /dev/null +++ b/bootloader/slot.cpp @@ -0,0 +1,28 @@ +#include + +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(;;); +} + +} \ No newline at end of file diff --git a/bootloader/slot.h b/bootloader/slot.h new file mode 100644 index 000000000..15a883f39 --- /dev/null +++ b/bootloader/slot.h @@ -0,0 +1,33 @@ +#ifndef BOOTLOADER_SLOT_H +#define BOOTLOADER_SLOT_H + +#include + +#include "kernel_header.h" +#include "userland_header.h" + +namespace Bootloader { + +class Slot { + +public: + Slot(uint32_t address) : + m_kernelHeader(reinterpret_cast(address)), + m_userlandHeader(reinterpret_cast(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 \ No newline at end of file diff --git a/bootloader/trampoline.cpp b/bootloader/trampoline.cpp index b69a79f18..5d7c541c0 100644 --- a/bootloader/trampoline.cpp +++ b/bootloader/trampoline.cpp @@ -3,7 +3,7 @@ #include #include -#include "trampoline.h" +#include namespace Bootloader { diff --git a/bootloader/userland_header.cpp b/bootloader/userland_header.cpp index 36963b589..275743a0a 100644 --- a/bootloader/userland_header.cpp +++ b/bootloader/userland_header.cpp @@ -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; +} + } diff --git a/bootloader/userland_header.h b/bootloader/userland_header.h index 6dc1a6c02..e53b3eccd 100644 --- a/bootloader/userland_header.h +++ b/bootloader/userland_header.h @@ -12,6 +12,7 @@ public: const char * version() const; const bool isValid() const; const bool isOmega() const; + const char * omegaVersion() const; private: UserlandHeader(); diff --git a/ion/src/device/n0110/internal_flash.ld b/ion/src/device/n0110/internal_flash.ld index 9eb193676..8f97d4528 100644 --- a/ion/src/device/n0110/internal_flash.ld +++ b/ion/src/device/n0110/internal_flash.ld @@ -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. *