mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
Bootloader pre-release
This commit is contained in:
@@ -1,38 +1,49 @@
|
||||
|
||||
bootloader_src += $(addprefix bootloader/,\
|
||||
slot_exam_mode.cpp \
|
||||
utility.cpp \
|
||||
boot.cpp \
|
||||
main.cpp \
|
||||
kernel_header.cpp \
|
||||
userland_header.cpp \
|
||||
slot.cpp \
|
||||
interface.cpp \
|
||||
jump_to_firmware.s \
|
||||
trampoline.cpp \
|
||||
recovery.cpp \
|
||||
usb_data.cpp \
|
||||
itoa.cpp \
|
||||
utility.cpp \
|
||||
)
|
||||
|
||||
bootloader_images = $(addprefix bootloader/, \
|
||||
computer.png \
|
||||
bootloader_src += $(addprefix bootloader/slots/, \
|
||||
slot_exam_mode.cpp \
|
||||
slot.cpp \
|
||||
userland_header.cpp \
|
||||
kernel_header.cpp \
|
||||
)
|
||||
|
||||
bootloader_src += $(addprefix bootloader/drivers/, \
|
||||
stm32_drivers.cpp \
|
||||
)
|
||||
|
||||
bootloader_src += $(addprefix bootloader/interface/static/, \
|
||||
interface.cpp \
|
||||
)
|
||||
|
||||
bootloader_src += $(addprefix bootloader/interface/src/,\
|
||||
menu.cpp \
|
||||
)
|
||||
|
||||
bootloader_src += $(addprefix bootloader/interface/menus/about/,\
|
||||
|
||||
bootloader_src += $(addprefix bootloader/interface/menus/, \
|
||||
about.cpp \
|
||||
)
|
||||
|
||||
bootloader_src += $(addprefix bootloader/interface/menus/home/,\
|
||||
home.cpp \
|
||||
dfu.cpp \
|
||||
installer.cpp \
|
||||
warning.cpp \
|
||||
slot_recovery.cpp \
|
||||
crash.cpp \
|
||||
)
|
||||
|
||||
bootloader_images = $(addprefix bootloader/, \
|
||||
computer.png \
|
||||
)
|
||||
|
||||
bootloader_src += $(ion_src) $(simple_kandinsky_src) $(liba_src) $(libaxx_src) $(bootloader_images)
|
||||
|
||||
$(eval $(call depends_on_image,bootloader/interface.cpp,$(bootloader_images)))
|
||||
$(eval $(call depends_on_image,bootloader/interface/menus/home/home.cpp,$(bootloader_images)))
|
||||
$(eval $(call depends_on_image,bootloader/interface/static/interface.cpp,$(bootloader_images)))
|
||||
$(eval $(call depends_on_image,bootloader/interface/src/menu.cpp,$(bootloader_images)))
|
||||
|
||||
@@ -1,19 +1,33 @@
|
||||
#include <bootloader/boot.h>
|
||||
#include <bootloader/slot.h>
|
||||
#include <ion.h>
|
||||
#include <ion/src/device/shared/drivers/reset.h>
|
||||
#include <bootloader/interface.h>
|
||||
#include <ion/src/device/n0110/drivers/power.h>
|
||||
#include <bootloader/slots/slot.h>
|
||||
#include <bootloader/interface/static/interface.h>
|
||||
#include <bootloader/recovery.h>
|
||||
#include <bootloader/usb_data.h>
|
||||
#include <ion/src/device/shared/drivers/flash.h>
|
||||
#include <bootloader/utility.h>
|
||||
#include <bootloader/interface/menus/home/home.h>
|
||||
#include <bootloader/interface/menus/home.h>
|
||||
#include <bootloader/interface/menus/warning.h>
|
||||
#include <ion.h>
|
||||
#include <ion/src/device/shared/drivers/flash.h>
|
||||
#include <ion/src/device/shared/drivers/board.h>
|
||||
#include <ion/src/device/shared/drivers/reset.h>
|
||||
#include <ion/src/device/shared/drivers/external_flash.h>
|
||||
#include <ion/src/device/n0110/drivers/power.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Utility;
|
||||
|
||||
extern "C" {
|
||||
extern char _fake_isr_function_start;
|
||||
}
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
BootConfig * Boot::config() {
|
||||
static BootConfig * bootcfg = new BootConfig();
|
||||
return bootcfg;
|
||||
}
|
||||
|
||||
BootMode Boot::mode() {
|
||||
return BootMode::SlotA;
|
||||
}
|
||||
@@ -22,36 +36,86 @@ void Boot::setMode(BootMode mode) {
|
||||
// We dont use the exam mode driver as storage for the boot mode because we need the 16k of storage x)
|
||||
}
|
||||
|
||||
void Boot::busErr() {
|
||||
if (config()->isBooting()) {
|
||||
config()->slot()->boot();
|
||||
}
|
||||
Bootloader::Recovery::crash_handler("BusFault");
|
||||
}
|
||||
|
||||
bool Boot::isKernelPatched(const Slot & s) {
|
||||
if (s.userlandHeader()->isOmega()) {
|
||||
// we don't need to patch the kernel
|
||||
return true;
|
||||
}
|
||||
|
||||
// It's an epsilon kernel, so we need to check if it's patched
|
||||
|
||||
uint32_t origin_isr = s.address() + sizeof(Bootloader::KernelHeader) - sizeof(uint32_t) * 3;
|
||||
|
||||
if (*(uint32_t *)(origin_isr + sizeof(uint32_t) * 12) == (uint32_t)0x0) {
|
||||
// fake epsilon
|
||||
return true;
|
||||
}
|
||||
|
||||
return *(uint32_t *)(origin_isr + sizeof(uint32_t) * 21) == (uint32_t)&_fake_isr_function_start;
|
||||
}
|
||||
|
||||
__attribute((section(".fake_isr_function"))) __attribute__((used)) void Boot::flsh_intr() {
|
||||
// a simple function
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
void Boot::patchKernel(const Slot & s) {
|
||||
uint32_t origin_isr = s.address() + sizeof(Bootloader::KernelHeader) - sizeof(uint32_t) * 3 - 0x90000000;
|
||||
// we allocate a big buffer to store the first sector
|
||||
uint8_t data[1024*4];
|
||||
memcpy(data, (void*)0x90000000, 1024*4);
|
||||
uint32_t dummy_address = (uint32_t)&_fake_isr_function_start;
|
||||
uint8_t * ptr = (uint8_t *)&dummy_address;
|
||||
data[origin_isr + sizeof(uint32_t) * 21] = ptr[0];
|
||||
data[origin_isr + sizeof(uint32_t) * 21 + 1] = ptr[1];
|
||||
data[origin_isr + sizeof(uint32_t) * 21 + 2] = ptr[2];
|
||||
data[origin_isr + sizeof(uint32_t) * 21 + 3] = ptr[3];
|
||||
Ion::Device::ExternalFlash::EraseSector(0);
|
||||
Ion::Device::ExternalFlash::WriteMemory((uint8_t*)0x90000000, data, 1024*4);
|
||||
}
|
||||
|
||||
void Boot::bootSlot(Bootloader::Slot s) {
|
||||
config()->setSlot(&s);
|
||||
if (!s.userlandHeader()->isOmega() && !s.userlandHeader()->isUpsilon()) {
|
||||
// We are trying to boot epsilon, so we check the version and show an advertisement if needed
|
||||
const char * version = s.userlandHeader()->version();
|
||||
const char * min = "18.2.4";
|
||||
const char * min = "18.2.0";
|
||||
int vsum = Utility::versionSum(version, strlen(version));
|
||||
int minsum = Utility::versionSum(min, strlen(min));
|
||||
if (vsum >= minsum) {
|
||||
Interface::drawEpsilonAdvertisement();
|
||||
uint64_t scan = 0;
|
||||
while (scan != Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
|
||||
scan = Ion::Keyboard::scan();
|
||||
if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::EXE) || scan == Ion::Keyboard::State(Ion::Keyboard::Key::OK)) {
|
||||
scan = Ion::Keyboard::State(Ion::Keyboard::Key::Back);
|
||||
s.boot();
|
||||
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::OnOff)) {
|
||||
Ion::Power::standby(); // Force a core reset to exit
|
||||
}
|
||||
}
|
||||
Interface::drawMenu();
|
||||
WarningMenu menu = WarningMenu();
|
||||
menu.open();
|
||||
return;
|
||||
}
|
||||
}
|
||||
s.boot();
|
||||
Interface::drawMenu();
|
||||
bootSelectedSlot();
|
||||
}
|
||||
|
||||
void Boot::bootSelectedSlot() {
|
||||
lockInternal();
|
||||
enableFlashIntr();
|
||||
config()->setBooting(true);
|
||||
Ion::Device::Flash::EnableInternalSessionLock();
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void Boot::boot() {
|
||||
assert(mode() != BootMode::Unknown);
|
||||
|
||||
Boot::config()->clearSlot();
|
||||
Boot::config()->setBooting(false);
|
||||
|
||||
if (!Boot::isKernelPatched(Slot::A())) {
|
||||
Boot::patchKernel(Slot::A());
|
||||
Ion::LED::setColor(KDColorRed);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
HomeMenu menu = HomeMenu();
|
||||
menu.open(true);
|
||||
@@ -61,67 +125,6 @@ __attribute__((noreturn)) void Boot::boot() {
|
||||
bootloader();
|
||||
}
|
||||
|
||||
void Boot::installerMenu() {
|
||||
Interface::drawInstallerSelection();
|
||||
uint64_t scan = 0;
|
||||
while (scan != Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
|
||||
scan = Ion::Keyboard::scan();
|
||||
if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::One)) {
|
||||
scan = Ion::Keyboard::State(Ion::Keyboard::Key::Back);
|
||||
bootloader();
|
||||
continue;
|
||||
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::Two)) {
|
||||
scan = Ion::Keyboard::State(Ion::Keyboard::Key::Back);
|
||||
bootloaderUpdate();
|
||||
continue;
|
||||
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::OnOff)) {
|
||||
Ion::Power::standby(); // Force a core reset to exit
|
||||
}
|
||||
}
|
||||
|
||||
Interface::drawMenu();
|
||||
}
|
||||
|
||||
void Boot::aboutMenu() {
|
||||
// Draw the about menu
|
||||
Interface::drawAbout();
|
||||
// Wait for the user to press OK, EXE or Back button
|
||||
while (true) {
|
||||
uint64_t scan = Ion::Keyboard::scan();
|
||||
if ((scan == Ion::Keyboard::State(Ion::Keyboard::Key::OK)) ||
|
||||
(scan == Ion::Keyboard::State(Ion::Keyboard::Key::EXE)) ||
|
||||
(scan == Ion::Keyboard::State(Ion::Keyboard::Key::Back))) {
|
||||
// Redraw the menu and return
|
||||
Interface::drawMenu();
|
||||
return;
|
||||
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::OnOff)) {
|
||||
Ion::Power::standby(); // Force a core reset to exit
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Boot::bootloaderUpdate() {
|
||||
USBData data = USBData::BOOTLOADER_UPDATE();
|
||||
|
||||
for (;;) {
|
||||
Bootloader::Interface::drawBootloaderUpdate();
|
||||
Ion::USB::enable();
|
||||
do {
|
||||
uint64_t scan = Ion::Keyboard::scan();
|
||||
if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
|
||||
Ion::USB::disable();
|
||||
Interface::drawMenu();
|
||||
return;
|
||||
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::OnOff)) {
|
||||
Ion::Power::standby();
|
||||
}
|
||||
} while (!Ion::USB::isEnumerated());
|
||||
|
||||
Ion::USB::DFU(true, &data);
|
||||
}
|
||||
}
|
||||
|
||||
void Boot::bootloader() {
|
||||
USBData data = USBData::DEFAULT();
|
||||
for(;;) {
|
||||
@@ -138,7 +141,6 @@ void Boot::bootloader() {
|
||||
if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
|
||||
// Disable USB, redraw the menu and return
|
||||
Ion::USB::disable();
|
||||
Interface::drawMenu();
|
||||
return;
|
||||
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::OnOff)) {
|
||||
Ion::Power::standby(); // Force a core reset to exit
|
||||
@@ -150,6 +152,10 @@ void Boot::bootloader() {
|
||||
}
|
||||
}
|
||||
|
||||
void Boot::jumpToInternalBootloader() {
|
||||
Ion::Device::Board::jumpToInternalBootloader();
|
||||
}
|
||||
|
||||
void Boot::lockInternal() {
|
||||
Ion::Device::Flash::DisableInternalProtection();
|
||||
Ion::Device::Flash::SetInternalSectorProtection(0, true);
|
||||
@@ -159,4 +165,8 @@ void Boot::lockInternal() {
|
||||
Ion::Device::Flash::EnableInternalProtection();
|
||||
}
|
||||
|
||||
void Boot::enableFlashIntr() {
|
||||
Ion::Device::Flash::EnableInternalFlashInterrupt();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,10 +2,25 @@
|
||||
#define BOOTLOADER_BOOT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <bootloader/slot.h>
|
||||
#include <bootloader/slots/slot.h>
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
class BootConfig {
|
||||
public:
|
||||
BootConfig() : m_slot(nullptr), m_booting(false) {};
|
||||
|
||||
void setSlot(Slot * slot) { m_slot = slot; }
|
||||
Slot * slot() const { return m_slot; }
|
||||
void clearSlot() { m_slot = nullptr; }
|
||||
|
||||
void setBooting(bool booting) { m_booting = booting; }
|
||||
bool isBooting() const { return m_booting; }
|
||||
private:
|
||||
Bootloader::Slot * m_slot;
|
||||
bool m_booting;
|
||||
};
|
||||
|
||||
enum BootMode: uint8_t {
|
||||
SlotA = 0,
|
||||
SlotB = 1,
|
||||
@@ -20,15 +35,26 @@ class Boot {
|
||||
public:
|
||||
static BootMode mode();
|
||||
static void setMode(BootMode mode);
|
||||
static BootConfig * config();
|
||||
|
||||
static bool isKernelPatched(const Slot & slot);
|
||||
static void patchKernel(const Slot & slot);
|
||||
|
||||
static void busErr();
|
||||
|
||||
__attribute__ ((noreturn)) static void boot();
|
||||
static void bootloader();
|
||||
static void aboutMenu();
|
||||
static void installerMenu();
|
||||
static void bootloaderUpdate();
|
||||
|
||||
static void bootSlot(Bootloader::Slot slot);
|
||||
static void bootSelectedSlot();
|
||||
__attribute__ ((noreturn)) static void jumpToInternalBootloader();
|
||||
__attribute((section(".fake_isr_function"))) __attribute__((used)) static void flsh_intr();
|
||||
|
||||
static void bootloader();
|
||||
static void lockInternal();
|
||||
static void enableFlashIntr();
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <drivers/reset.h>
|
||||
#include <drivers/timing.h>
|
||||
#include <bootloader/recovery.h>
|
||||
#include <bootloader/boot.h>
|
||||
|
||||
typedef void (*cxx_constructor)();
|
||||
|
||||
@@ -49,7 +50,7 @@ void __attribute__((noinline)) usage_fault_handler() {
|
||||
}
|
||||
|
||||
void __attribute__((noinline)) bus_fault_handler() {
|
||||
Bootloader::Recovery::crash_handler("BusFault");
|
||||
Bootloader::Boot::busErr();
|
||||
}
|
||||
|
||||
/* In order to ensure that this method is execute from the external flash, we
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
#include <drivers/config/clocks.h>
|
||||
#include <drivers/config/internal_flash.h>
|
||||
#include <drivers/external_flash.h>
|
||||
#include <drivers/timing.h>
|
||||
#include <regs/regs.h>
|
||||
#include <ion.h>
|
||||
|
||||
#include <bootloader/drivers/stm32_drivers.h>
|
||||
|
||||
using namespace STM32;
|
||||
typedef void(*ISR)(void);
|
||||
extern ISR InitialisationVector[];
|
||||
|
||||
@@ -439,6 +443,20 @@ bool pcbVersionIsLocked() {
|
||||
return *reinterpret_cast<const uint8_t *>(InternalFlash::Config::OTPLockAddress(k_pcbVersionOTPIndex)) == 0;
|
||||
}
|
||||
|
||||
void jumpToInternalBootloader() {
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
|
||||
STM32::rcc_deinit();
|
||||
STM32::hal_deinit();
|
||||
STM32::systick_deinit();
|
||||
|
||||
const uint32_t p = (*((uint32_t *) 0x1FF00000));
|
||||
asm volatile ("MSR msp, %0" : : "r" (p) : );
|
||||
void (*SysMemBootJump)(void);
|
||||
SysMemBootJump = (void (*)(void)) (*((uint32_t *) 0x1FF00004));
|
||||
SysMemBootJump();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
56
bootloader/drivers/stm32_drivers.cpp
Normal file
56
bootloader/drivers/stm32_drivers.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "stm32_drivers.h"
|
||||
|
||||
void STM32::rcc_deinit() {
|
||||
SET_BIT(STM_32_RCC->CR, (0x1UL << (0U)));
|
||||
while (READ_BIT(STM_32_RCC->CR, (0x1UL << (1U))) == 0) {}
|
||||
SET_BIT(STM_32_RCC->CR, (0x10UL << (3U)));
|
||||
CLEAR_REG(STM_32_RCC->CFGR);
|
||||
while (READ_BIT(STM_32_RCC->CFGR, (0x3UL << (2U))) != 0) {}
|
||||
CLEAR_BIT(STM_32_RCC->CR, (0x1UL << (16U)) | (0x1UL << (18U)) | (0x1UL << (19U)));
|
||||
while (READ_BIT(STM_32_RCC->CR, (0x1UL << (17U))) != 0) {}
|
||||
CLEAR_BIT(STM_32_RCC->CR, (0x1UL << (24U)));
|
||||
while (READ_BIT(STM_32_RCC->CR, (0x1UL << (25U))) != 0) {}
|
||||
CLEAR_BIT(STM_32_RCC->CR, (0x1UL << (26U)));
|
||||
while (READ_BIT(STM_32_RCC->CR, (0x1UL << (27U))) != 0) {}
|
||||
CLEAR_BIT(STM_32_RCC->CR, (0x1UL << (28U)));
|
||||
while (READ_BIT(STM_32_RCC->CR, (0x1UL << (29U))) != 0) {}
|
||||
STM_32_RCC->PLLCFGR = ((0x10UL << (0x0U)) | (0x040UL << (6U)) | (0x080UL << (6U)) | (0x4UL << (24U)) | 0x20000000U);
|
||||
STM_32_RCC->PLLI2SCFGR = ((0x040UL << (6U)) | (0x080UL << (6U)) | (0x4UL << (24U)) | (0x2UL << (28U)));
|
||||
STM_32_RCC->PLLSAICFGR = ((0x040UL << (6U)) | (0x080UL << (6U)) | (0x4UL << (24U)) | 0x20000000U);
|
||||
CLEAR_BIT(STM_32_RCC->CIR, ((0x1UL << (8U)) | (0x1UL << (9U)) | (0x1UL << (10U)) | (0x1UL << (11U)) | (0x1UL << (12U)) | (0x1UL << (13U)) | (0x1UL << (14U))));
|
||||
SET_BIT(STM_32_RCC->CIR, ((0x1UL << (16U)) | (0x1UL << (17U)) | (0x1UL << (18U)) | (0x1UL << (19U)) | (0x1UL << (20U)) | (0x1UL << (21U)) | (0x1UL << (22U)) | (0x1UL << (23U))));
|
||||
CLEAR_BIT(STM_32_RCC->CSR, ((0x1UL << (0U))));
|
||||
SET_BIT(STM_32_RCC->CSR, ((0x1UL << (24U))));
|
||||
uint32_t sysclock = ((uint32_t)16000000U);
|
||||
uint32_t a = ((sysclock / 1000U));
|
||||
uint32_t b = 15U;
|
||||
STM_32_SysTick->LOAD = (uint32_t)(a - 1UL);
|
||||
STM_32_SCB->SHPR[(((uint32_t)(-1))&0xFUL)-4UL] = (uint8_t)((((1UL << 4U)-1UL) << (8U - 4UL)) & (uint32_t)0xFFUL);
|
||||
STM_32_SysTick->VAL = 0U;
|
||||
STM_32_SysTick->CTRL = (1UL << 2U) | (1UL << 1U) | (1UL);
|
||||
uint32_t c = ((uint32_t)((STM_32_SCB->AIRCR & (7UL << 8U)) >> 8U));
|
||||
uint32_t d = (c & (uint32_t)0x07UL);
|
||||
uint32_t e;
|
||||
uint32_t f;
|
||||
e = ((7UL - d) > (uint32_t)(4UL)) ? (uint32_t)(4UL) : (7UL - d);
|
||||
f = ((d + (uint32_t)(4UL)) < (uint32_t)(7UL)) ? (uint32_t)(0UL) : (uint32_t)((d - 7UL) + (uint32_t)(4UL));
|
||||
uint32_t g = (((b & (uint32_t)((1UL << (e)) - 1UL)) << f) | ((0UL & (uint32_t)((1UL << (f)) - 1UL))));
|
||||
STM_32_SCB->SHPR[(((uint32_t)(-1))&0xFUL)-4UL] = (uint8_t)((g << (8U - 4UL)) & (uint32_t)0xFFUL);
|
||||
}
|
||||
|
||||
void STM32::hal_deinit() {
|
||||
STM_32_RCC->APB1RSTR = 0xFFFFFFFFU;
|
||||
STM_32_RCC->APB1RSTR = 0x00U;
|
||||
STM_32_RCC->APB2RSTR = 0xFFFFFFFFU;
|
||||
STM_32_RCC->APB2RSTR = 0x00U;
|
||||
STM_32_RCC->AHB1RSTR = 0xFFFFFFFFU;
|
||||
STM_32_RCC->AHB1RSTR = 0x00U;
|
||||
STM_32_RCC->AHB2RSTR = 0xFFFFFFFFU;
|
||||
STM_32_RCC->AHB2RSTR = 0x00U;
|
||||
STM_32_RCC->AHB3RSTR = 0xFFFFFFFFU;
|
||||
STM_32_RCC->AHB3RSTR = 0x00U;
|
||||
}
|
||||
|
||||
void STM32::systick_deinit() {
|
||||
STM_32_SysTick->CTRL = STM_32_SysTick->LOAD = STM_32_SysTick->VAL = 0;
|
||||
}
|
||||
153
bootloader/drivers/stm32_drivers.h
Normal file
153
bootloader/drivers/stm32_drivers.h
Normal file
@@ -0,0 +1,153 @@
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
Here we implement a very little part of the code from the default stm32 libs because we only need the unload function.
|
||||
Now we include the license of the original code as required.
|
||||
*/
|
||||
|
||||
/*
|
||||
This software component is provided to you as part of a software package and
|
||||
applicable license terms are in the Package_license file. If you received this
|
||||
software component outside of a package or without applicable license terms,
|
||||
the terms of the BSD-3-Clause license shall apply.
|
||||
You may obtain a copy of the BSD-3-Clause at:
|
||||
https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
namespace STM32 {
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t CR;
|
||||
volatile uint32_t PLLCFGR;
|
||||
volatile uint32_t CFGR;
|
||||
volatile uint32_t CIR;
|
||||
volatile uint32_t AHB1RSTR;
|
||||
volatile uint32_t AHB2RSTR;
|
||||
volatile uint32_t AHB3RSTR;
|
||||
uint32_t RESERVED0;
|
||||
volatile uint32_t APB1RSTR;
|
||||
volatile uint32_t APB2RSTR;
|
||||
uint32_t RESERVED1[2];
|
||||
volatile uint32_t AHB1ENR;
|
||||
volatile uint32_t AHB2ENR;
|
||||
volatile uint32_t AHB3ENR;
|
||||
uint32_t RESERVED2;
|
||||
volatile uint32_t APB1ENR;
|
||||
volatile uint32_t APB2ENR;
|
||||
uint32_t RESERVED3[2];
|
||||
volatile uint32_t AHB1LPENR;
|
||||
volatile uint32_t AHB2LPENR;
|
||||
volatile uint32_t AHB3LPENR;
|
||||
uint32_t RESERVED4;
|
||||
volatile uint32_t APB1LPENR;
|
||||
volatile uint32_t APB2LPENR;
|
||||
uint32_t RESERVED5[2];
|
||||
volatile uint32_t BDCR;
|
||||
volatile uint32_t CSR;
|
||||
uint32_t RESERVED6[2];
|
||||
volatile uint32_t SSCGR;
|
||||
volatile uint32_t PLLI2SCFGR;
|
||||
volatile uint32_t PLLSAICFGR;
|
||||
volatile uint32_t DCKCFGR1;
|
||||
volatile uint32_t DCKCFGR2;
|
||||
} STM32_RCC_TypeDef;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t CTRL;
|
||||
volatile uint32_t LOAD;
|
||||
volatile uint32_t VAL;
|
||||
volatile const uint32_t CALIB;
|
||||
} STM32_SysTick_Type;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t ISER[8U];
|
||||
uint32_t RESERVED0[24U];
|
||||
volatile uint32_t ICER[8U];
|
||||
uint32_t RSERVED1[24U];
|
||||
volatile uint32_t ISPR[8U];
|
||||
uint32_t RESERVED2[24U];
|
||||
volatile uint32_t ICPR[8U];
|
||||
uint32_t RESERVED3[24U];
|
||||
volatile uint32_t IABR[8U];
|
||||
uint32_t RESERVED4[56U];
|
||||
volatile uint8_t IP[240U];
|
||||
uint32_t RESERVED5[644U];
|
||||
volatile uint32_t STIR;
|
||||
} STM32_NVIC_Type;
|
||||
|
||||
typedef struct {
|
||||
volatile const uint32_t CPUID;
|
||||
volatile uint32_t ICSR;
|
||||
volatile uint32_t VTOR;
|
||||
volatile uint32_t AIRCR;
|
||||
volatile uint32_t SCR;
|
||||
volatile uint32_t CCR;
|
||||
volatile uint8_t SHPR[12U];
|
||||
volatile uint32_t SHCSR;
|
||||
volatile uint32_t CFSR;
|
||||
volatile uint32_t HFSR;
|
||||
volatile uint32_t DFSR;
|
||||
volatile uint32_t MMFAR;
|
||||
volatile uint32_t BFAR;
|
||||
volatile uint32_t AFSR;
|
||||
volatile const uint32_t ID_PFR[2U];
|
||||
volatile const uint32_t ID_DFR;
|
||||
volatile const uint32_t ID_AFR;
|
||||
volatile const uint32_t ID_MFR[4U];
|
||||
volatile const uint32_t ID_ISAR[5U];
|
||||
uint32_t RESERVED0[1U];
|
||||
volatile const uint32_t CLIDR;
|
||||
volatile const uint32_t CTR;
|
||||
volatile const uint32_t CCSIDR;
|
||||
volatile uint32_t CSSELR;
|
||||
volatile uint32_t CPACR;
|
||||
uint32_t RESERVED3[93U];
|
||||
volatile uint32_t STIR;
|
||||
uint32_t RESERVED4[15U];
|
||||
volatile const uint32_t MVFR0;
|
||||
volatile const uint32_t MVFR1;
|
||||
volatile const uint32_t MVFR2;
|
||||
uint32_t RESERVED5[1U];
|
||||
volatile uint32_t ICIALLU;
|
||||
uint32_t RESERVED6[1U];
|
||||
volatile uint32_t ICIMVAU;
|
||||
volatile uint32_t DCIMVAC;
|
||||
volatile uint32_t DCISW;
|
||||
volatile uint32_t DCCMVAU;
|
||||
volatile uint32_t DCCMVAC;
|
||||
volatile uint32_t DCCSW;
|
||||
volatile uint32_t DCCIMVAC;
|
||||
volatile uint32_t DCCISW;
|
||||
uint32_t RESERVED7[6U];
|
||||
volatile uint32_t ITCMCR;
|
||||
volatile uint32_t DTCMCR;
|
||||
volatile uint32_t AHBPCR;
|
||||
volatile uint32_t CACR;
|
||||
volatile uint32_t AHBSCR;
|
||||
uint32_t RESERVED8[1U];
|
||||
volatile uint32_t ABFSR;
|
||||
} STM32_SCB_Type;
|
||||
|
||||
#define RCC_BASE 0x40023800UL
|
||||
#define SysTick_BASE 0xE000E010UL
|
||||
#define NVIC_BASE 0xE000E100UL
|
||||
#define SCB_BASE 0xE000ED00UL
|
||||
|
||||
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
|
||||
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
|
||||
#define READ_BIT(REG, BIT) ((REG) & (BIT))
|
||||
#define CLEAR_REG(REG) ((REG) = (0x0))
|
||||
#define READ_REG(REG) ((REG))
|
||||
|
||||
#define STM_32_RCC ((STM32::STM32_RCC_TypeDef *) RCC_BASE)
|
||||
#define STM_32_SysTick ((STM32::STM32_SysTick_Type *) SysTick_BASE)
|
||||
#define STM_32_NVIC ((STM32::STM32_NVIC_Type *) NVIC_BASE)
|
||||
#define STM_32_SCB ((STM32_SCB_Type *) SCB_BASE)
|
||||
|
||||
extern void rcc_deinit();
|
||||
extern void hal_deinit();
|
||||
extern void systick_deinit();
|
||||
}
|
||||
@@ -1,328 +0,0 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <ion.h>
|
||||
#include <ion/timing.h>
|
||||
|
||||
#include <bootloader/interface.h>
|
||||
#include <bootloader/messages.h>
|
||||
#include <bootloader/slot.h>
|
||||
#include <bootloader/boot.h>
|
||||
|
||||
#include "computer.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<uint8_t *>(pixelBuffer),
|
||||
size,
|
||||
pixelBufferSize * sizeof(KDColor)
|
||||
);
|
||||
|
||||
KDRect bounds((320 - image->width()) / 2, offset, image->width(), image->height());
|
||||
|
||||
ctx->fillRectWithPixels(bounds, pixelBuffer, nullptr);
|
||||
}
|
||||
|
||||
void Interface::drawHeader() {
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
ctx->fillRect(KDRect(0, 0, 320, 240), KDColorWhite);
|
||||
drawImage(ctx, ImageStore::Computer, 25);
|
||||
KDSize fontSize = KDFont::LargeFont->glyphSize();
|
||||
int initPos = (320 - fontSize.width() * strlen(Messages::mainTitle)) / 2;
|
||||
ctx->drawString(Messages::mainTitle, KDPoint(initPos, ImageStore::Computer->height() + fontSize.height() + 10), KDFont::LargeFont, KDColorBlack, KDColorWhite);
|
||||
}
|
||||
|
||||
void Interface::drawMenu() {
|
||||
// Get the context
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
// Clear the screen
|
||||
ctx->fillRect(KDRect(0, 0, 320, 240), KDColorWhite);
|
||||
// Draw the image
|
||||
drawImage(ctx, ImageStore::Computer, 25);
|
||||
// Get the font size
|
||||
KDSize largeSize = KDFont::LargeFont->glyphSize();
|
||||
KDSize smallSize = KDFont::SmallFont->glyphSize();
|
||||
// Draw the title
|
||||
int initPos = (320 - largeSize.width() * strlen(Messages::mainMenuTitle)) / 2;
|
||||
ctx->drawString(Messages::mainMenuTitle, KDPoint(initPos, ImageStore::Computer->height() + largeSize.height() + 10), KDFont::LargeFont, KDColorBlack, KDColorWhite);
|
||||
|
||||
// Initialize the slot list
|
||||
Slot slots[3] = {Slot::A(), Slot::Khi(), Slot::B()};
|
||||
char indexes[3] = {'1', '2', '3'};
|
||||
|
||||
// Set the khi slot index, improve this when Khi will have a dedicated header
|
||||
const uint8_t khiIndex = 2 - 1;
|
||||
|
||||
// Get the start y position
|
||||
int y = ImageStore::Computer->height() + (largeSize.height() + 10) + (smallSize.height() + 10);
|
||||
|
||||
// Iterate over the slot list
|
||||
for (uint8_t i = 0; i < sizeof(indexes) / sizeof(indexes[0]); i++) {
|
||||
// Get the slot from the list
|
||||
Slot slot = slots[i];
|
||||
// Get the "X - " string
|
||||
char converted[] = {indexes[i], ' ', '-', ' ', '\0'};
|
||||
// Setup the margin
|
||||
int x = 10;
|
||||
// If the slot is valid, draw the slot
|
||||
if (slot.kernelHeader()->isValid() && slot.userlandHeader()->isValid()) {
|
||||
// Draw the slot number
|
||||
ctx->drawString(converted, KDPoint(x, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
// Increment the x position
|
||||
x += strlen(converted) * smallSize.width();
|
||||
// Draw the slot version
|
||||
ctx->drawString(slot.userlandHeader()->version(), KDPoint(x, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
|
||||
// Get if the commit (patchLevel) isn't empty
|
||||
if (slot.kernelHeader()->patchLevel()[0] != '\0') {
|
||||
// Increment the x position
|
||||
x += strlen(slot.userlandHeader()->version()) * smallSize.width() + smallSize.width() * 2;
|
||||
// Draw the slot commit
|
||||
ctx->drawString(slot.kernelHeader()->patchLevel(), KDPoint(x, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
// Increment the x position
|
||||
x += strlen(slot.kernelHeader()->patchLevel()) * smallSize.width() + smallSize.width();
|
||||
} else {
|
||||
// Increment the x position
|
||||
x += strlen(slot.userlandHeader()->version()) * smallSize.width() + smallSize.width();
|
||||
}
|
||||
|
||||
const char * OSName = "";
|
||||
const char * OSVersion = "";
|
||||
// If the slot is Upsilon, draw the slot name
|
||||
if (slot.userlandHeader()->isOmega() && slot.userlandHeader()->isUpsilon()) {
|
||||
// Set the OS name
|
||||
OSName = Messages::upsilon;
|
||||
// Set the OS version
|
||||
OSVersion = slot.userlandHeader()->upsilonVersion();
|
||||
} else if (slot.userlandHeader()->isOmega()) {
|
||||
// Get if slot is Khi
|
||||
bool isKhi = (i == khiIndex);
|
||||
// If the slot is Khi, draw the slot name (Khi)
|
||||
if (isKhi) {
|
||||
// Set the OS name
|
||||
OSName = Messages::khi;
|
||||
} else {
|
||||
// Set the OS name
|
||||
OSName = Messages::omega;
|
||||
}
|
||||
// Set the OS version
|
||||
OSVersion = slot.userlandHeader()->omegaVersion();
|
||||
} else {
|
||||
// Set the OS name
|
||||
OSName = Messages::epsilon;
|
||||
}
|
||||
// Draw the OS name
|
||||
ctx->drawString(OSName, KDPoint(x, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
// Increment the x position
|
||||
x += strlen(OSName) * smallSize.width() + smallSize.width();
|
||||
// Draw the OS version
|
||||
ctx->drawString(OSVersion, KDPoint(x, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
// Else, the slot is invalid
|
||||
} else {
|
||||
ctx->drawString(Messages::invalidSlot, KDPoint(10, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
}
|
||||
// Increment the y position
|
||||
y += smallSize.height() + 10;
|
||||
}
|
||||
|
||||
// Draw the DFU message
|
||||
ctx->drawString(Messages::dfuText, KDPoint(10, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
|
||||
// Increment the y position
|
||||
y += smallSize.height() + 10;
|
||||
// Draw the about message
|
||||
ctx->drawString(Messages::aboutText, KDPoint(10, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
|
||||
// Reboot is disabled for now
|
||||
// y += smallSize.height() + 10;
|
||||
// ctx->drawString(Messages::rebootText, KDPoint(10, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
|
||||
// Draw the footer
|
||||
initPos = (320 - smallSize.width() * strlen(Messages::mainTitle)) / 2;
|
||||
ctx->drawString(Messages::mainTitle, KDPoint(initPos, 240 - smallSize.height() - 10), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
}
|
||||
|
||||
void Interface::drawFlasher() {
|
||||
Interface::drawHeader();
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
int y = ImageStore::Computer->height() + (KDFont::LargeFont->glyphSize().height() + 10) + (KDFont::SmallFont->glyphSize().height() + 10);
|
||||
int initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::dfuSubtitle)) / 2;
|
||||
ctx->drawString(Messages::dfuSubtitle, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
}
|
||||
|
||||
void Interface::drawLoading() {
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
ctx->fillRect(KDRect(0, 0, 320, 240), KDColorWhite);
|
||||
drawImage(ctx, ImageStore::Computer, 25);
|
||||
Ion::Timing::msleep(250);
|
||||
KDSize fontSize = KDFont::LargeFont->glyphSize();
|
||||
int initPos = (320 - fontSize.width() * strlen(Messages::mainTitle)) / 2;
|
||||
for (uint8_t i = 0; i < strlen(Messages::mainTitle); i++) {
|
||||
char tmp[2] = {Messages::mainTitle[i], '\0'};
|
||||
ctx->drawString(tmp, KDPoint(initPos + i * (fontSize.width()), ImageStore::Computer->height() + fontSize.height() + 10), KDFont::LargeFont, KDColorBlack, KDColorWhite);
|
||||
Ion::Timing::msleep(50);
|
||||
}
|
||||
Ion::Timing::msleep(500);
|
||||
}
|
||||
|
||||
void Interface::drawAbout() {
|
||||
drawHeader();
|
||||
// Create the list of about messages
|
||||
// TODO: Move it to messages.h
|
||||
char aboutMessages[][38] = {
|
||||
"This is the bootloader of",
|
||||
"the Upsilon Calculator.",
|
||||
"It is used to install",
|
||||
"and select the OS",
|
||||
"to boot."
|
||||
};
|
||||
// Get the context
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
// Get the start Y position
|
||||
KDSize largeSize = KDFont::LargeFont->glyphSize();
|
||||
KDSize smallSize = KDFont::SmallFont->glyphSize();
|
||||
int y = ImageStore::Computer->height() + (largeSize.height() + 10) + (smallSize.height() + 10);
|
||||
// Iterate over the list and draw each message
|
||||
for (uint8_t i = 0; i < sizeof(aboutMessages) / sizeof(aboutMessages[0]); i++) {
|
||||
// Get the message
|
||||
char * actualMessage = aboutMessages[i];
|
||||
// Get the start X position
|
||||
int initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(actualMessage)) / 2;
|
||||
// Draw the message
|
||||
ctx->drawString(actualMessage, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
// Increment the Y position
|
||||
y += smallSize.height() + 10;
|
||||
}
|
||||
|
||||
ctx->drawString(Messages::bootloaderVersion, KDPoint((320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::bootloaderVersion)) / 2, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
|
||||
}
|
||||
|
||||
void Interface::drawCrash(const char * error) {
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
ctx->fillRect(KDRect(0, 0, 320, 240), KDColorWhite);
|
||||
drawImage(ctx, ImageStore::Computer, 25);
|
||||
KDSize fontSize = KDFont::LargeFont->glyphSize();
|
||||
int initPos = (320 - fontSize.width() * strlen(Messages::crashTitle)) / 2;
|
||||
ctx->drawString(Messages::crashTitle, KDPoint(initPos, ImageStore::Computer->height() + fontSize.height() + 10), KDFont::LargeFont, KDColorBlack, KDColorWhite);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(error)) / 2;
|
||||
ctx->drawString(error, KDPoint(initPos, ImageStore::Computer->height() + fontSize.height() + 10 + KDFont::SmallFont->glyphSize().height() + 10), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::crashText1)) / 2;
|
||||
ctx->drawString(Messages::crashText1, KDPoint(initPos, ImageStore::Computer->height() + fontSize.height() + 10 + KDFont::SmallFont->glyphSize().height() + 10 + KDFont::SmallFont->glyphSize().height() + 10 + 20), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::crashText2)) / 2;
|
||||
ctx->drawString(Messages::crashText2, KDPoint(initPos, ImageStore::Computer->height() + fontSize.height() + 10 + KDFont::SmallFont->glyphSize().height() + 10 + KDFont::SmallFont->glyphSize().height() + 10 + 20 + KDFont::SmallFont->glyphSize().height() + 10), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
}
|
||||
|
||||
void Interface::drawRecovery() {
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
ctx->fillRect(KDRect(0, 0, 320, 240), KDColorWhite);
|
||||
drawImage(ctx, ImageStore::Computer, 25);
|
||||
KDSize fontSize = KDFont::LargeFont->glyphSize();
|
||||
int initPos = (320 - fontSize.width() * strlen(Messages::recoveryTitle)) / 2;
|
||||
int y = ImageStore::Computer->height() + fontSize.height() + 5;
|
||||
ctx->drawString(Messages::recoveryTitle, KDPoint(initPos, y), KDFont::LargeFont, KDColorBlack, KDColorWhite);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::recoveryText1)) / 2;
|
||||
y += fontSize.height() + 5;
|
||||
ctx->drawString(Messages::recoveryText1, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::recoveryText2)) / 2;
|
||||
y += fontSize.height() + 5;
|
||||
ctx->drawString(Messages::recoveryText2, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::recoveryText3)) / 2;
|
||||
y += fontSize.height() + 5;
|
||||
ctx->drawString(Messages::recoveryText3, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::recoveryText4)) / 2;
|
||||
y += fontSize.height() + 5;
|
||||
ctx->drawString(Messages::recoveryText4, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::recoveryText5)) / 2;
|
||||
y += fontSize.height() + 5;
|
||||
ctx->drawString(Messages::recoveryText5, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
}
|
||||
|
||||
void Interface::drawInstallerSelection() {
|
||||
// Get the context
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
// Clear the screen
|
||||
ctx->fillRect(KDRect(0, 0, 320, 240), KDColorWhite);
|
||||
// Draw the image
|
||||
drawImage(ctx, ImageStore::Computer, 25);
|
||||
// Get the font size
|
||||
KDSize largeSize = KDFont::LargeFont->glyphSize();
|
||||
KDSize smallSize = KDFont::SmallFont->glyphSize();
|
||||
// Get the start x position
|
||||
int initPos = (320 - largeSize.width() * strlen(Messages::installerSelectionTitle)) / 2;
|
||||
// Get the start y position
|
||||
int y = ImageStore::Computer->height() + largeSize.height() + 10;
|
||||
// Draw the title
|
||||
ctx->drawString(Messages::installerSelectionTitle, KDPoint(initPos, y), KDFont::LargeFont, KDColorBlack, KDColorWhite);
|
||||
// Increment the y position
|
||||
y += largeSize.height() + 5;
|
||||
// Get the y position of the subtitle
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::installerText1)) / 2;
|
||||
// Draw the subtitle
|
||||
ctx->drawString(Messages::installerText1, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
// Increment the y position
|
||||
y += smallSize.height() + 10;
|
||||
// Set the start x position
|
||||
initPos = 10;
|
||||
// Draw the first button (slot flash)
|
||||
ctx->drawString(Messages::installerText2, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
// Increment the y position
|
||||
y += smallSize.height() + 10;
|
||||
// Draw the second button (bootloader flash)
|
||||
ctx->drawString(Messages::installerText3, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
}
|
||||
|
||||
void Interface::drawBootloaderUpdate() {
|
||||
Interface::drawHeader();
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
int y = ImageStore::Computer->height() + (KDFont::LargeFont->glyphSize().height() + 10) + (KDFont::SmallFont->glyphSize().height() + 10);
|
||||
int initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::bootloaderSubtitle)) / 2;
|
||||
ctx->drawString(Messages::bootloaderSubtitle, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
}
|
||||
|
||||
void Interface::drawEpsilonAdvertisement() {
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
ctx->fillRect(KDRect(0, 0, 320, 240), KDColorRed);
|
||||
drawImage(ctx, ImageStore::Computer, 25);
|
||||
KDSize fontSize = KDFont::LargeFont->glyphSize();
|
||||
int initPos = (320 - fontSize.width() * strlen(Messages::epsilonWarningTitle)) / 2;
|
||||
int y = ImageStore::Computer->height() + fontSize.height() + 15;
|
||||
ctx->drawString(Messages::epsilonWarningTitle, KDPoint(initPos, y), KDFont::LargeFont, KDColorWhite, KDColorRed);
|
||||
initPos = (320 - fontSize.width() * strlen(Messages::epsilonWarningText1)) / 2;
|
||||
y += fontSize.height() + 5;
|
||||
ctx->drawString(Messages::epsilonWarningText1, KDPoint(initPos, y), KDFont::LargeFont, KDColorWhite, KDColorRed);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::epsilonWarningText2)) / 2;
|
||||
y += fontSize.height() + 2;
|
||||
ctx->drawString(Messages::epsilonWarningText2, KDPoint(initPos, y), KDFont::SmallFont, KDColorWhite, KDColorRed);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::epsilonWarningText3)) / 2;
|
||||
y += KDFont::SmallFont->glyphSize().height() + 5;
|
||||
ctx->drawString(Messages::epsilonWarningText3, KDPoint(initPos, y), KDFont::SmallFont, KDColorWhite, KDColorRed);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::epsilonWarningText4)) / 2;
|
||||
y += KDFont::SmallFont->glyphSize().height() + 10;
|
||||
ctx->drawString(Messages::epsilonWarningText4, KDPoint(initPos, y), KDFont::SmallFont, KDColorWhite, KDColorRed);
|
||||
y += KDFont::SmallFont->glyphSize().height() + 10;
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::epsilonWarningText5)) / 2;
|
||||
ctx->drawString(Messages::epsilonWarningText5, KDPoint(initPos, y), KDFont::SmallFont, KDColorWhite, KDColorRed);
|
||||
y += KDFont::SmallFont->glyphSize().height() + 5;
|
||||
ctx->drawString(Messages::epsilonWarningText6, KDPoint(initPos, y), KDFont::SmallFont, KDColorWhite, KDColorRed);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef BOOTLOADER_INTERFACE
|
||||
#define BOOTLOADER_INTERFACE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <kandinsky/context.h>
|
||||
#include <escher/image.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class Interface {
|
||||
|
||||
public:
|
||||
static void drawImage(KDContext * ctx, const Image * image, int offset);
|
||||
static void drawLoading();
|
||||
static void drawHeader();
|
||||
static void drawMenu();
|
||||
static void drawFlasher();
|
||||
static void drawAbout();
|
||||
static void drawCrash(const char * error);
|
||||
static void drawRecovery();
|
||||
static void drawInstallerSelection();
|
||||
static void drawBootloaderUpdate();
|
||||
static void drawEpsilonAdvertisement();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
20
bootloader/interface/menus/about.cpp
Normal file
20
bootloader/interface/menus/about.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "about.h"
|
||||
#include <bootloader/interface/static/messages.h>
|
||||
|
||||
Bootloader::AboutMenu::AboutMenu() : Menu(KDColorBlack, KDColorWhite, Messages::aboutMenuTitle, Messages::bootloaderVersion) {
|
||||
setup();
|
||||
}
|
||||
|
||||
void Bootloader::AboutMenu::setup() {
|
||||
m_default_columns[0] = Column(Messages::aboutMessage1, k_small_font, 0, true);
|
||||
m_default_columns[1] = Column(Messages::aboutMessage2, k_small_font, 0, true);
|
||||
m_default_columns[2] = Column(Messages::aboutMessage3, k_small_font, 0, true);
|
||||
m_default_columns[3] = Column(Messages::aboutMessage4, k_small_font, 0, true);
|
||||
m_default_columns[4] = Column(Messages::aboutMessage5, k_small_font, 0, true);
|
||||
|
||||
m_columns[0] = ColumnBinder(&m_default_columns[0]);
|
||||
m_columns[1] = ColumnBinder(&m_default_columns[1]);
|
||||
m_columns[2] = ColumnBinder(&m_default_columns[2]);
|
||||
m_columns[3] = ColumnBinder(&m_default_columns[3]);
|
||||
m_columns[4] = ColumnBinder(&m_default_columns[4]);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _BOOTLOADER_INTERFACE_ABOUT_ABOUT_H_
|
||||
#define _BOOTLOADER_INTERFACE_ABOUT_ABOUT_H_
|
||||
#ifndef _BOOTLOADER_INTERFACE_ABOUT_H_
|
||||
#define _BOOTLOADER_INTERFACE_ABOUT_H_
|
||||
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Bootloader {
|
||||
AboutMenu();
|
||||
|
||||
void setup() override;
|
||||
|
||||
void post_open() override {};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "about.h"
|
||||
|
||||
Bootloader::AboutMenu::AboutMenu() : Menu(KDColorBlack, KDColorWhite, Messages::aboutMenuTitle, Messages::bootloaderVersion) {
|
||||
setup();
|
||||
}
|
||||
|
||||
void Bootloader::AboutMenu::setup() {
|
||||
m_colomns[0] = Colomn("This is the bootloader of", k_small_font, 0, true);
|
||||
m_colomns[1] = Colomn("the Upsilon Calculator.", k_small_font, 0, true);
|
||||
m_colomns[2] = Colomn("It is used to install", k_small_font, 0, true);
|
||||
m_colomns[3] = Colomn("and select the OS", k_small_font, 0, true);
|
||||
m_colomns[4] = Colomn("to boot.", k_small_font, 0, true);
|
||||
}
|
||||
22
bootloader/interface/menus/crash.cpp
Normal file
22
bootloader/interface/menus/crash.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "crash.h"
|
||||
|
||||
Bootloader::CrashMenu::CrashMenu(const char * err) : Menu(KDColorBlack, KDColorWhite, Bootloader::Messages::bootloaderCrashTitle, Bootloader::Messages::mainTitle), m_error(err) {
|
||||
setup();
|
||||
}
|
||||
|
||||
void Bootloader::CrashMenu::setup() {
|
||||
m_default_columns[0] = Column(m_error, k_large_font, 0, true);
|
||||
m_default_columns[1] = Column(Bootloader::Messages::bootloaderCrashMessage1, k_small_font, 0, true);
|
||||
m_default_columns[2] = Column(Bootloader::Messages::bootloaderCrashMessage2, k_small_font, 0, true);
|
||||
|
||||
m_columns[0] = ColumnBinder(&m_default_columns[0]);
|
||||
m_columns[1] = ColumnBinder(&m_default_columns[1]);
|
||||
m_columns[2] = ColumnBinder(&m_default_columns[2]);
|
||||
}
|
||||
|
||||
void Bootloader::CrashMenu::post_open() {
|
||||
// We override the open method
|
||||
for (;;) {
|
||||
// Infinite loop
|
||||
}
|
||||
}
|
||||
19
bootloader/interface/menus/crash.h
Normal file
19
bootloader/interface/menus/crash.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _BOOTLOADER_INTERFACE_MENUS_CRASH_H_
|
||||
#define _BOOTLOADER_INTERFACE_MENUS_CRASH_H_
|
||||
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class CrashMenu : public Menu {
|
||||
public:
|
||||
CrashMenu(const char * error);
|
||||
|
||||
void setup() override;
|
||||
void post_open() override;
|
||||
|
||||
private:
|
||||
const char * m_error;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
37
bootloader/interface/menus/dfu.cpp
Normal file
37
bootloader/interface/menus/dfu.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "dfu.h"
|
||||
#include <bootloader/boot.h>
|
||||
#include <ion.h>
|
||||
|
||||
Bootloader::DfuMenu::DfuMenu(const char * text, const USBData * data) : Menu(KDColorBlack, KDColorWhite, Messages::dfuTitle, Messages::mainTitle), m_submenu_text(text), m_data(data) {
|
||||
setup();
|
||||
}
|
||||
|
||||
void Bootloader::DfuMenu::setup() {
|
||||
m_default_columns[0] = Column(m_submenu_text, k_small_font, 0, true);
|
||||
|
||||
m_columns[0] = ColumnBinder(&m_default_columns[0]);
|
||||
}
|
||||
|
||||
void Bootloader::DfuMenu::post_open() {
|
||||
// We override the open method
|
||||
if (!m_data->getData().isProtectedInternal() && m_data->getData().isProtectedExternal()) {
|
||||
// Because we want to flash the internal, we will jump into the stm32 bootloader
|
||||
Bootloader::Boot::jumpToInternalBootloader();
|
||||
return; // We never reach this point
|
||||
}
|
||||
for (;;) {
|
||||
Ion::USB::enable();
|
||||
do {
|
||||
uint64_t scan = Ion::Keyboard::scan();
|
||||
if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
|
||||
Ion::USB::disable();
|
||||
forceExit();
|
||||
return;
|
||||
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::OnOff)) {
|
||||
Ion::Power::standby();
|
||||
return;
|
||||
}
|
||||
} while (!Ion::USB::isEnumerated());
|
||||
Ion::USB::DFU(true, (void *)m_data);
|
||||
}
|
||||
}
|
||||
21
bootloader/interface/menus/dfu.h
Normal file
21
bootloader/interface/menus/dfu.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef _BOOTLOADER_INTERFACE_MENUS_DFU_H_
|
||||
#define _BOOTLOADER_INTERFACE_MENUS_DFU_H_
|
||||
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
#include <bootloader/usb_data.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class DfuMenu : public Menu {
|
||||
public:
|
||||
DfuMenu(const char * submenu, const USBData * usbData);
|
||||
|
||||
void setup() override;
|
||||
void post_open() override;
|
||||
|
||||
private:
|
||||
const char * m_submenu_text;
|
||||
const USBData * m_data;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
144
bootloader/interface/menus/home.cpp
Normal file
144
bootloader/interface/menus/home.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#include "home.h"
|
||||
#include <bootloader/boot.h>
|
||||
#include <bootloader/slots/slot.h>
|
||||
#include <bootloader/interface/menus/about.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
Bootloader::AboutMenu * Bootloader::HomeMenu::aboutMenu() {
|
||||
static AboutMenu * aboutMenu = new AboutMenu();
|
||||
return aboutMenu;
|
||||
}
|
||||
|
||||
Bootloader::InstallerMenu * Bootloader::HomeMenu::installerMenu() {
|
||||
static InstallerMenu * installerMenu = new InstallerMenu();
|
||||
return installerMenu;
|
||||
}
|
||||
|
||||
Bootloader::HomeMenu::HomeMenu() : Menu(KDColorBlack, KDColorWhite, Messages::homeTitle, Messages::mainTitle) {
|
||||
setup();
|
||||
}
|
||||
|
||||
bool slotA_submenu() {
|
||||
if (Bootloader::Slot::isFullyValid(Bootloader::Slot::A())) {
|
||||
Bootloader::Boot::bootSlot(Bootloader::Slot::A());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool slotKhi_submenu() {
|
||||
if (Bootloader::Slot::isFullyValid(Bootloader::Slot::Khi())) {
|
||||
Bootloader::Boot::bootSlot(Bootloader::Slot::Khi());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool slotB_submenu() {
|
||||
if (Bootloader::Slot::isFullyValid(Bootloader::Slot::B())) {
|
||||
Bootloader::Boot::bootSlot(Bootloader::Slot::B());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool installer_submenu() {
|
||||
Bootloader::HomeMenu::installerMenu()->open();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool about_submenu() {
|
||||
Bootloader::HomeMenu::aboutMenu()->open();
|
||||
return true;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotA_text() {
|
||||
return Slot::isFullyValid(Slot::A()) ? Messages::homeSlotASubmenu : Messages::invalidSlot;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotA_kernel_text() {
|
||||
return Slot::isFullyValid(Slot::A()) ? Slot::A().kernelHeader()->patchLevel() : nullptr;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotA_version_text() {
|
||||
return Slot::isFullyValid(Slot::A()) ? Slot::A().userlandHeader()->isOmega() && Slot::A().userlandHeader()->isUpsilon() ? Slot::A().userlandHeader()->upsilonVersion() : Slot::A().userlandHeader()->isOmega() ? Slot::A().userlandHeader()->omegaVersion() : Slot::A().kernelHeader()->version() : nullptr;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotA_os_text() {
|
||||
if (Slot::isFullyValid(Slot::A())) {
|
||||
if (Slot::A().userlandHeader()->isOmega() && Slot::A().userlandHeader()->isUpsilon()) {
|
||||
return Messages::upsilonSlot;
|
||||
} else if (Slot::A().userlandHeader()->isOmega()) {
|
||||
return Messages::omegaSlot;
|
||||
} else {
|
||||
return Messages::epsilonSlot;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotKhi_text() {
|
||||
return Slot::isFullyValid(Slot::Khi()) ? Messages:: homeSlotKhiSubmenu : Messages::invalidSlot;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotKhi_kernel_text() {
|
||||
return Slot::isFullyValid(Slot::Khi()) ? Slot::Khi().kernelHeader()->patchLevel() : nullptr;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotKhi_os_text() {
|
||||
if (Slot::isFullyValid(Slot::Khi())) {
|
||||
if (Slot::Khi().userlandHeader()->isOmega() && Slot::Khi().userlandHeader()->isUpsilon()) {
|
||||
return Messages::upsilonSlot;
|
||||
} else if (Slot::Khi().userlandHeader()->isOmega()) {
|
||||
return Messages::omegaSlot;
|
||||
} else {
|
||||
return Messages::epsilonSlot;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotKhi_version_text() {
|
||||
return Slot::isFullyValid(Slot::Khi()) ? Slot::Khi().userlandHeader()->isOmega() && Slot::Khi().userlandHeader()->isUpsilon() ? Slot::Khi().userlandHeader()->upsilonVersion() : Slot::Khi().userlandHeader()->isOmega() ? Slot::Khi().userlandHeader()->omegaVersion() : Slot::Khi().kernelHeader()->version() : nullptr;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotB_text() {
|
||||
return Slot::isFullyValid(Slot::B()) ? Messages::homeSlotBSubmenu : Messages::invalidSlot;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotB_kernel_text() {
|
||||
return Slot::isFullyValid(Slot::B()) ? Slot::B().kernelHeader()->patchLevel() : nullptr;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotB_os_text() {
|
||||
if (Slot::isFullyValid(Slot::B())) {
|
||||
if (Slot::B().userlandHeader()->isOmega() && Slot::B().userlandHeader()->isUpsilon()) {
|
||||
return Messages::upsilonSlot;
|
||||
} else if (Slot::B().userlandHeader()->isOmega()) {
|
||||
return Messages::omegaSlot;
|
||||
} else {
|
||||
return Messages::epsilonSlot;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotB_version_text() {
|
||||
return Slot::isFullyValid(Slot::B()) ? Slot::B().userlandHeader()->isOmega() && Slot::B().userlandHeader()->isUpsilon() ? Slot::B().userlandHeader()->upsilonVersion() : Slot::B().userlandHeader()->isOmega() ? Slot::B().userlandHeader()->omegaVersion() : Slot::B().kernelHeader()->version() : nullptr;
|
||||
}
|
||||
|
||||
void Bootloader::HomeMenu::setup() {
|
||||
m_slot_columns[0] = SlotColumn(slotA_text(), slotA_kernel_text(), slotA_os_text(), slotA_version_text(), Ion::Keyboard::Key::One, k_small_font, 10, false, &slotA_submenu);
|
||||
m_slot_columns[1] = SlotColumn(slotKhi_text(), slotKhi_kernel_text(), slotKhi_os_text(), slotKhi_version_text(), Ion::Keyboard::Key::Two, k_small_font, 10, false, &slotKhi_submenu);
|
||||
m_slot_columns[2] = SlotColumn(slotB_text(), slotB_kernel_text(), slotB_os_text(), slotB_version_text(), Ion::Keyboard::Key::Three, k_small_font, 10, false, &slotB_submenu);
|
||||
m_default_columns[0] = Column(Messages::homeInstallerSubmenu, Ion::Keyboard::Key::Four, k_small_font, 10, false, &installer_submenu);
|
||||
m_default_columns[1] = Column(Messages::homeAboutSubmenu, Ion::Keyboard::Key::Five, k_small_font, 10, false, &about_submenu);
|
||||
|
||||
|
||||
m_columns[0] = ColumnBinder(&m_slot_columns[0]);
|
||||
m_columns[1] = ColumnBinder(&m_slot_columns[1]);
|
||||
m_columns[2] = ColumnBinder(&m_slot_columns[2]);
|
||||
m_columns[3] = ColumnBinder(&m_default_columns[0]);
|
||||
m_columns[4] = ColumnBinder(&m_default_columns[1]);
|
||||
|
||||
}
|
||||
36
bootloader/interface/menus/home.h
Normal file
36
bootloader/interface/menus/home.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef _BOOTLOADER_INTERFACE_MENUS_HOME_H_
|
||||
#define _BOOTLOADER_INTERFACE_MENUS_HOME_H_
|
||||
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
#include <bootloader/interface/menus/about.h>
|
||||
#include <bootloader/interface/menus/installer.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class HomeMenu : public Menu {
|
||||
public:
|
||||
HomeMenu();
|
||||
|
||||
void setup() override;
|
||||
void post_open() override {};
|
||||
|
||||
static AboutMenu * aboutMenu();
|
||||
static InstallerMenu * installerMenu();
|
||||
|
||||
private:
|
||||
const char * slotA_text();
|
||||
const char * slotA_kernel_text();
|
||||
const char * slotA_os_text();
|
||||
const char * slotA_version_text();
|
||||
const char * slotKhi_text();
|
||||
const char * slotKhi_kernel_text();
|
||||
const char * slotKhi_os_text();
|
||||
const char * slotKhi_version_text();
|
||||
const char * slotB_text();
|
||||
const char * slotB_kernel_text();
|
||||
const char * slotB_os_text();
|
||||
const char * slotB_version_text();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,62 +0,0 @@
|
||||
#include "home.h"
|
||||
#include <bootloader/slot.h>
|
||||
#include <bootloader/interface/menus/about/about.h>
|
||||
|
||||
Bootloader::AboutMenu * Bootloader::HomeMenu::aboutMenu() {
|
||||
static AboutMenu * aboutMenu = new AboutMenu();
|
||||
return aboutMenu;
|
||||
}
|
||||
|
||||
Bootloader::HomeMenu::HomeMenu() : Menu(KDColorBlack, KDColorWhite, Messages::mainMenuTitle, Messages::mainTitle) {
|
||||
setup();
|
||||
}
|
||||
|
||||
bool slotA_submenu() {
|
||||
if (Bootloader::Slot::isFullyValid(Bootloader::Slot::A())) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool slotKhi_submenu() {
|
||||
if (Bootloader::Slot::isFullyValid(Bootloader::Slot::Khi())) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool slotB_submenu() {
|
||||
if (Bootloader::Slot::isFullyValid(Bootloader::Slot::B())) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool installer_submenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool about_submenu() {
|
||||
Bootloader::HomeMenu::aboutMenu()->open();
|
||||
return true;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotA_text() {
|
||||
return Slot::isFullyValid(Slot::A()) ? "1 - Slot A" : Messages::invalidSlot;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotKhi_text() {
|
||||
return Slot::isFullyValid(Slot::Khi()) ? "2 - Slot Khi" : Messages::invalidSlot;
|
||||
}
|
||||
|
||||
const char * Bootloader::HomeMenu::slotB_text() {
|
||||
return Slot::isFullyValid(Slot::B()) ? "3 - Slot B" : Messages::invalidSlot;
|
||||
}
|
||||
|
||||
void Bootloader::HomeMenu::setup() {
|
||||
m_colomns[0] = Colomn(slotA_text(), Ion::Keyboard::Key::One, k_small_font, 30, false, &slotA_submenu);
|
||||
m_colomns[1] = Colomn(slotKhi_text(), Ion::Keyboard::Key::Two, k_small_font, 30, false, &slotKhi_submenu);
|
||||
m_colomns[2] = Colomn(slotB_text(), Ion::Keyboard::Key::Three, k_small_font, 30, false, &slotB_submenu);
|
||||
m_colomns[3] = Colomn("4- installer", Ion::Keyboard::Key::Four, k_small_font, 30, false, &installer_submenu);
|
||||
m_colomns[4] = Colomn("5- about", Ion::Keyboard::Key::Five, k_small_font, 30, false, &about_submenu);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef _BOOTLOADER_INTERFACE_HOME_HOME_H_
|
||||
#define _BOOTLOADER_INTERFACE_HOME_HOME_H_
|
||||
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
#include <bootloader/interface/menus/about/about.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class HomeMenu : public Menu {
|
||||
public:
|
||||
HomeMenu();
|
||||
|
||||
void setup() override;
|
||||
static AboutMenu * aboutMenu();
|
||||
|
||||
private:
|
||||
const char * slotA_text();
|
||||
const char * slotKhi_text();
|
||||
const char * slotB_text();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
41
bootloader/interface/menus/installer.cpp
Normal file
41
bootloader/interface/menus/installer.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "installer.h"
|
||||
#include <bootloader/interface/static/messages.h>
|
||||
#include <bootloader/usb_data.h>
|
||||
|
||||
#include <bootloader/interface/menus/dfu.h>
|
||||
|
||||
Bootloader::DfuMenu * Bootloader::InstallerMenu::SlotsDFU() {
|
||||
USBData data = USBData::DEFAULT();
|
||||
static DfuMenu * slotsDfu = new DfuMenu(Messages::dfuSlotsUpdate, &data);
|
||||
return slotsDfu;
|
||||
}
|
||||
|
||||
Bootloader::DfuMenu * Bootloader::InstallerMenu::BootloaderDFU() {
|
||||
USBData data = USBData::BOOTLOADER_UPDATE();
|
||||
static DfuMenu * bootloaderDfu = new DfuMenu(Messages::dfuBootloaderUpdate, &data);
|
||||
return bootloaderDfu;
|
||||
}
|
||||
|
||||
Bootloader::InstallerMenu::InstallerMenu() : Menu(KDColorBlack, KDColorWhite, Messages::installerTitle, Messages::mainTitle) {
|
||||
setup();
|
||||
}
|
||||
|
||||
bool slots_submenu() {
|
||||
Bootloader::InstallerMenu::SlotsDFU()->open();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bootloader_submenu() {
|
||||
Bootloader::InstallerMenu::BootloaderDFU()->open();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bootloader::InstallerMenu::setup() {
|
||||
m_default_columns[0] = Column(Messages::installerText1, k_large_font, 0, true);
|
||||
m_default_columns[1] = Column(Messages::installerSlotsSubmenu, Ion::Keyboard::Key::One, k_small_font, 30, false, &slots_submenu);
|
||||
m_default_columns[2] = Column(Messages::installerBootloaderSubmenu, Ion::Keyboard::Key::Two, k_small_font, 30, false, &bootloader_submenu);
|
||||
|
||||
m_columns[0] = ColumnBinder(&m_default_columns[0]);
|
||||
m_columns[1] = ColumnBinder(&m_default_columns[1]);
|
||||
m_columns[2] = ColumnBinder(&m_default_columns[2]);
|
||||
}
|
||||
20
bootloader/interface/menus/installer.h
Normal file
20
bootloader/interface/menus/installer.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef _BOOTLOADER_INTERFACE_MENUS_INSTALLER_H_
|
||||
#define _BOOTLOADER_INTERFACE_MENUS_INSTALLER_H_
|
||||
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
#include <bootloader/interface/menus/dfu.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class InstallerMenu : public Menu {
|
||||
public:
|
||||
InstallerMenu();
|
||||
|
||||
void setup() override;
|
||||
void post_open() override {};
|
||||
|
||||
static DfuMenu * SlotsDFU();
|
||||
static DfuMenu * BootloaderDFU();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef _BOOTLOADER_INTERFACE_MENUS_INSTALLER_INSTALLER_H_
|
||||
#define _BOOTLOADER_INTERFACE_MENUS_INSTALLER_INSTALLER_H_
|
||||
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class InstallerMenu : public Menu {
|
||||
public:
|
||||
InstallerMenu();
|
||||
|
||||
void setup() override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
39
bootloader/interface/menus/slot_recovery.cpp
Normal file
39
bootloader/interface/menus/slot_recovery.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "slot_recovery.h"
|
||||
#include <ion.h>
|
||||
|
||||
Bootloader::SlotRecoveryMenu::SlotRecoveryMenu(USBData * usb) : Menu(KDColorBlack, KDColorWhite, Messages::recoveryTitle, Messages::mainTitle), m_data(usb) {
|
||||
setup();
|
||||
}
|
||||
|
||||
void Bootloader::SlotRecoveryMenu::setup() {
|
||||
m_default_columns[0] = Column(Messages::recoveryMessage1, k_small_font, 0, true);
|
||||
m_default_columns[1] = Column(Messages::recoveryMessage2, k_small_font, 0, true);
|
||||
m_default_columns[2] = Column(Messages::recoveryMessage3, k_small_font, 0, true);
|
||||
m_default_columns[3] = Column(Messages::recoveryMessage4, k_small_font, 0, true);
|
||||
m_default_columns[4] = Column(Messages::recoveryMessage5, k_small_font, 0, true);
|
||||
|
||||
m_columns[0] = ColumnBinder(&m_default_columns[0]);
|
||||
m_columns[1] = ColumnBinder(&m_default_columns[1]);
|
||||
m_columns[2] = ColumnBinder(&m_default_columns[2]);
|
||||
m_columns[3] = ColumnBinder(&m_default_columns[3]);
|
||||
m_columns[4] = ColumnBinder(&m_default_columns[4]);
|
||||
}
|
||||
|
||||
void Bootloader::SlotRecoveryMenu::post_open() {
|
||||
// We override the open method
|
||||
for (;;) {
|
||||
Ion::USB::enable();
|
||||
do {
|
||||
uint64_t scan = Ion::Keyboard::scan();
|
||||
if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
|
||||
Ion::USB::disable();
|
||||
forceExit();
|
||||
return;
|
||||
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::OnOff)) {
|
||||
Ion::Power::standby();
|
||||
return;
|
||||
}
|
||||
} while (!Ion::USB::isEnumerated());
|
||||
Ion::USB::DFU(true, (void *)m_data);
|
||||
}
|
||||
}
|
||||
19
bootloader/interface/menus/slot_recovery.h
Normal file
19
bootloader/interface/menus/slot_recovery.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _BOOTLOADER_INTERFACE_MENU_SLOT_RECOVERY_H
|
||||
#define _BOOTLOADER_INTERFACE_MENU_SLOT_RECOVERY_H
|
||||
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
#include <bootloader/usb_data.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class SlotRecoveryMenu : public Menu {
|
||||
public:
|
||||
SlotRecoveryMenu(USBData * usbData);
|
||||
|
||||
void setup() override;
|
||||
void post_open() override;
|
||||
private:
|
||||
const USBData * m_data;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
35
bootloader/interface/menus/warning.cpp
Normal file
35
bootloader/interface/menus/warning.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "warning.h"
|
||||
#include <bootloader/slots/slot.h>
|
||||
#include <bootloader/boot.h>
|
||||
|
||||
Bootloader::WarningMenu::WarningMenu() : Menu(KDColorWhite, KDColorRed, Messages::epsilonWarningTitle, Messages::mainTitle, false, 3) {
|
||||
setup();
|
||||
}
|
||||
|
||||
bool proceed() {
|
||||
Bootloader::Boot::bootSelectedSlot();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool backoff() {
|
||||
if (Bootloader::Boot::config()->slot() != nullptr) {
|
||||
Bootloader::Boot::config()->clearSlot();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bootloader::WarningMenu::setup() {
|
||||
m_default_columns[0] = Column(Messages::epsilonWarningMessage1, k_small_font, 0, true);
|
||||
m_default_columns[1] = Column(Messages::epsilonWarningMessage2, k_small_font, 0, true);
|
||||
m_default_columns[2] = Column(Messages::epsilonWarningMessage3, k_small_font, 0, true);
|
||||
m_default_columns[3] = Column(Messages::epsilonWarningMessage4, k_small_font, 0, true);
|
||||
m_default_columns[4] = Column(Messages::epsilonWarningMessage5, Ion::Keyboard::Key::EXE, k_small_font, 0, true, &proceed);
|
||||
m_default_columns[5] = Column(Messages::epsilonWarningMessage6, Ion::Keyboard::Key::Back, k_small_font, 0, true, &backoff);
|
||||
|
||||
m_columns[0] = ColumnBinder(&m_default_columns[0]);
|
||||
m_columns[1] = ColumnBinder(&m_default_columns[1]);
|
||||
m_columns[2] = ColumnBinder(&m_default_columns[2]);
|
||||
m_columns[3] = ColumnBinder(&m_default_columns[3]);
|
||||
m_columns[4] = ColumnBinder(&m_default_columns[4]);
|
||||
m_columns[5] = ColumnBinder(&m_default_columns[5]);
|
||||
}
|
||||
17
bootloader/interface/menus/warning.h
Normal file
17
bootloader/interface/menus/warning.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef _BOOTLOADER_INTERFACE_MENUS_WARNING_H_
|
||||
#define _BOOTLOADER_INTERFACE_MENUS_WARNING_H_
|
||||
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
#include <bootloader/slots/slot.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class WarningMenu : public Menu {
|
||||
public:
|
||||
WarningMenu();
|
||||
|
||||
void setup() override;
|
||||
void post_open() override {};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <bootloader/interface/src/menu.h>
|
||||
#include <bootloader/interface.h>
|
||||
#include <bootloader/interface/static/interface.h>
|
||||
#include <ion.h>
|
||||
#include <kandinsky/context.h>
|
||||
#include <string.h>
|
||||
@@ -9,7 +9,7 @@
|
||||
const Ion::Keyboard::Key Bootloader::Menu::k_breaking_keys[];
|
||||
|
||||
void Bootloader::Menu::setup() {
|
||||
// Here we add the colomns to the menu.
|
||||
// Here we add the columns to the menu.
|
||||
}
|
||||
|
||||
void Bootloader::Menu::open(bool noreturn) {
|
||||
@@ -17,8 +17,10 @@ void Bootloader::Menu::open(bool noreturn) {
|
||||
|
||||
uint64_t scan = 0;
|
||||
bool exit = false;
|
||||
|
||||
post_open();
|
||||
|
||||
while(!exit) {
|
||||
while(!exit && !m_forced_exit) {
|
||||
scan = Ion::Keyboard::scan();
|
||||
exit = !handleKey(scan);
|
||||
if (noreturn) {
|
||||
@@ -40,13 +42,17 @@ void Bootloader::Menu::showMenu() {
|
||||
ctx->drawString(m_title, KDPoint(x, y), k_large_font, m_foreground, m_background);
|
||||
y += largeFontHeight() + 10;
|
||||
|
||||
//TODO: center the colomns if m_centerY is true
|
||||
//TODO: center the columns if m_centerY is true
|
||||
|
||||
for (Colomn & colomn : m_colomns) {
|
||||
if (colomn.isNull()) {
|
||||
break;
|
||||
for (ColumnBinder column : m_columns) {
|
||||
if (column.isNull()) {
|
||||
continue;
|
||||
}
|
||||
if (column.type() == ColumnType::SLOT) {
|
||||
y += ((SlotColumn *)column.getColumn())->draw(ctx, y, m_background, m_foreground) + m_margin;
|
||||
} else if (column.type() == ColumnType::DEFAULT) {
|
||||
y += ((Column *)column.getColumn())->draw(ctx, y, m_background, m_foreground) + m_margin;
|
||||
}
|
||||
y += colomn.draw(ctx, y, m_background, m_foreground) + k_colomns_margin;
|
||||
}
|
||||
|
||||
if (m_bottom != nullptr) {
|
||||
@@ -66,26 +72,32 @@ bool Bootloader::Menu::handleKey(uint64_t key) {
|
||||
Ion::Power::standby();
|
||||
return false;
|
||||
}
|
||||
for (Colomn & colomn : this->m_colomns) {
|
||||
if (colomn.isNull() || !colomn.isClickable()) {
|
||||
for (ColumnBinder column : m_columns) {
|
||||
if (column.isNull()) {
|
||||
continue;
|
||||
} else {
|
||||
if (colomn.didHandledEvent(key)) {
|
||||
redraw();
|
||||
if (column.type() == ColumnType::SLOT) {
|
||||
if (((SlotColumn *)column.getColumn())->didHandledEvent(key)) {
|
||||
redraw();
|
||||
}
|
||||
} else if (column.type() == ColumnType::DEFAULT) {
|
||||
if (((Column *)column.getColumn())->didHandledEvent(key)) {
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bootloader::Menu::Colomn::didHandledEvent(uint64_t key) {
|
||||
bool Bootloader::Menu::Column::didHandledEvent(uint64_t key) {
|
||||
if (isMyKey(key) && isClickable()) {
|
||||
return m_callback();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Bootloader::Menu::Colomn::draw(KDContext * ctx, int y, KDColor background, KDColor foreground) {
|
||||
int Bootloader::Menu::Column::draw(KDContext * ctx, int y, KDColor background, KDColor foreground) {
|
||||
int x = m_extraX;
|
||||
if (m_center) {
|
||||
x += Bootloader::Menu::calculateCenterX(m_text, m_font->glyphSize().width());
|
||||
@@ -93,3 +105,32 @@ int Bootloader::Menu::Colomn::draw(KDContext * ctx, int y, KDColor background, K
|
||||
ctx->drawString(m_text, KDPoint(x, y), m_font, foreground, background);
|
||||
return m_font->glyphSize().height();
|
||||
}
|
||||
|
||||
int Bootloader::Menu::SlotColumn::draw(KDContext * ctx, int y, KDColor background, KDColor foreground) {
|
||||
int x = m_extraX;
|
||||
|
||||
int width = strlen(m_text);
|
||||
if (m_kernalPatch != nullptr) {
|
||||
width += strlen(m_kernalPatch) + m_font->glyphSize().width();
|
||||
}
|
||||
if (m_osType != nullptr) {
|
||||
width += strlen(m_osType) + m_font->glyphSize().width();
|
||||
}
|
||||
if (m_center) {
|
||||
x += Bootloader::Menu::getScreen().width() - width * m_font->glyphSize().width();
|
||||
}
|
||||
ctx->drawString(m_text, KDPoint(x, y), m_font, foreground, background);
|
||||
x += strlen(m_text) * m_font->glyphSize().width() + m_font->glyphSize().width();
|
||||
if (m_kernalPatch != nullptr) {
|
||||
ctx->drawString(m_kernalPatch, KDPoint(x, y), m_font, foreground, background);
|
||||
}
|
||||
x += strlen(m_kernalPatch) * m_font->glyphSize().width() + m_font->glyphSize().width();
|
||||
if (m_osType != nullptr) {
|
||||
ctx->drawString(m_osType, KDPoint(x, y), m_font, foreground, background);
|
||||
}
|
||||
x += strlen(m_osType) * m_font->glyphSize().width() + m_font->glyphSize().width();
|
||||
if (m_kernelVersion != nullptr) {
|
||||
ctx->drawString(m_kernelVersion, KDPoint(x, y), m_font, foreground, background);
|
||||
}
|
||||
return m_font->glyphSize().height();
|
||||
}
|
||||
|
||||
@@ -2,48 +2,82 @@
|
||||
#define _BOOTLOADER_MENU_H_
|
||||
|
||||
#include <ion/keyboard.h>
|
||||
#include <bootloader/messages.h>
|
||||
#include <bootloader/interface/static/messages.h>
|
||||
#include <kandinsky/context.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class Menu {
|
||||
public:
|
||||
Menu() : m_colomns(), m_background(KDColorWhite), m_title(Messages::mainTitle), m_foreground(KDColorBlack), m_bottom(nullptr), m_centerY(false) {
|
||||
setup();
|
||||
};
|
||||
Menu(KDColor forground, KDColor background, const char * title) : m_colomns(), m_background(background), m_title(title), m_foreground(forground), m_bottom(nullptr), m_centerY(false) {
|
||||
setup();
|
||||
};
|
||||
Menu(KDColor forground, KDColor background, const char * title, const char * bottom) : m_colomns(), m_background(background), m_title(title), m_foreground(forground), m_bottom(bottom), m_centerY(false) {
|
||||
setup();
|
||||
};
|
||||
Menu(KDColor forground, KDColor background, const char * title, const char * bottom, bool centerY) : m_colomns(), m_background(background), m_title(title), m_foreground(forground), m_bottom(bottom), m_centerY(centerY) {
|
||||
Menu() : Menu(KDColorBlack, KDColorWhite, Messages::mainTitle) { };
|
||||
Menu(KDColor forground, KDColor background, const char * title) : Menu(forground, background, title, nullptr) {};
|
||||
Menu(KDColor forground, KDColor background, const char * title, const char * bottom) : Menu(forground, background, title, bottom, false) {};
|
||||
Menu(KDColor forground, KDColor background, const char * title, const char * bottom, bool centerY) : Menu(forground, background, title, bottom, centerY, k_columns_margin) {};
|
||||
Menu(KDColor forground, KDColor background, const char * title, const char * bottom, bool centerY, int margin) : m_columns(), m_default_columns(), m_slot_columns(), m_background(background), m_title(title), m_foreground(forground), m_bottom(bottom), m_centerY(centerY), m_forced_exit(false), m_margin(margin) {
|
||||
setup();
|
||||
}
|
||||
static const int k_columns_margin = 5;
|
||||
|
||||
virtual void setup() = 0;
|
||||
virtual void post_open() = 0;
|
||||
|
||||
enum ColumnType {
|
||||
DEFAULT,
|
||||
SLOT
|
||||
};
|
||||
|
||||
class Colomn {
|
||||
class Column {
|
||||
public:
|
||||
Colomn() : m_text(nullptr), m_key(Ion::Keyboard::Key::None), m_font(KDFont::SmallFont), m_extraX(0), m_center(false), m_callback(nullptr) {};
|
||||
Colomn(const char * t, Ion::Keyboard::Key k, const KDFont * font, int extraX, bool center, bool(*pointer)()) : m_text(t), m_key(k), m_font(font), m_extraX(extraX), m_center(center), m_callback(pointer), m_clickable(true) {};
|
||||
Colomn(const char * t, const KDFont * font, int extraX, bool center) : m_text(t), m_key(Ion::Keyboard::Key::None), m_font(font), m_extraX(extraX), m_center(center), m_callback(nullptr), m_clickable(false) {};
|
||||
Column() : m_text(nullptr), m_key(Ion::Keyboard::Key::None), m_font(KDFont::SmallFont), m_extraX(0), m_center(false), m_callback(nullptr), m_clickable(false) {};
|
||||
|
||||
Column(const char * t, Ion::Keyboard::Key k, const KDFont * font, int extraX, bool center, bool(*pointer)()) : m_text(t), m_key(k), m_font(font), m_extraX(extraX), m_center(center), m_callback(pointer), m_clickable(true) {};
|
||||
Column(const char * t, const KDFont * font, int extraX, bool center) : m_text(t), m_key(Ion::Keyboard::Key::None), m_font(font), m_extraX(extraX), m_center(center), m_callback(nullptr), m_clickable(false) {};
|
||||
|
||||
bool isNull() const { return m_text == nullptr; };
|
||||
bool isClickable() const { return m_clickable; };
|
||||
bool didHandledEvent(uint64_t key);
|
||||
int draw(KDContext * ctx, int y, KDColor background, KDColor foreground);
|
||||
virtual int draw(KDContext * ctx, int y, KDColor background, KDColor foreground);
|
||||
virtual int columnType() { return ColumnType::DEFAULT; };
|
||||
|
||||
private:
|
||||
bool isMyKey(uint64_t key) const { return Ion::Keyboard::State(m_key) == key; };
|
||||
|
||||
protected:
|
||||
const char * m_text;
|
||||
Ion::Keyboard::Key m_key;
|
||||
const KDFont * m_font;
|
||||
int m_extraX;
|
||||
bool m_center;
|
||||
bool m_clickable;
|
||||
bool (*m_callback)();
|
||||
bool m_clickable;
|
||||
};
|
||||
|
||||
class SlotColumn : public Column {
|
||||
public:
|
||||
SlotColumn() : Column(), m_kernalPatch(nullptr), m_osType(nullptr), m_kernelVersion(nullptr) {};
|
||||
|
||||
SlotColumn(const char * t, Ion::Keyboard::Key k, const KDFont * font, int extraX, bool center, bool(*pointer)()) : Column(t, k, font, extraX, center, pointer), m_kernalPatch(nullptr), m_osType(nullptr), m_kernelVersion(nullptr) {};
|
||||
SlotColumn(const char * t, const char * k, const char * o, const char * kernelV, Ion::Keyboard::Key key, const KDFont * font, int extraX, bool center, bool(*pointer)()) : Column(t, key, font, extraX, center, pointer), m_kernalPatch(k), m_osType(o), m_kernelVersion(kernelV) {};
|
||||
|
||||
int draw(KDContext * ctx, int y, KDColor background, KDColor foreground) override;
|
||||
virtual int columnType() { return ColumnType::SLOT; };
|
||||
|
||||
private:
|
||||
const char * m_kernalPatch;
|
||||
const char * m_osType;
|
||||
const char * m_kernelVersion;
|
||||
};
|
||||
|
||||
class ColumnBinder {
|
||||
public:
|
||||
ColumnBinder() : m_pointer(nullptr), m_type(ColumnType::DEFAULT) {};
|
||||
ColumnBinder(Column * pointer) : m_pointer(pointer), m_type(ColumnType::DEFAULT) {};
|
||||
ColumnBinder(SlotColumn * pointer) : m_pointer(pointer), m_type(ColumnType::SLOT) {};
|
||||
|
||||
bool isNull() const { return m_pointer == nullptr; };
|
||||
void * getColumn() const { return m_pointer; };
|
||||
ColumnType type() const { return m_type; };
|
||||
private:
|
||||
void * m_pointer;
|
||||
ColumnType m_type;
|
||||
};
|
||||
|
||||
void open(bool noreturn = false);
|
||||
@@ -56,9 +90,11 @@ namespace Bootloader {
|
||||
|
||||
static const KDRect getScreen() { return KDRect(0, 0, 320, 240); };
|
||||
|
||||
protected:
|
||||
void forceExit() { m_forced_exit = true; };
|
||||
|
||||
private:
|
||||
static const int k_max_colomns = 5;
|
||||
static const int k_colomns_margin = 5;
|
||||
static const int k_max_columns = 6;
|
||||
|
||||
static constexpr Ion::Keyboard::Key k_breaking_keys[] = {Ion::Keyboard::Key::Back, Ion::Keyboard::Key::Home};
|
||||
|
||||
@@ -72,12 +108,18 @@ namespace Bootloader {
|
||||
void showMenu();
|
||||
|
||||
protected:
|
||||
Colomn m_colomns[k_max_colomns];
|
||||
ColumnBinder m_columns[k_max_columns];
|
||||
// Columns Storage
|
||||
Column m_default_columns[k_max_columns];
|
||||
SlotColumn m_slot_columns[k_max_columns];
|
||||
KDColor m_background;
|
||||
KDColor m_foreground;
|
||||
const char * m_title;
|
||||
const char * m_bottom;
|
||||
bool m_centerY;
|
||||
int m_margin;
|
||||
private:
|
||||
bool m_forced_exit;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
68
bootloader/interface/static/interface.cpp
Normal file
68
bootloader/interface/static/interface.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <ion.h>
|
||||
#include <ion/timing.h>
|
||||
#include <bootloader/interface/static/interface.h>
|
||||
#include <bootloader/interface/static/messages.h>
|
||||
|
||||
#include <bootloader/computer.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<uint8_t *>(pixelBuffer),
|
||||
size,
|
||||
pixelBufferSize * sizeof(KDColor)
|
||||
);
|
||||
|
||||
KDRect bounds((320 - image->width()) / 2, offset, image->width(), image->height());
|
||||
|
||||
ctx->fillRectWithPixels(bounds, pixelBuffer, nullptr);
|
||||
}
|
||||
|
||||
void Interface::drawFlasher() {
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
ctx->fillRect(KDRect(0, 0, 320, 240), KDColorWhite);
|
||||
drawImage(ctx, ImageStore::Computer, 25);
|
||||
KDSize fontSize = KDFont::LargeFont->glyphSize();
|
||||
int initPos = (320 - fontSize.width() * strlen(Messages::mainTitle)) / 2;
|
||||
ctx->drawString(Messages::mainTitle, KDPoint(initPos, ImageStore::Computer->height() + fontSize.height() + 10), KDFont::LargeFont, KDColorBlack, KDColorWhite);
|
||||
int y = ImageStore::Computer->height() + (KDFont::LargeFont->glyphSize().height() + 10) + (KDFont::SmallFont->glyphSize().height() + 10);
|
||||
initPos = (320 - KDFont::SmallFont->glyphSize().width() * strlen(Messages::dfuSlotsUpdate)) / 2;
|
||||
ctx->drawString(Messages::dfuSlotsUpdate, KDPoint(initPos, y), KDFont::SmallFont, KDColorBlack, KDColorWhite);
|
||||
}
|
||||
|
||||
void Interface::drawLoading() {
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
ctx->fillRect(KDRect(0, 0, 320, 240), KDColorWhite);
|
||||
drawImage(ctx, ImageStore::Computer, 25);
|
||||
Ion::Timing::msleep(250);
|
||||
KDSize fontSize = KDFont::LargeFont->glyphSize();
|
||||
int initPos = (320 - fontSize.width() * strlen(Messages::mainTitle)) / 2;
|
||||
for (uint8_t i = 0; i < strlen(Messages::mainTitle); i++) {
|
||||
char tmp[2] = {Messages::mainTitle[i], '\0'};
|
||||
ctx->drawString(tmp, KDPoint(initPos + i * (fontSize.width()), ImageStore::Computer->height() + fontSize.height() + 10), KDFont::LargeFont, KDColorBlack, KDColorWhite);
|
||||
Ion::Timing::msleep(50);
|
||||
}
|
||||
Ion::Timing::msleep(500);
|
||||
}
|
||||
|
||||
}
|
||||
19
bootloader/interface/static/interface.h
Normal file
19
bootloader/interface/static/interface.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef BOOTLOADER_INTERFACE_STATIC_INTERFACE_H
|
||||
#define BOOTLOADER_INTERFACE_STATIC_INTERFACE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <kandinsky/context.h>
|
||||
#include <escher/image.h>
|
||||
|
||||
namespace Bootloader {
|
||||
class Interface {
|
||||
|
||||
public:
|
||||
static void drawImage(KDContext * ctx, const Image * image, int offset);
|
||||
static void drawLoading();
|
||||
static void drawFlasher();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
93
bootloader/interface/static/messages.h
Normal file
93
bootloader/interface/static/messages.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#ifndef BOOTLOADER_INTERFACE_STATIC_MESSAGES_H
|
||||
#define BOOTLOADER_INTERFACE_STATIC_MESSAGES_H
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
class Messages {
|
||||
public:
|
||||
// TODO: Remove it when this fork will be updated
|
||||
#ifdef UPSILON_VERSION
|
||||
constexpr static const char * mainTitle = "Upsilon Calculator";
|
||||
#elif defined OMEGA_VERSION
|
||||
constexpr static const char * mainTitle = "Omega Calculator";
|
||||
#else
|
||||
constexpr static const char * mainTitle = "NumWorks Calculator";
|
||||
#endif
|
||||
|
||||
// home menu
|
||||
constexpr static const char * homeTitle = "Select a slot";
|
||||
|
||||
// Slots OS Type
|
||||
constexpr static const char * upsilonSlot = "-- Upsilon ";
|
||||
constexpr static const char * khiSlot = "-- Khi ";
|
||||
constexpr static const char * omegaSlot = "-- Omega ";
|
||||
constexpr static const char * epsilonSlot = "-- Epsilon ";
|
||||
constexpr static const char * invalidSlot = "X - Invalid slot";
|
||||
|
||||
// Home Submenu
|
||||
constexpr static const char * homeSlotASubmenu = "1 - Slot A";
|
||||
constexpr static const char * homeSlotKhiSubmenu = "2 - Slot Khi";
|
||||
constexpr static const char * homeSlotBSubmenu = "3 - Slot B";
|
||||
constexpr static const char * homeInstallerSubmenu = "4 - Installer Mode";
|
||||
constexpr static const char * homeAboutSubmenu = "5 - About";
|
||||
constexpr static const char * homeRebootSubmenu = "6 - Reboot";
|
||||
|
||||
// DFU menu
|
||||
constexpr static const char * dfuTitle = "Installer";
|
||||
|
||||
constexpr static const char * dfuSlotsUpdate = "Waiting for Slots...";
|
||||
constexpr static const char * dfuBootloaderUpdate = "Waiting for Bootloader...";
|
||||
|
||||
// Installer menu
|
||||
constexpr static const char * installerTitle = "Installer mode";
|
||||
|
||||
constexpr static const char * installerText1 = "Please select a mode:";
|
||||
constexpr static const char * installerSlotsSubmenu = "1 - Flash Slots";
|
||||
constexpr static const char * installerBootloaderSubmenu = "2 - Flash Bootloader";
|
||||
|
||||
// Bootloader Crash Handler
|
||||
constexpr static const char * bootloaderCrashTitle = "BOOTLOADER CRASH";
|
||||
|
||||
constexpr static const char * bootloaderCrashMessage1 = "The bootloader has crashed.";
|
||||
constexpr static const char * bootloaderCrashMessage2 = "Please restart the calculator.";
|
||||
|
||||
// Recovery menu
|
||||
constexpr static const char * recoveryTitle = "Recovery mode";
|
||||
|
||||
constexpr static const char * recoveryMessage1 = "The bootloader has detected a crash.";
|
||||
constexpr static const char * recoveryMessage2 = "Plug the calculator to a device capable of";
|
||||
constexpr static const char * recoveryMessage3 = "accessing the internal storage.";
|
||||
constexpr static const char * recoveryMessage4 = "Press Back to continue.";
|
||||
constexpr static const char * recoveryMessage5 = "(you will not be able to recover your data !)";
|
||||
|
||||
// Warning menu
|
||||
constexpr static const char * epsilonWarningTitle = "Epsilon Slot";
|
||||
|
||||
constexpr static const char * epsilonWarningMessage1 = "!! WARNING !! ";
|
||||
constexpr static const char * epsilonWarningMessage2 = "This version of epsilon";
|
||||
constexpr static const char * epsilonWarningMessage3 = "can lock the calculator.";
|
||||
constexpr static const char * epsilonWarningMessage4 = "Proceed the boot ?";
|
||||
constexpr static const char * epsilonWarningMessage5 = "EXE - Yes";
|
||||
constexpr static const char * epsilonWarningMessage6 = "BACK - No";
|
||||
|
||||
// About menu
|
||||
constexpr static const char * aboutMenuTitle = "About";
|
||||
|
||||
constexpr static const char * aboutMessage1 = "This is the bootloader of";
|
||||
constexpr static const char * aboutMessage2 = "the Upsilon Calculator.";
|
||||
constexpr static const char * aboutMessage3 = "It is used to install";
|
||||
constexpr static const char * aboutMessage4 = "and select the OS";
|
||||
constexpr static const char * aboutMessage5 = "to boot.";
|
||||
|
||||
constexpr static const char * bootloaderVersion = "Version 1.0.0 - FREED0M";
|
||||
|
||||
//USB NAMES
|
||||
constexpr static const char * usbUpsilonBootloader = "Upsilon Bootloader";
|
||||
constexpr static const char * usbUpsilonRecovery = "Upsilon Recovery";
|
||||
constexpr static const char * usbBootloaderUpdate = "Bootloader Update";
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -3,9 +3,9 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include <bootloader/boot.h>
|
||||
#include <bootloader/interface.h>
|
||||
#include <bootloader/slot.h>
|
||||
#include <bootloader/slot_exam_mode.h>
|
||||
#include <bootloader/interface/static/interface.h>
|
||||
#include <bootloader/slots/slot.h>
|
||||
#include <bootloader/slots/slot_exam_mode.h>
|
||||
#include <bootloader/recovery.h>
|
||||
#include <ion/src/device/shared/drivers/flash.h>
|
||||
|
||||
@@ -17,20 +17,20 @@ __attribute__ ((noreturn)) void ion_main(int argc, const char * const argv[]) {
|
||||
|
||||
// We check if there is a slot in exam_mode
|
||||
|
||||
bool isSlotA = Bootloader::Slot::A().kernelHeader()->isValid();
|
||||
bool isSlotA = Bootloader::Slot::isFullyValid(Bootloader::Slot::A());
|
||||
|
||||
if (isSlotA) {
|
||||
Bootloader::ExamMode::ExamMode SlotAExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotAExamMode(Bootloader::Slot::A().kernelHeader()->isAboveVersion16());
|
||||
Bootloader::ExamMode::ExamMode SlotAExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotAExamMode(!Bootloader::Slot::A().userlandHeader()->isOmega());
|
||||
if (SlotAExamMode != Bootloader::ExamMode::ExamMode::Off && SlotAExamMode != Bootloader::ExamMode::ExamMode::Unknown) {
|
||||
// We boot the slot in exam_mode
|
||||
Bootloader::Slot::A().boot();
|
||||
}
|
||||
}
|
||||
|
||||
bool isSlotB = Bootloader::Slot::B().kernelHeader()->isValid();
|
||||
bool isSlotB = Bootloader::Slot::isFullyValid(Bootloader::Slot::B());
|
||||
|
||||
if (isSlotB) {
|
||||
Bootloader::ExamMode::ExamMode SlotBExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotBExamMode(Bootloader::Slot::B().kernelHeader()->isAboveVersion16());
|
||||
Bootloader::ExamMode::ExamMode SlotBExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotBExamMode(!Bootloader::Slot::B().userlandHeader()->isOmega());
|
||||
if (SlotBExamMode != Bootloader::ExamMode::ExamMode::Off && SlotBExamMode != Bootloader::ExamMode::ExamMode::Unknown && isSlotB) {
|
||||
// We boot the slot in exam_mode
|
||||
Bootloader::Slot::B().boot();
|
||||
@@ -38,6 +38,18 @@ __attribute__ ((noreturn)) void ion_main(int argc, const char * const argv[]) {
|
||||
|
||||
}
|
||||
|
||||
// I have no idea if this will work, but if Pariss did a good job, it should
|
||||
|
||||
bool isKhiSlot = Bootloader::Slot::isFullyValid(Bootloader::Slot::Khi());
|
||||
|
||||
if (isKhiSlot) {
|
||||
Bootloader::ExamMode::ExamMode KhiExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotKhiExamMode();
|
||||
if (KhiExamMode != Bootloader::ExamMode::ExamMode::Off && KhiExamMode != Bootloader::ExamMode::ExamMode::Unknown && isKhiSlot) {
|
||||
// We boot the slot in exam_mode
|
||||
Bootloader::Slot::Khi().boot();
|
||||
}
|
||||
}
|
||||
|
||||
if (Bootloader::Recovery::has_crashed()) {
|
||||
Bootloader::Recovery::recover_data();
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
#ifndef BOOTLOADER_INTERFACE_MESSAGES_H
|
||||
#define BOOTLOADER_INTERFACE_MESSAGES_H
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
class Messages {
|
||||
public:
|
||||
// TODO: Remove it when this fork will be updated
|
||||
#ifdef UPSILON_VERSION
|
||||
constexpr static const char * mainTitle = "Upsilon Calculator";
|
||||
#elif defined OMEGA_VERSION
|
||||
constexpr static const char * mainTitle = "Omega Calculator";
|
||||
#else
|
||||
constexpr static const char * mainTitle = "NumWorks Calculator";
|
||||
#endif
|
||||
constexpr static const char * mainMenuTitle = "Select a slot";
|
||||
constexpr static const char * upsilon = "-- Upsilon ";
|
||||
constexpr static const char * khi = "-- Khi ";
|
||||
constexpr static const char * omega = "-- Omega ";
|
||||
constexpr static const char * epsilon = "-- Epsilon ";
|
||||
constexpr static const char * invalidSlot = "X - Invalid slot";
|
||||
constexpr static const char * dfuText = "4 - Installer Mode";
|
||||
constexpr static const char * aboutText = "5 - About";
|
||||
constexpr static const char * rebootText = "6 - Reboot";
|
||||
constexpr static const char * dfuSubtitle = "Waiting for Slots...";
|
||||
constexpr static const char * crashTitle = "BOOTLOADER CRASH";
|
||||
constexpr static const char * crashText1 = "The bootloader has crashed.";
|
||||
constexpr static const char * crashText2 = "Please restart the calculator.";
|
||||
constexpr static const char * recoveryTitle = "Recovery mode";
|
||||
constexpr static const char * recoveryText1 = "The bootloader has detected a crash.";
|
||||
constexpr static const char * recoveryText2 = "Plug the calculator to a device capable of";
|
||||
constexpr static const char * recoveryText3 = "accessing the internal storage.";
|
||||
constexpr static const char * recoveryText4 = "Press Back to continue.";
|
||||
constexpr static const char * recoveryText5 = "(you will not be able to recover your data !)";
|
||||
constexpr static const char * installerSelectionTitle = "Installer Mode";
|
||||
constexpr static const char * installerText1 = "Please select a mode:";
|
||||
constexpr static const char * installerText2 = "1. Flash slots";
|
||||
constexpr static const char * installerText3 = "2. Flash the bootloader";
|
||||
constexpr static const char * bootloaderSubtitle = "Waiting for the bootloader...";
|
||||
constexpr static const char * epsilonWarningTitle = "Epsilon Slot";
|
||||
constexpr static const char * epsilonWarningText1 = "!! WARNING !! ";
|
||||
constexpr static const char * epsilonWarningText2 = "This version of epsilon";
|
||||
constexpr static const char * epsilonWarningText3 = "can lock the calculator.";
|
||||
constexpr static const char * epsilonWarningText4 = "Proceed the boot ?";
|
||||
constexpr static const char * epsilonWarningText5 = "EXE - Yes";
|
||||
constexpr static const char * epsilonWarningText6 = "BACK - No";
|
||||
constexpr static const char * bootloaderVersion = "Version 1.0.0 - FREEDOM";
|
||||
constexpr static const char * aboutMenuTitle = "About";
|
||||
|
||||
//USB NAMES
|
||||
|
||||
constexpr static const char * upsilonBootloader = "Upsilon Bootloader";
|
||||
constexpr static const char * upsilonRecovery = "Upsilon Recovery";
|
||||
constexpr static const char * bootloaderUpdate = "Bootloader Update";
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -5,9 +5,11 @@
|
||||
#include <ion/src/device/shared/drivers/board.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <bootloader/interface.h>
|
||||
#include <bootloader/slot.h>
|
||||
#include <bootloader/interface/static/interface.h>
|
||||
#include <bootloader/slots/slot.h>
|
||||
#include <bootloader/usb_data.h>
|
||||
#include <bootloader/interface/menus/slot_recovery.h>
|
||||
#include <bootloader/interface/menus/crash.h>
|
||||
|
||||
constexpr static uint32_t MagicStorage = 0xEE0BDDBA;
|
||||
|
||||
@@ -19,11 +21,8 @@ void Bootloader::Recovery::crash_handler(const char *error) {
|
||||
Ion::Backlight::setBrightness(180);
|
||||
|
||||
Ion::Display::pushRectUniform(KDRect(0,0,320,240), KDColorWhite);
|
||||
Interface::drawCrash(error);
|
||||
|
||||
while (true) {
|
||||
|
||||
}
|
||||
CrashMenu menu(error);
|
||||
menu.open(true);
|
||||
}
|
||||
|
||||
bool Bootloader::Recovery::has_crashed() {
|
||||
@@ -76,55 +75,13 @@ void Bootloader::Recovery::recover_data() {
|
||||
Ion::Device::Board::initPeripherals(false);
|
||||
Ion::Display::pushRectUniform(KDRect(0,0,320,240), KDColorWhite);
|
||||
Ion::Backlight::init();
|
||||
Interface::drawRecovery();
|
||||
|
||||
uint64_t scan = 0;
|
||||
|
||||
USBData udata = USBData::Recovery((uint32_t)getSlotConcerned().getStorageAddress(), (uint32_t)getSlotConcerned().getStorageSize());
|
||||
|
||||
while (scan != Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
|
||||
Ion::USB::enable();
|
||||
do {
|
||||
scan = Ion::Keyboard::scan();
|
||||
if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
|
||||
Ion::USB::disable();
|
||||
}
|
||||
} while (!Ion::USB::isEnumerated() && scan != Ion::Keyboard::State(Ion::Keyboard::Key::Back));
|
||||
|
||||
if (scan != Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
|
||||
Ion::USB::DFU(true, &udata);
|
||||
}
|
||||
}
|
||||
|
||||
SlotRecoveryMenu menu = SlotRecoveryMenu(&udata);
|
||||
menu.open();
|
||||
|
||||
// Invalidate storage header
|
||||
*(uint32_t *)(getSlotConcerned().getStorageAddress()) = (uint32_t)0x0;
|
||||
|
||||
}
|
||||
|
||||
void Bootloader::Recovery::debug() {
|
||||
bool isA = Bootloader::Slot::A().kernelHeader()->isValid() && Bootloader::Slot::A().userlandHeader()->isValid();
|
||||
bool isB = Bootloader::Slot::B().kernelHeader()->isValid() && Bootloader::Slot::B().userlandHeader()->isValid();
|
||||
|
||||
if (isA) {
|
||||
const uint32_t * storage = (uint32_t *)Bootloader::Slot::A().userlandHeader()->storageAddress();
|
||||
*(uint32_t *)(0x20000070) = *storage;
|
||||
if (*storage == MagicStorage) {
|
||||
*(uint32_t *)(0x20000070 + (sizeof(uint32_t))) = 0xDEADBEEF;
|
||||
}
|
||||
}
|
||||
|
||||
if (isB) {
|
||||
const uint32_t * storage = (uint32_t *)Bootloader::Slot::B().userlandHeader()->storageAddress();
|
||||
*(uint32_t *)(0x20000070 + 2*(sizeof(uint32_t))) = *storage;
|
||||
if (*storage == MagicStorage) {
|
||||
*(uint32_t *)(0x20000070 + 3*(sizeof(uint32_t))) = 0xDEADBEEF;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_crashed()) {
|
||||
*(uint32_t *)(0x20000070 + 4*(sizeof(uint32_t))) = 0xDEADBEEF;
|
||||
} else {
|
||||
*(uint32_t *)(0x20000070 + 4*(sizeof(uint32_t))) = 0xBEEFDEAD;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ class Recovery {
|
||||
static void crash_handler(const char * error);
|
||||
static void recover_data();
|
||||
static bool has_crashed();
|
||||
static void debug();
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <bootloader/kernel_header.h>
|
||||
#include <bootloader/slots/kernel_header.h>
|
||||
#include <bootloader/utility.h>
|
||||
|
||||
namespace Bootloader {
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BOOTLOADER_KERNEL_HEADER_H
|
||||
#define BOOTLOADER_KERNEL_HEADER_H
|
||||
#ifndef BOOTLOADER_SLOTS_KERNEL_HEADER_H
|
||||
#define BOOTLOADER_SLOTS_KERNEL_HEADER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <bootloader/utility.h>
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <bootloader/slot.h>
|
||||
#include <bootloader/slots/slot.h>
|
||||
#include <ion/src/device/shared/drivers/board.h>
|
||||
#include <ion/src/device/shared/drivers/flash.h>
|
||||
#include <bootloader/boot.h>
|
||||
@@ -37,8 +37,6 @@ const UserlandHeader* Slot::userlandHeader() const {
|
||||
Ion::Device::Flash::LockSlotA();
|
||||
}
|
||||
|
||||
Boot::lockInternal();
|
||||
|
||||
// Configure the MPU for the booted firmware
|
||||
Ion::Device::Board::bootloaderMPU();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BOOTLOADER_SLOT_H
|
||||
#define BOOTLOADER_SLOT_H
|
||||
#ifndef BOOTLOADER_SLOTS_SLOT_H
|
||||
#define BOOTLOADER_SLOTS_SLOT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
const KernelHeader* kernelHeader() const;
|
||||
const UserlandHeader* userlandHeader() const;
|
||||
[[ noreturn ]] void boot() const;
|
||||
const uint32_t address() const { return m_address; }
|
||||
|
||||
static const Slot A();
|
||||
static const Slot B();
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <bootloader/slot_exam_mode.h>
|
||||
#include <bootloader/slots/slot_exam_mode.h>
|
||||
#include <assert.h>
|
||||
#include <ion.h>
|
||||
#include <ion/src/device/shared/drivers/flash.h>
|
||||
@@ -118,6 +118,32 @@ uint8_t * SignificantSlotBExamModeAddress(bool newVersion) {
|
||||
|
||||
}
|
||||
|
||||
uint8_t * SignificantSlotKhiExamModeAddress() {
|
||||
uint32_t * persitence_start_32 = (uint32_t *)SlotsExamMode::getSlotKhiStartExamAddress();
|
||||
uint32_t * persitence_end_32 = (uint32_t *)SlotsExamMode::getSlotKhiEndExamAddress();
|
||||
|
||||
assert((persitence_end_32 - persitence_start_32) % 4 == 0);
|
||||
while (persitence_start_32 < persitence_end_32 && *persitence_start_32 == 0x0) {
|
||||
// Scan by groups of 32 bits to reach first non-zero bit
|
||||
persitence_start_32++;
|
||||
}
|
||||
uint8_t * persitence_start_8 = (uint8_t *)persitence_start_32;
|
||||
uint8_t * persitence_end_8 = (uint8_t *)persitence_end_32;
|
||||
while (persitence_start_8 < persitence_end_8 && *persitence_start_8 == 0x0) {
|
||||
// Scan by groups of 8 bits to reach first non-zero bit
|
||||
persitence_start_8++;
|
||||
}
|
||||
if (persitence_start_8 == persitence_end_8
|
||||
// we can't toggle from 0[3] to 2[3] when there is only one 1 bit in the whole sector
|
||||
|| (persitence_start_8 + 1 == persitence_end_8 && *persitence_start_8 == 1)) {
|
||||
assert(Ion::Device::Flash::SectorAtAddress(SlotsExamMode::getSlotKhiStartExamAddress()) >= 0);
|
||||
Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress(SlotsExamMode::getSlotKhiStartExamAddress()));
|
||||
return (uint8_t *)SlotsExamMode::getSlotKhiStartExamAddress();
|
||||
}
|
||||
|
||||
return persitence_start_8;
|
||||
}
|
||||
|
||||
uint8_t SlotsExamMode::FetchSlotAExamMode(bool newVersion) {
|
||||
uint8_t * readingAddress = SignificantSlotAExamModeAddress(newVersion);
|
||||
if (!newVersion) {
|
||||
@@ -146,6 +172,15 @@ uint8_t SlotsExamMode::FetchSlotBExamMode(bool newVersion) {
|
||||
|
||||
}
|
||||
|
||||
uint8_t SlotsExamMode::FetchSlotKhiExamMode() {
|
||||
uint8_t * readingAddress = SignificantSlotKhiExamModeAddress();
|
||||
// Count the number of 0[3] before reading address
|
||||
uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)getSlotKhiStartExamAddress()) * numberOfBitsInByte) % 4;
|
||||
// Count the number of 0[3] at reading address
|
||||
size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*readingAddress)) % 4;
|
||||
return (nbOfZerosBefore + numberOfLeading0) % 4;
|
||||
}
|
||||
|
||||
uint32_t SlotsExamMode::getSlotAStartExamAddress(bool newVersion) {
|
||||
return newVersion ? SlotAExamModeBufferStartNewVersions : SlotAExamModeBufferStartOldVersions;
|
||||
}
|
||||
@@ -162,5 +197,13 @@ uint32_t SlotsExamMode::getSlotBEndExamAddress(bool newVersion) {
|
||||
return newVersion ? SlotBExamModeBufferEndNewVersions : SlotBExamModeBufferEndOldVersions;
|
||||
}
|
||||
|
||||
uint32_t SlotsExamMode::getSlotKhiStartExamAddress() {
|
||||
return SlotKhiExamModeBufferStart;
|
||||
}
|
||||
|
||||
uint32_t SlotsExamMode::getSlotKhiEndExamAddress() {
|
||||
return SlotKhiExamModeBufferEnd;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BOOTLOADER_EXAM_MODE_H
|
||||
#define BOOTLOADER_EXAM_MODE_H
|
||||
#ifndef BOOTLOADER_SLOTS_EXAM_MODE_H
|
||||
#define BOOTLOADER_SLOTS_EXAM_MODE_H
|
||||
|
||||
extern "C" {
|
||||
#include <stdint.h>
|
||||
@@ -20,15 +20,21 @@ static const uint32_t SlotBExamModeBufferEndOldVersions = 0x90403000;
|
||||
static const uint32_t SlotBExamModeBufferStartNewVersions = 0x907f0000;
|
||||
static const uint32_t SlotBExamModeBufferEndNewVersions = 0x90800000;
|
||||
|
||||
static const uint32_t SlotKhiExamModeBufferStart = 0x90181000;
|
||||
static const uint32_t SlotKhiExamModeBufferEnd = 0x90183000;
|
||||
|
||||
class SlotsExamMode{
|
||||
public:
|
||||
static uint8_t FetchSlotAExamMode(bool newVersion);
|
||||
static uint8_t FetchSlotBExamMode(bool newVerion);
|
||||
static uint8_t FetchSlotKhiExamMode();
|
||||
|
||||
static uint32_t getSlotAStartExamAddress(bool newVersion);
|
||||
static uint32_t getSlotAEndExamAddress(bool newVersion);
|
||||
static uint32_t getSlotBStartExamAddress(bool newVersion);
|
||||
static uint32_t getSlotBEndExamAddress(bool newVersion);
|
||||
static uint32_t getSlotKhiStartExamAddress();
|
||||
static uint32_t getSlotKhiEndExamAddress();
|
||||
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <bootloader/userland_header.h>
|
||||
#include <bootloader/slots/userland_header.h>
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BOOTLOADER_USERLAND_HEADER_H
|
||||
#define BOOTLOADER_USERLAND_HEADER_H
|
||||
#ifndef BOOTLOADER_SLOTS_USERLAND_HEADER_H
|
||||
#define BOOTLOADER_SLOTS_USERLAND_HEADER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <bootloader/usb_data.h>
|
||||
#include <bootloader/interface/static/messages.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <bootloader/utility.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <bootloader/messages.h>
|
||||
|
||||
extern "C" {
|
||||
}
|
||||
@@ -13,13 +13,13 @@ static char data[255];
|
||||
|
||||
const char * Bootloader::USBData::buildStringDescriptor(StringHeader header, uint32_t startAddress, uint32_t size) {
|
||||
strlcpy(data, header.getString(), sizeof(data));
|
||||
Bootloader::Utility::itoa((int32_t)startAddress, &data[strlen(header.getString())], 16);
|
||||
itoa((int32_t)startAddress, &data[strlen(header.getString())], 16);
|
||||
data[strlen(header.getString()) + 8] = '/';
|
||||
data[strlen(header.getString()) + 8 + 1] = '0';
|
||||
data[strlen(header.getString()) + 8 + 2] = '1';
|
||||
data[strlen(header.getString()) + 8 + 3] = '*';
|
||||
data[strlen(header.getString()) + 8 + 4] = '0';
|
||||
Bootloader::Utility::itoa((int32_t)size/1024, &data[strlen(header.getString()) + 8 + 5], 10);
|
||||
itoa((int32_t)size/1024, &data[strlen(header.getString()) + 8 + 5], 10);
|
||||
data[strlen(header.getString()) + 8 + 5 + 2] = 'K';
|
||||
data[strlen(header.getString()) + 8 + 5 + 2 + 1] = 'g';
|
||||
data[strlen(header.getString()) + 8 + 5 + 2 + 2] = '\0';
|
||||
@@ -27,13 +27,13 @@ const char * Bootloader::USBData::buildStringDescriptor(StringHeader header, uin
|
||||
}
|
||||
|
||||
const Bootloader::USBData Bootloader::USBData::DEFAULT() {
|
||||
return USBData("@Flash/0x90000000/08*004Kg,01*032Kg,63*064Kg,64*064Kg", Messages::upsilonBootloader, ProtectionState());
|
||||
return USBData("@Flash/0x90000000/08*004Kg,01*032Kg,63*064Kg,64*064Kg", Messages::usbUpsilonBootloader, ProtectionState(false, true));
|
||||
}
|
||||
|
||||
const Bootloader::USBData Bootloader::USBData::BOOTLOADER_UPDATE() {
|
||||
return USBData("@Flash/0x08000000/04*016Kg", Messages::bootloaderUpdate, ProtectionState(true, false));
|
||||
return USBData("@Flash/0x08000000/04*016Kg", Messages::usbBootloaderUpdate, ProtectionState(true, false));
|
||||
}
|
||||
|
||||
Bootloader::USBData Bootloader::USBData::Recovery(uint32_t startAddress, uint32_t size) {
|
||||
return USBData(buildStringDescriptor(StringHeader::SRAM(), startAddress, size), Messages::upsilonRecovery, ProtectionState(false, false));
|
||||
return USBData(buildStringDescriptor(StringHeader::SRAM(), startAddress, size), Messages::usbUpsilonRecovery, ProtectionState(false, false));
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ class USBData {
|
||||
const char * m_string;
|
||||
};
|
||||
|
||||
USBData(const char * desc, const char * name, ProtectionState data = ProtectionState()) : m_stringDescriptor(desc), m_name(name), m_data(&data) {};
|
||||
USBData(const char * desc, const char * name, ProtectionState data = ProtectionState()) : m_stringDescriptor(desc), m_name(name), m_data(data) {};
|
||||
|
||||
const char * stringDescriptor() const { return m_stringDescriptor; }
|
||||
const char * getName() const { return m_name; }
|
||||
ProtectionState * getData() const { return m_data; }
|
||||
ProtectionState getData() const { return m_data; }
|
||||
|
||||
static const char * buildStringDescriptor(StringHeader header, uint32_t startAddress, uint32_t size);
|
||||
|
||||
@@ -48,7 +48,7 @@ class USBData {
|
||||
private:
|
||||
const char * m_stringDescriptor;
|
||||
const char * m_name;
|
||||
ProtectionState * m_data;
|
||||
ProtectionState m_data;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
const char* stringDescriptor() {
|
||||
return "@Flash/0x90000000/08*004Kg,01*032Kg,63*064Kg,64*064Kg";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <bootloader/utility.h>
|
||||
#include <string.h>
|
||||
|
||||
int Bootloader::Utility::versionSum(const char * version, int length) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
sum += version[i] * (strlen(version) * 100 - i * 10);
|
||||
}
|
||||
return sum;
|
||||
int Utility::versionSum(const char * version, int length) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
sum += version[i] * (strlen(version) * 100 - i * 10);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
#ifndef _BOOTLOADER_ITOA_H_
|
||||
#define _BOOTLOADER_ITOA_H_
|
||||
|
||||
namespace Bootloader {
|
||||
class Utility {
|
||||
public:
|
||||
static char * itoa(int value, char * result, int base);
|
||||
static int versionSum(const char * version, int length);
|
||||
};
|
||||
namespace Utility {
|
||||
extern int versionSum(const char * version, int length);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,6 +45,14 @@ SECTIONS {
|
||||
_exam_mode_buffer_end = .;
|
||||
} >INTERNAL_FLASH
|
||||
|
||||
.fake_isr_function : {
|
||||
. = ALIGN(4);
|
||||
_fake_isr_function_start = .;
|
||||
KEEP(*(.fake_isr_function))
|
||||
KEEP(*(.fake_isr_function.*))
|
||||
_fake_isr_function_end = .;
|
||||
}
|
||||
|
||||
.text : {
|
||||
. = ALIGN(4);
|
||||
*(.text)
|
||||
|
||||
@@ -211,23 +211,14 @@ void DFUInterface::eraseMemoryIfNeeded() {
|
||||
|
||||
willErase();
|
||||
|
||||
Bootloader::ProtectionState * config = getDfuConfig();
|
||||
Bootloader::ProtectionState config = getDfuConfig();
|
||||
|
||||
if (config != nullptr) {
|
||||
// More simple to read
|
||||
if ((0x08000000 <= m_eraseAddress && m_eraseAddress <= 0x08010000)&& !m_dfuData.isProtectedInternal()) {
|
||||
Flash::EraseSector(m_erasePage);
|
||||
} else if ((0x90000000 <= m_eraseAddress && m_eraseAddress <= 0x90800000)&& !m_dfuData.isProtectedExternal()) {
|
||||
Flash::EraseSector(m_erasePage);
|
||||
}
|
||||
} else {
|
||||
if (m_erasePage == Flash::TotalNumberOfSectors()) {
|
||||
Flash::MassErase();
|
||||
} else {
|
||||
Flash::EraseSector(m_erasePage);
|
||||
}
|
||||
// More simple to read
|
||||
if ((0x08000000 <= m_eraseAddress && m_eraseAddress <= 0x08010000)&& !m_dfuData.isProtectedInternal()) {
|
||||
Flash::EraseSector(m_erasePage);
|
||||
} else if ((0x90000000 <= m_eraseAddress && m_eraseAddress <= 0x90800000)&& !m_dfuData.isProtectedExternal()) {
|
||||
Flash::EraseSector(m_erasePage);
|
||||
}
|
||||
|
||||
/* Put an out of range value in m_erasePage to indicate that no erase is
|
||||
* waiting. */
|
||||
m_erasePage = -1;
|
||||
@@ -242,15 +233,11 @@ void DFUInterface::writeOnMemory() {
|
||||
memcpy((void *)m_writeAddress, m_largeBuffer, m_largeBufferLength);
|
||||
} else if (Flash::SectorAtAddress(m_writeAddress) >= 0) {
|
||||
|
||||
Bootloader::ProtectionState * config = getDfuConfig();
|
||||
Bootloader::ProtectionState config = getDfuConfig();
|
||||
|
||||
if (config != nullptr) {
|
||||
if (m_writeAddress >= 0x08000000 && m_writeAddress <= 0x08010000 && !m_dfuData.isProtectedInternal()) {
|
||||
Flash::WriteMemory(reinterpret_cast<uint8_t *>(m_writeAddress), m_largeBuffer, m_largeBufferLength);
|
||||
} else if (m_writeAddress >= 0x90000000 && m_writeAddress <= 0x90800000 && !m_dfuData.isProtectedExternal()) {
|
||||
Flash::WriteMemory(reinterpret_cast<uint8_t *>(m_writeAddress), m_largeBuffer, m_largeBufferLength);
|
||||
}
|
||||
} else {
|
||||
if (m_writeAddress >= 0x08000000 && m_writeAddress <= 0x08010000 && !m_dfuData.isProtectedInternal()) {
|
||||
Flash::WriteMemory(reinterpret_cast<uint8_t *>(m_writeAddress), m_largeBuffer, m_largeBufferLength);
|
||||
} else if (m_writeAddress >= 0x90000000 && m_writeAddress <= 0x90800000 && !m_dfuData.isProtectedExternal()) {
|
||||
Flash::WriteMemory(reinterpret_cast<uint8_t *>(m_writeAddress), m_largeBuffer, m_largeBufferLength);
|
||||
}
|
||||
|
||||
@@ -306,7 +293,7 @@ void DFUInterface::leaveDFUAndReset() {
|
||||
}
|
||||
|
||||
void DFUInterface::copyDfuData() {
|
||||
m_dfuData = Bootloader::ProtectionState(!m_dfuConfig->isProtectedInternal(), !m_dfuConfig->isProtectedExternal());
|
||||
m_dfuData = Bootloader::ProtectionState(!m_dfuConfig.isProtectedInternal(), !m_dfuConfig.isProtectedExternal());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
m_writeAddress(0),
|
||||
m_bInterfaceAlternateSetting(bInterfaceAlternateSetting),
|
||||
m_isErasingAndWriting(false),
|
||||
m_dfuConfig(nullptr),
|
||||
m_dfuConfig(),
|
||||
m_eraseAddress(0),
|
||||
m_dfuData()
|
||||
{
|
||||
@@ -40,8 +40,8 @@ public:
|
||||
void wholeDataSentCallback(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength) override;
|
||||
bool isErasingAndWriting() const { return m_isErasingAndWriting; }
|
||||
|
||||
void setDfuConfig(Bootloader::ProtectionState * data) { m_dfuConfig = data; copyDfuData(); }
|
||||
Bootloader::ProtectionState * getDfuConfig() const { return m_dfuConfig; }
|
||||
void setDfuConfig(Bootloader::ProtectionState data) { m_dfuConfig = data; copyDfuData(); }
|
||||
Bootloader::ProtectionState getDfuConfig() const { return m_dfuConfig; }
|
||||
|
||||
protected:
|
||||
void setActiveInterfaceAlternative(uint8_t interfaceAlternativeIndex) override {
|
||||
@@ -180,7 +180,7 @@ private:
|
||||
uint32_t m_writeAddress;
|
||||
uint8_t m_bInterfaceAlternateSetting;
|
||||
bool m_isErasingAndWriting;
|
||||
Bootloader::ProtectionState * m_dfuConfig;
|
||||
Bootloader::ProtectionState m_dfuConfig;
|
||||
uint32_t m_eraseAddress;
|
||||
Bootloader::ProtectionState m_dfuData;
|
||||
};
|
||||
|
||||
@@ -40,6 +40,7 @@ void writePCBVersion(PCBVersion version);
|
||||
void lockPCBVersion();
|
||||
bool pcbVersionIsLocked();
|
||||
|
||||
void jumpToInternalBootloader();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,14 @@ void SetInternalSectorProtection(int i, bool protect) {
|
||||
InternalFlash::SetSectorProtection(i, protect);
|
||||
}
|
||||
|
||||
void EnableInternalSessionLock() {
|
||||
InternalFlash::EnableSessionLock();
|
||||
}
|
||||
|
||||
void EnableInternalFlashInterrupt() {
|
||||
InternalFlash::EnableFlashInterrupt();
|
||||
}
|
||||
|
||||
void LockSlotA() {
|
||||
ExternalFlash::LockSlotA();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ void WriteMemory(uint8_t * destination, uint8_t * source, size_t length);
|
||||
void DisableInternalProtection();
|
||||
void EnableInternalProtection();
|
||||
void SetInternalSectorProtection(int i, bool protect);
|
||||
void EnableInternalSessionLock(); // Will cause BUSERR when enabled
|
||||
void EnableInternalFlashInterrupt();
|
||||
void LockSlotA();
|
||||
void LockSlotB();
|
||||
|
||||
|
||||
@@ -344,6 +344,25 @@ void SetSectorProtection(int i, bool protect) {
|
||||
}
|
||||
}
|
||||
|
||||
void EnableSessionLock() {
|
||||
if (FLASH.OPTCR()->getLOCK()) {
|
||||
// writing bullshit to the lock register to lock it until next core reset
|
||||
FLASH.OPTKEYR()->set(0x00000000);
|
||||
FLASH.OPTKEYR()->set(0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
void EnableFlashInterrupt() {
|
||||
open();
|
||||
FLASH.CR()->setERRIE(true);
|
||||
wait();
|
||||
FLASH.CR()->setEOPIE(true);
|
||||
wait();
|
||||
FLASH.CR()->setRDERRIE(true);
|
||||
wait();
|
||||
close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ void WriteMemory(uint8_t * destination, uint8_t * source, size_t length);
|
||||
void EnableProtection();
|
||||
void DisableProtection();
|
||||
void SetSectorProtection(int i, bool protect);
|
||||
void EnableSessionLock();
|
||||
void EnableFlashInterrupt();
|
||||
|
||||
/* The Device is powered by a 2.8V LDO. This allows us to perform writes to the
|
||||
* Flash 32 bits at once. */
|
||||
|
||||
@@ -45,6 +45,9 @@ public:
|
||||
REGS_FIELD(SNB, uint8_t, 6, 3);
|
||||
REGS_TYPE_FIELD(PSIZE, 9, 8);
|
||||
REGS_BOOL_FIELD(STRT, 16);
|
||||
REGS_BOOL_FIELD(EOPIE, 24);
|
||||
REGS_BOOL_FIELD(ERRIE, 25);
|
||||
REGS_BOOL_FIELD(RDERRIE, 26)
|
||||
REGS_BOOL_FIELD(LOCK, 31);
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@ public:
|
||||
public:
|
||||
REGS_BOOL_FIELD(HSION, 0);
|
||||
REGS_BOOL_FIELD(HSIRDY, 1);
|
||||
REGS_BOOL_FIELD(HSITRIM1, 3);
|
||||
REGS_BOOL_FIELD(HSITRIM2, 4);
|
||||
REGS_BOOL_FIELD(HSITRIM3, 5);
|
||||
REGS_BOOL_FIELD(HSITRIM4, 6);
|
||||
REGS_BOOL_FIELD(HSITRIM5, 7);
|
||||
REGS_BOOL_FIELD(HSICAL, 8);
|
||||
REGS_BOOL_FIELD(HSEON, 16);
|
||||
REGS_BOOL_FIELD_R(HSERDY, 17);
|
||||
REGS_BOOL_FIELD(PLLON, 24);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <regs/config/syscfg.h>
|
||||
#include "gpio.h"
|
||||
|
||||
#define REGS_SYSCFG_CONFIG_F412 1
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Regs {
|
||||
|
||||
@@ -24,6 +24,7 @@ liba_src += $(addprefix liba/src/, \
|
||||
strlcpy.c \
|
||||
strlen.c \
|
||||
external/sqlite/mem5.c \
|
||||
itoa.c \
|
||||
)
|
||||
|
||||
liba_src += $(addprefix liba/src/external/openbsd/, \
|
||||
|
||||
@@ -10,6 +10,7 @@ void free(void *ptr);
|
||||
void * malloc(size_t size);
|
||||
void * realloc(void *ptr, size_t size);
|
||||
void * calloc(size_t count, size_t size);
|
||||
char * itoa(int value, char *str, int base);
|
||||
|
||||
void abort(void) __attribute__((noreturn));
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <bootloader/utility.h>
|
||||
|
||||
// https://www.techiedelight.com/implement-itoa-function-in-c/
|
||||
|
||||
@@ -19,7 +18,7 @@ char* reverse(char *buffer, int i, int j) {
|
||||
}
|
||||
|
||||
// Iterative function to implement `itoa()` function in C
|
||||
char* Bootloader::Utility::itoa(int value, char* buffer, int base) {
|
||||
char* itoa(int value, char* buffer, int base) {
|
||||
// invalid input
|
||||
if (base < 2 || base > 32) {
|
||||
return buffer;
|
||||
BIN
themes/themes/local/upsilon_light/bootloader/cable.png
Normal file
BIN
themes/themes/local/upsilon_light/bootloader/cable.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 179 B |
BIN
themes/themes/local/upsilon_light/bootloader/computer.xcf
Normal file
BIN
themes/themes/local/upsilon_light/bootloader/computer.xcf
Normal file
Binary file not shown.
Reference in New Issue
Block a user