Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[recovery] Recovery Improvements #234

Open
wants to merge 13 commits into
base: upsilon-dev
Choose a base branch
from
1 change: 1 addition & 0 deletions bootloader/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ bootloader_src += $(addprefix bootloader/interface/menus/, \
warning.cpp \
slot_recovery.cpp \
crash.cpp \
upsilon_recovery.cpp \
)

bootloader_images = $(addprefix bootloader/, \
Expand Down
2 changes: 1 addition & 1 deletion bootloader/boot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ bool Boot::isKernelPatched(const Slot & s) {
return *(uint32_t *)(origin_isr + sizeof(uint32_t) * 7) == ((uint32_t)&_fake_isr_function_start) + 1;
}

__attribute((section(".fake_isr_function"))) __attribute__((used)) void Boot::flash_interrupt() {
__attribute__((section(".fake_isr_function"))) __attribute__((used)) void Boot::flash_interrupt() {
// a simple function
Ion::Device::Flash::ClearInternalFlashErrors();
asm("bx lr");
Expand Down
2 changes: 1 addition & 1 deletion bootloader/boot.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Boot {
static void bootSlot(Bootloader::Slot slot);
static void bootSelectedSlot();
__attribute__ ((noreturn)) static void jumpToInternalBootloader();
__attribute((section(".fake_isr_function"))) __attribute__((used)) static void flash_interrupt();
__attribute__ ((section(".fake_isr_function"))) __attribute__((used)) static void flash_interrupt();

static void bootloader();
static void lockInternal();
Expand Down
48 changes: 48 additions & 0 deletions bootloader/interface/menus/upsilon_recovery.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "upsilon_recovery.h"
#include <bootloader/slots/slot.h>
#include <bootloader/usb_data.h>
#include <ion/src/device/shared/drivers/board.h>
#include <ion.h>
#include <stdlib.h>

extern "C" void jump_to_firmware(const uint32_t* stackPtr, const void(*startPtr)(void));

Bootloader::UpsilonRecoveryMenu::UpsilonRecoveryMenu() : Menu(KDColorBlack, KDColorWhite, Messages::upsilonRecoveryTitle, Messages::mainTitle) {
setup();
}

void Bootloader::UpsilonRecoveryMenu::setup() {
m_defaultColumns[0] = Column(Messages::upsilonRecoveryMessage1, k_small_font, 0, true);
m_defaultColumns[1] = Column(Messages::upsilonRecoveryMessage2, k_small_font, 0, true);
m_defaultColumns[2] = Column(Messages::upsilonRecoveryMessage3, k_small_font, 0, true);
m_defaultColumns[3] = Column(Messages::upsilonRecoveryMessage4, k_small_font, 0, true);
m_defaultColumns[4] = Column(Messages::upsilonRecoveryMessage5, k_small_font, 0, true);

m_columns[0] = ColumnBinder(&m_defaultColumns[0]);
m_columns[1] = ColumnBinder(&m_defaultColumns[1]);
m_columns[2] = ColumnBinder(&m_defaultColumns[2]);
m_columns[3] = ColumnBinder(&m_defaultColumns[3]);
m_columns[4] = ColumnBinder(&m_defaultColumns[4]);
}

void Bootloader::UpsilonRecoveryMenu::postOpen() {
// We override the open method
for (;;) {
uint64_t scan = Ion::Keyboard::scan();
if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::Back)) {
while (Ion::Keyboard::scan() == Ion::Keyboard::State(Ion::Keyboard::Key::Back));
forceExit();
return;
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::OnOff)) {
Ion::Power::suspend();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you redraw the screen after it ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean, relaunch the recovery mode ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the screen it powered down, it lost the frame buffer, you need to draw the menu a new time, not necessary by relaunching it.

return;
} else if (scan == Ion::Keyboard::State(Ion::Keyboard::Key::OK)) {
Slot slot = Slot::Upsilon();
Ion::Device::Board::bootloaderMPU();
// Deinitialize the backlight to prevent bugs when the firmware boots
Ion::Backlight::shutdown();
jump_to_firmware(slot.kernelHeader()->stackPointer(), slot.userlandHeader()->upsilonRecoveryBootFunction());
for(;;);
}
}
}
15 changes: 15 additions & 0 deletions bootloader/interface/menus/upsilon_recovery.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef _BOOTLOADER_INTERFACE_MENUS_UPSILON_RECOVERY_H_
#define _BOOTLOADER_INTERFACE_MENUS_UPSILON_RECOVERY_H_

#include <bootloader/interface/src/menu.h>

namespace Bootloader {
class UpsilonRecoveryMenu : public Menu {
public:
UpsilonRecoveryMenu();
void setup() override;
void postOpen() override;
};
}

#endif
9 changes: 9 additions & 0 deletions bootloader/interface/static/messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ class Messages {
constexpr static const char * recoveryMessage4 = "Press Back to continue.";
constexpr static const char * recoveryMessage5 = "(you will not be able to recover your data !)";

// Upsilon Recovery menu
constexpr static const char * upsilonRecoveryTitle = "Upsilon Recovery";

constexpr static const char * upsilonRecoveryMessage1 = "The bootloader has detected a crash.";
constexpr static const char * upsilonRecoveryMessage2 = "Because you also have an Upsilon slot,";
constexpr static const char * upsilonRecoveryMessage3 = "you can recover your data by booting";
constexpr static const char * upsilonRecoveryMessage4 = "the Upsilon slot.";
constexpr static const char * upsilonRecoveryMessage5 = "Press OK to continue, BACK to cancel";

// Warning menu
constexpr static const char * epsilonWarningTitle = "Epsilon Slot";

Expand Down
12 changes: 11 additions & 1 deletion bootloader/recovery.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <bootloader/recovery.h>
#include <ion.h>
#include <ion/src/device/n0110/drivers/power.h>
#include <ion/src/device/shared/drivers/bldata.h>
#include <ion/src/device/shared/drivers/reset.h>
#include <ion/src/device/shared/drivers/board.h>
#include <assert.h>
Expand All @@ -10,6 +11,7 @@
#include <bootloader/usb_data.h>
#include <bootloader/interface/menus/slot_recovery.h>
#include <bootloader/interface/menus/crash.h>
#include <bootloader/interface/menus/upsilon_recovery.h>

constexpr static uint32_t MagicStorage = 0xEE0BDDBA;

Expand Down Expand Up @@ -76,7 +78,15 @@ void Bootloader::Recovery::recoverData() {
Ion::Display::pushRectUniform(KDRect(0,0,320,240), KDColorWhite);
Ion::Backlight::init();

USBData udata = USBData::Recovery((uint32_t)getSlotConcerned().getStorageAddress(), (uint32_t)getSlotConcerned().getStorageSize());
CrashedSlot slot = getSlotConcerned();

if (Slot::hasUpsilon() && Slot::Upsilon().userlandHeader()->hasUpsilonExtras()) {
Ion::Device::BootloaderSharedData::sharedBootloaderData()->setRecovery((uint32_t)slot.getStorageAddress(), slot.getStorageSize());
UpsilonRecoveryMenu reco = UpsilonRecoveryMenu();
reco.open();
}

USBData udata = USBData::Recovery((uint32_t)slot.getStorageAddress(), (uint32_t)slot.getStorageSize());

SlotRecoveryMenu menu = SlotRecoveryMenu(&udata);
menu.open();
Expand Down
14 changes: 14 additions & 0 deletions bootloader/slots/slot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include <ion/src/device/shared/drivers/board.h>
#include <ion/src/device/shared/drivers/flash.h>
#include <bootloader/boot.h>
#include <assert.h>
#include <ion.h>

extern "C" void jump_to_firmware(const uint32_t* stackPtr, const void(*startPtr)(void));

Expand All @@ -19,6 +21,15 @@ const Slot Slot::Khi() {
return Slot(0x90180000);
}

const bool Slot::hasUpsilon() {
return (isFullyValid(A()) && A().userlandHeader()->isUpsilon()) || (isFullyValid(B()) && B().userlandHeader()->isUpsilon());
}

const Slot Slot::Upsilon() {
assert(hasUpsilon());
return (isFullyValid(A()) && A().userlandHeader()->isUpsilon()) ? A() : B();
}

const KernelHeader* Slot::kernelHeader() const {
return m_kernelHeader;
}
Expand All @@ -40,6 +51,9 @@ const UserlandHeader* Slot::userlandHeader() const {
// Configure the MPU for the booted firmware
Ion::Device::Board::bootloaderMPU();

// Deinitialize the backlight to prevent bugs when the firmware boots
Ion::Backlight::shutdown();

// Jump
jump_to_firmware(kernelHeader()->stackPointer(), kernelHeader()->startPointer());
for(;;);
Expand Down
2 changes: 2 additions & 0 deletions bootloader/slots/slot.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class Slot {
static const Slot A();
static const Slot B();
static const Slot Khi();
static const bool hasUpsilon();
static const Slot Upsilon();

static bool isFullyValid(const Slot& slot) {
return slot.kernelHeader()->isValid() && slot.userlandHeader()->isValid();
Expand Down
12 changes: 12 additions & 0 deletions bootloader/slots/userland_header.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,16 @@ const size_t UserlandHeader::storageSize() const {
return m_storageSizeRAM;
}

const bool UserlandHeader::hasUpsilonExtras() const {
return m_upsilonExtraMagicHeader == UpsilonExtraMagic && m_upsilonExtraMagicFooter == UpsilonExtraMagic;
}

const uint16_t UserlandHeader::getExtraVersion() const {
return m_extraVersion;
}

const void (*UserlandHeader::upsilonRecoveryBootFunction() const)() {
return m_recoveryAddress;
}

}
9 changes: 9 additions & 0 deletions bootloader/slots/userland_header.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@ class UserlandHeader {
const char * upsilonVersion() const;
const void * storageAddress() const;
const size_t storageSize() const;
const bool hasUpsilonExtras() const;
const void (*upsilonRecoveryBootFunction() const)();
const uint32_t getExtraVersion() const;


private:
UserlandHeader();
constexpr static uint32_t Magic = 0xDEC0EDFE;
constexpr static uint32_t OmegaMagic = 0xEFBEADDE;
constexpr static uint32_t UpsilonMagic = 0x55707369;
constexpr static uint32_t UpsilonExtraMagic = 0xaa7073ff;
uint32_t m_header;
const char m_expectedEpsilonVersion[8];
void * m_storageAddressRAM;
Expand All @@ -42,6 +47,10 @@ class UserlandHeader {
const char m_UpsilonVersion[16];
uint32_t m_osType;
uint32_t m_upsilonMagicFooter;
uint32_t m_upsilonExtraMagicHeader;
const void (*m_recoveryAddress)();
uint32_t m_extraVersion;
uint32_t m_upsilonExtraMagicFooter;
};

extern const UserlandHeader* s_userlandHeaderA;
Expand Down
45 changes: 45 additions & 0 deletions ion/src/device/bootloader/boot/rt0.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#include <stdint.h>
#include <string.h>
#include <ion.h>
#include <ion/led.h>
#include <ion/storage.h>
#include <ion/internal_storage.h>
#include <boot/isr.h>
#include <drivers/board.h>
#include <drivers/rtc.h>
#include <drivers/reset.h>
#include <drivers/timing.h>
#include <drivers/bldata.h>

typedef void (*cxx_constructor)();

Expand All @@ -14,6 +18,8 @@ extern "C" {
extern char _data_section_start_ram;
extern char _data_section_end_ram;
extern char _bss_section_start_ram;
extern char _static_storage_start;
extern char _static_storage_end;
extern char _bss_section_end_ram;
extern cxx_constructor _init_array_start;
extern cxx_constructor _init_array_end;
Expand Down Expand Up @@ -129,6 +135,45 @@ void __attribute__((noinline)) start() {
abort();
}

void __attribute__((noinline)) __attribute__((section(".recovery_boot"))) __attribute__((used)) recovery_start() {
// Here we are in the recovery boot.
Ion::Device::Board::initFPU();

bool is_recoverying = Ion::Device::BootloaderSharedData::sharedBootloaderData()->storageAddress() != 0;

if (is_recoverying) {
uint32_t address = Ion::Device::BootloaderSharedData::sharedBootloaderData()->storageAddress();
uint32_t size = Ion::Device::BootloaderSharedData::sharedBootloaderData()->storageSize();

size_t storageSize = (&_static_storage_end - &_static_storage_start);

memcpy(&_static_storage_start, (void*)address, size);

size_t dataSectionLength = (&_data_section_end_ram - &_data_section_start_ram);
memcpy(&_data_section_start_ram, &_data_section_start_flash, dataSectionLength);

size_t bssSectionLength = (&_bss_section_end_ram - &_static_storage_end);
memset(&_static_storage_end, 0, bssSectionLength);
} else {
size_t dataSectionLength = (&_data_section_end_ram - &_data_section_start_ram);
memcpy(&_data_section_start_ram, &_data_section_start_flash, dataSectionLength);
size_t bssSectionLength = (&_bss_section_end_ram - &_bss_section_start_ram);
memset(&_bss_section_start_ram, 0, bssSectionLength);
}

if (&_init_array_start != &_init_array_end) {
abort();
}
size_t isrSectionLength = (&_isr_vector_table_end_ram - &_isr_vector_table_start_ram);
memcpy(&_isr_vector_table_start_ram, &_isr_vector_table_start_flash, isrSectionLength);

Ion::Device::Board::init();

jump_to_external_flash();

abort();
}

void __attribute__((interrupt, noinline)) isr_systick() {
auto t = Ion::Device::Timing::MillisElapsed;
t++;
Expand Down
29 changes: 27 additions & 2 deletions ion/src/device/bootloader/bootloader_common.ld
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
BOOTLOADER_SHARED_OFFSET = 0x3d0;

SECTIONS {
.signed_payload_prefix ORIGIN(FLASH) : {
Expand Down Expand Up @@ -34,7 +35,14 @@ SECTIONS {
_isr_vector_table_end_ram = .;
} >SRAM

.exam_mode_buffer ORIGIN(FLASH) + SIZEOF(.signed_payload_prefix) + SIZEOF(.kernel_header) + SIZEOF(.isr_vector_table) : {
.bootloader_shared ORIGIN(SRAM) + BOOTLOADER_SHARED_OFFSET : AT(ORIGIN(FLASH) + SIZEOF(.signed_payload_prefix) + SIZEOF(.kernel_header) + SIZEOF(.isr_vector_table) + SIZEOF(.slot_info)) {
_bootloader_shared_start = .;
KEEP(*(.bootloader_shared))
KEEP(*(.bootloader_shared.*))
_bootloader_shared_end = .;
} >SRAM

.exam_mode_buffer ORIGIN(FLASH) + SIZEOF(.signed_payload_prefix) + SIZEOF(.kernel_header) + SIZEOF(.isr_vector_table) + SIZEOF(.bootloader_shared) + SIZEOF(.slot_info) : {
. = ALIGN(4K);
_exam_mode_buffer_start = .;
KEEP(*(.exam_mode_buffer))
Expand All @@ -49,6 +57,13 @@ SECTIONS {
KEEP(*(.userland_header));
} > FLASH

.recovery_boot : {
. = ALIGN(4);
_recovery_boot_start = .;
KEEP(*(.recovery_boot));
_recovery_boot_end = .;
} >FLASH

.text : {
. = ALIGN(4);
*(.text)
Expand Down Expand Up @@ -88,6 +103,17 @@ SECTIONS {
_data_section_end_ram = .;
} >SRAM AT> FLASH

/*
* We set the .static_storage right after the .data section, even if it's a bss region, because we need to fix it in memory.
*/
.static_storage : {
. = ALIGN(4);
_bss_section_start_ram = .;
_static_storage_start = .;
KEEP (*(.static_storage))
_static_storage_end = .;
} > SRAM

.bss : {
/* The bss section contains data for all uninitialized variables
* So like the .data section, it will go in RAM, but unlike the data section
Expand All @@ -96,7 +122,6 @@ SECTIONS {
* Before execution, crt0 will erase that section of memory though, so we'll
* need pointers to the beginning and end of this section. */
. = ALIGN(4);
_bss_section_start_ram = .;
*(.bss)
*(.bss.*)
/* The compiler may choose to allocate uninitialized global variables as
Expand Down
12 changes: 11 additions & 1 deletion ion/src/device/bootloader/internal_flash.ld
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ MEMORY {
STACK_SIZE = 32K;
TRAMPOLINES_OFFSET = 0xE000;
CUSTOM_TRAMPOLINES_OFFSET = 64K - 64;
BOOTLOADER_SHARED_OFFSET = 0x3d0;

SECTIONS {
.isr_vector_table ORIGIN(INTERNAL_FLASH) : {
Expand All @@ -31,7 +32,16 @@ SECTIONS {
KEEP(*(.header))
} >INTERNAL_FLASH

.rodata : {
.bootloader_shared ORIGIN(SRAM) + BOOTLOADER_SHARED_OFFSET : AT(ORIGIN(INTERNAL_FLASH) + SIZEOF(.isr_vector_table) + SIZEOF(.header)) {
. = ORIGIN(SRAM) + BOOTLOADER_SHARED_OFFSET;
_bootloader_shared_start = .;
KEEP(*(.bootloader_shared))
KEEP(*(.bootloader_shared.*))
_bootloader_shared_end = .;
} >SRAM

.rodata ORIGIN(INTERNAL_FLASH) + SIZEOF(.isr_vector_table) + SIZEOF(.header) + SIZEOF(.bootloader_shared) : {

. = ALIGN(4);
*(.rodata)
*(.rodata.*)
Expand Down
Loading