diff --git a/bootloader/Makefile b/bootloader/Makefile index c1b39faf4..948599786 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -1,6 +1,16 @@ bootloader_src += $(addprefix bootloader/,\ main.cpp \ + slot.cpp \ + interface.cpp \ + jump_to_firmware.s \ ) -bootloader_src += $(ion_src) $(kandinsky_src) $(liba_src) $(libaxx_src) +bootloader_images = $(addprefix bootloader/, \ + cable.png \ + computer.png \ +) + +bootloader_src += $(ion_src) $(kandinsky_src) $(liba_src) $(libaxx_src) $(bootloader_images) + +$(eval $(call depends_on_image,bootloader/interface.cpp,$(bootloader_images))) diff --git a/bootloader/interface.cpp b/bootloader/interface.cpp new file mode 100644 index 000000000..3bab7e3d8 --- /dev/null +++ b/bootloader/interface.cpp @@ -0,0 +1,47 @@ + +#include +#include + +#include "interface.h" + +#include "computer.h" +#include "cable.h" + +namespace Bootloader { + +void Interface::drawImage(KDContext* ctx, const Image* image, int offset) { + const uint8_t* data; + size_t size; + size_t pixelBufferSize; + + if (image != nullptr) { + data = image->compressedPixelData(); + size = image->compressedPixelDataSize(); + pixelBufferSize = image->width() * image->height(); + } else { + return; + } + + KDColor pixelBuffer[4000]; + assert(pixelBufferSize <= 4000); + assert(Ion::stackSafe()); // That's a VERY big buffer we're allocating on the stack + + Ion::decompress( + data, + reinterpret_cast(pixelBuffer), + size, + pixelBufferSize * sizeof(KDColor) + ); + + KDRect bounds((320 - image->width()) / 2, offset, image->width(), image->height()); + + ctx->fillRectWithPixels(bounds, pixelBuffer, nullptr); +} + +void Interface::draw() { + KDContext * ctx = KDIonContext::sharedContext(); + drawImage(ctx, ImageStore::Computer, 70); + drawImage(ctx, ImageStore::Cable, 172); +} + +} diff --git a/bootloader/interface.h b/bootloader/interface.h new file mode 100644 index 000000000..0a98c2b57 --- /dev/null +++ b/bootloader/interface.h @@ -0,0 +1,22 @@ +#ifndef BOOTLOADER_INTERFACE +#define BOOTLOADER_INTERFACE + +#include +#include +#include + +namespace Bootloader { + +class Interface { + +private: + static void drawImage(KDContext* ctx, const Image* image, int offset); + +public: + static void draw(); + +}; + +} + +#endif \ No newline at end of file diff --git a/bootloader/jump_to_firmware.s b/bootloader/jump_to_firmware.s new file mode 100644 index 000000000..c5b54bcd2 --- /dev/null +++ b/bootloader/jump_to_firmware.s @@ -0,0 +1,11 @@ + +.syntax unified +.section .text.jump_to_firmware +.align 2 +.thumb +.global jump_to_firmware +jump_to_firmware: + dsb 0xF + isb 0xF + msr msp, r0 + bx r1 diff --git a/bootloader/main.cpp b/bootloader/main.cpp index 0147279bb..119911199 100644 --- a/bootloader/main.cpp +++ b/bootloader/main.cpp @@ -1,15 +1,32 @@ -#include -#include -#include +#include +#include +#include + +#include "interface.h" void ion_main(int argc, const char * const argv[]) { + // Clear the screen + Ion::Display::pushRectUniform(KDRect(0,0,320,240), KDColorBlack); // Initialize the backlight Ion::Backlight::init(); - while (1) { - Ion::Display::pushRectUniform(KDRect(0,0,10,10), KDColorRed); - Ion::Timing::msleep(100); - Ion::Display::pushRectUniform(KDRect(0,0,10,10), KDColorBlue); - Ion::Timing::msleep(100); + + 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); + } } + + /* + KDContext * ctx = KDIonContext::sharedContext(); + ctx->drawString(Bootloader::s_slotA->version(), KDPoint(0, 20)); + + */ + Bootloader::s_slotA->boot(); } diff --git a/bootloader/slot.cpp b/bootloader/slot.cpp index ff2020214..3df80ac87 100644 --- a/bootloader/slot.cpp +++ b/bootloader/slot.cpp @@ -1,8 +1,29 @@ #include +extern "C" void jump_to_firmware(const uint32_t* stackPtr, const void(*startPtr)(void)); + namespace Bootloader { - const struct Slot* s_slotA = reinterpret_cast(0x90000000); - const struct Slot* s_slotB = reinterpret_cast(0x90400000); + +const Slot* s_slotA = reinterpret_cast(0x90000000); +const Slot* s_slotB = reinterpret_cast(0x90400000); + +const char * Slot::version() const { + return m_version; +} + +const char * Slot::patchLevel() const { + return m_patchLevel; +} + +const bool Slot::isValid() const { + return m_header == Magic && m_footer == Magic; +} + +[[ noreturn ]] void Slot::boot() const { + jump_to_firmware(m_stackPointer, m_startPointer); + for(;;); +} + } diff --git a/bootloader/slot.h b/bootloader/slot.h index 6190fcf8d..4bb7de8fd 100644 --- a/bootloader/slot.h +++ b/bootloader/slot.h @@ -5,21 +5,29 @@ namespace Bootloader { -struct Slot { - uint32_t unknown; - uint32_t signature_offset; - uint32_t magik_header; - char version[8]; - char patch_level[8]; - uint32_t magik_footer; - uint32_t* stack_pointer; - void(*main_pointer)(); +class Slot { +public: + const char * version() const; + const char * patchLevel() const; + const bool isValid() const; + [[ noreturn ]] void boot() const; + +private: + Slot(); + constexpr static uint32_t Magic = 0xDEC00DF0; + const uint32_t m_unknown; + const uint32_t m_signature; + const uint32_t m_header; + const char m_version[8]; + const char m_patchLevel[8]; + const uint32_t m_footer; + const uint32_t* m_stackPointer; + const void(*m_startPointer)(); }; -extern const struct Slot* s_slotA; -extern const struct Slot* s_slotB; +extern const Slot* s_slotA; +extern const Slot* s_slotB; } - -#endif \ No newline at end of file +#endif diff --git a/build/targets.device.n0110.mak b/build/targets.device.n0110.mak index 87508eac2..d5e7dd30e 100644 --- a/build/targets.device.n0110.mak +++ b/build/targets.device.n0110.mak @@ -6,7 +6,7 @@ $(BUILD_DIR)/test.external_flash.read.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ext $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_external_flash_write_symbols.o $(call object_for,$(test_external_flash_src) $(test_ion_external_flash_write_src)) -$(BUILD_DIR)/bootloader.$(EXE): $(call flavored_object_for,$(bootloader_src)) +$(BUILD_DIR)/bootloader.$(EXE): $(call flavored_object_for,$(bootloader_src),usbxip) $(BUILD_DIR)/bootloader.$(EXE): LDSCRIPT = ion/test/device/n0110/external_flash_tests.ld .PHONY: %_flash diff --git a/themes/icons.json b/themes/icons.json index 3dc1ae52d..c3349673d 100644 --- a/themes/icons.json +++ b/themes/icons.json @@ -40,5 +40,8 @@ "apps/probability/images/normal_icon.png" : "probability/normal_icon.png", "apps/probability/images/poisson_icon.png" : "probability/poisson_icon.png", "apps/probability/images/student_icon.png" : "probability/student_icon.png", - "apps/probability/images/uniform_icon.png" : "probability/uniform_icon.png" + "apps/probability/images/uniform_icon.png" : "probability/uniform_icon.png", + + "bootloader/cable.png": "bootloader/cable.png", + "bootloader/computer.png": "bootloader/computer.png" } diff --git a/themes/themes/local/omega_light/bootloader/cable.png b/themes/themes/local/omega_light/bootloader/cable.png new file mode 100644 index 000000000..cf2c2f845 Binary files /dev/null and b/themes/themes/local/omega_light/bootloader/cable.png differ diff --git a/themes/themes/local/omega_light/bootloader/computer.png b/themes/themes/local/omega_light/bootloader/computer.png new file mode 100644 index 000000000..0b5a578e6 Binary files /dev/null and b/themes/themes/local/omega_light/bootloader/computer.png differ