mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
134 lines
6.3 KiB
C
134 lines
6.3 KiB
C
/* Copyright 2026 Armel F4HWN
|
|
* https://github.com/armel
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* Overlay-app loader (POC).
|
|
*
|
|
* A leaf, modal app is a self-contained blob held in the external SPI flash. To
|
|
* run it the loader validates the header + code CRC, copies the code into the
|
|
* 4 KiB overlay (the PY25Q16 sector cache, shared VMA with the multiboot RAM
|
|
* stub), and calls its entry point. The blob runs from RAM and reaches every
|
|
* resident service through app_api_t. The loader never touches the internal
|
|
* application flash, so a corrupt or incompatible blob is only refused (header/CRC
|
|
* mismatch) or crashes into a watchdog reset.
|
|
*
|
|
* This is NOT a security sandbox. The CRC is an integrity check, not authentication,
|
|
* and a launched app is TRUSTED NATIVE CODE: it runs privileged with full access to
|
|
* memory and peripherals (no MPU, no crypto auth), so a malicious or buggy app CAN
|
|
* brick the radio - e.g. by driving the internal-flash controller itself. Only
|
|
* install apps you trust.
|
|
*
|
|
* External-flash "Apps" region (carved from the free space in the PY25Q16 map,
|
|
* after the multiboot markers, before the RX/TX log):
|
|
*
|
|
* 0x102000 slot 0 ] 16 slots x 8 KiB = 128 KiB
|
|
* 0x104000 slot 1 ] each slot: 4 KiB header sector + 4 KiB code
|
|
* ... ]
|
|
* 0x120000 slot 15 ]
|
|
*
|
|
* Host tooling (APP_SlotErase/Write/Info) touches the external flash only and is
|
|
* never brick-critical; a bad slot is simply refused at launch by the CRC check.
|
|
*/
|
|
|
|
#ifndef APPS_APP_OVERLAY_H
|
|
#define APPS_APP_OVERLAY_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "app_api.h"
|
|
|
|
/* ---- external-flash Apps region ---- */
|
|
#define APP_REGION_BASE 0x00102000u /* first app slot */
|
|
#define APP_SLOT_STRIDE 0x00002000u /* 8 KiB per slot */
|
|
#define APP_CODE_OFFSET 0x00001000u /* code starts after the 4 KiB header sector */
|
|
#define APP_SECTOR_SIZE 0x00001000u /* external NOR erase granularity */
|
|
#define APP_SLOT_COUNT 16u
|
|
#define APP_SLOT_BASE(s) (APP_REGION_BASE + (uint32_t)(s) * APP_SLOT_STRIDE)
|
|
|
|
/* ---- overlay RAM budget: the PY25Q16 4 KiB sector cache reused as workspace.
|
|
* The link VMA itself is pinned in Core/py32f071xb.ld (ORIGIN+0x280) and passed
|
|
* via compile-app.sh; the loader checks each blob's link_vma against it. ---- */
|
|
#define APP_OVERLAY_MAX 0x00001000u /* 4 KiB */
|
|
|
|
/* ---- blob header (64 bytes, little-endian; see App/apps/pack_app.py) ---- */
|
|
#define APP_MAGIC 0x31504146u /* "FAP1" */
|
|
#define APP_HDR_VERSION 1u
|
|
#define APP_FLAG_COMMITTED 0x0001u
|
|
#define APP_FLAG_SCREEN_SAVER 0x0002u
|
|
#define APP_FLAG_SHORTCUT_SHIFT 8u
|
|
#define APP_FLAG_SHORTCUT_MASK 0x0F00u
|
|
#define APP_NAME_LEN 16
|
|
#define APP_VERSION_LEN 16
|
|
|
|
#define APP_SHORTCUT_FM 0x01u
|
|
#define APP_SHORTCUT_FOXHUNT 0x02u
|
|
#define APP_SHORTCUT_BEACON 0x04u
|
|
#define APP_SHORTCUT_BEAM 0x08u
|
|
|
|
/* Optional resident facilities an app may require. Requirements live in the
|
|
* previously reserved header bytes, so app_header_t remains 64 bytes. */
|
|
#define APP_CAP_FM 0x00000001u
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
uint32_t magic; /* APP_MAGIC */
|
|
uint16_t hdr_version; /* APP_HDR_VERSION */
|
|
uint8_t abi_major; /* required ABI family */
|
|
uint8_t api_min; /* minimum append-only API level */
|
|
uint32_t code_size; /* bytes of code, <= APP_OVERLAY_MAX */
|
|
uint32_t code_crc32; /* CRC-32 (zlib) over code_size bytes */
|
|
uint16_t entry_off; /* entry offset within the code (0) */
|
|
uint16_t flags; /* APP_FLAG_COMMITTED, ... */
|
|
char name[APP_NAME_LEN]; /* human-readable, NUL-terminated */
|
|
char version[APP_VERSION_LEN];/* app version string */
|
|
uint32_t link_vma; /* RAM VMA the code was linked at */
|
|
uint32_t required_caps; /* APP_CAP_* required by this app */
|
|
uint8_t reserved[4]; /* pad to 64 bytes */
|
|
} app_header_t;
|
|
|
|
enum {
|
|
APP_OK = 0,
|
|
APP_ERR_SLOT, /* slot index out of range */
|
|
APP_ERR_MAGIC, /* no/invalid header */
|
|
APP_ERR_ABI, /* ABI family/API level mismatch */
|
|
APP_ERR_NOT_COMMITTED, /* image not marked complete */
|
|
APP_ERR_SIZE, /* code_size out of range */
|
|
APP_ERR_CRC, /* code CRC-32 mismatch */
|
|
APP_ERR_VMA, /* overlay buffer not at the link VMA */
|
|
APP_ERR_AUTH, /* host write refused: timestamp mismatch */
|
|
APP_ERR_CAP, /* required firmware capability missing */
|
|
};
|
|
|
|
/* Read + validate a slot header (no CRC of the code). */
|
|
uint8_t APP_ValidateSlot(uint8_t slot, app_header_t *out_header);
|
|
|
|
/* Validate, load into the overlay, verify the code CRC, and run the app.
|
|
* Returns when the app exits; the internal flash is never touched. */
|
|
uint8_t APP_LaunchOverlay(uint8_t slot);
|
|
|
|
/* Launch the first installed app advertising this shortcut bit. */
|
|
uint8_t APP_LaunchOverlayShortcut(uint8_t shortcut);
|
|
|
|
/* Cached availability of apps exposed as resident quick actions. */
|
|
uint8_t APP_OverlayShortcutMask(void);
|
|
|
|
/* Host-tool slot management (external flash only, never brick-critical). */
|
|
uint8_t APP_SlotInfo(uint8_t slot, app_header_t *out_header);
|
|
uint8_t APP_SlotErase(uint8_t slot);
|
|
uint8_t APP_SlotWrite(uint8_t slot, uint32_t offset, const uint8_t *data, uint32_t len);
|
|
|
|
|
|
#endif /* APPS_APP_OVERLAY_H */
|