Skip to content

Commit

Permalink
Initial commit using partition firmware
Browse files Browse the repository at this point in the history
Add rom_pick_ab_update_partition to do all the checking

Only allows picking verified images, and can be safely called before explicit_buy

Add pico_use_partition_firmware function

Also embed pt by default

Minor bug fixes, and tidy up returns
  • Loading branch information
will-v-pi committed Oct 3, 2024
1 parent 9260cf7 commit f109303
Show file tree
Hide file tree
Showing 7 changed files with 348 additions and 8 deletions.
100 changes: 100 additions & 0 deletions src/rp2_common/pico_cyw43_driver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,104 @@ if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE})
endfunction()

pico_promote_common_scope_vars()

# Set env var, so it can be accessed in the function
set(ENV{PICO_CYW43_DRIVER_CURRENT_PATH} ${CMAKE_CURRENT_LIST_DIR})
function(pico_use_partition_firmware TARGET)
target_compile_definitions(${TARGET} PRIVATE CYW43_USE_PARTITION_FIRMWARE=1)
pico_embed_pt_in_binary(${TARGET} $ENV{PICO_CYW43_DRIVER_CURRENT_PATH}/wifi_pt.json)

find_package (Python3 REQUIRED COMPONENTS Interpreter)

# Wifi firmware blob
add_custom_target(${TARGET}_firmware_w_blob DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/firmware_w_blob.S)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/firmware_w_blob.S
COMMAND ${Python3_EXECUTABLE} $ENV{PICO_CYW43_DRIVER_CURRENT_PATH}/cyw43_firmware.py ${PICO_CYW43_DRIVER_PATH}/firmware/w43439A0_7_95_49_00_combined.h ${CMAKE_CURRENT_BINARY_DIR}/firmware_w_blob.S
)

# Wifi and bluetooth firmware blob
add_custom_target(${TARGET}_firmware_wb_blob DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/firmware_wb_blob.S)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/firmware_wb_blob.S
COMMAND ${Python3_EXECUTABLE} $ENV{PICO_CYW43_DRIVER_CURRENT_PATH}/cyw43_firmware.py ${PICO_CYW43_DRIVER_PATH}/firmware/wb43439A0_7_95_49_00_combined.h ${CMAKE_CURRENT_BINARY_DIR}/firmware_wb_blob.S
)

# Create UF2s for all the variants - Wifi vs Wifi+Bluetooth, and TBYB
add_executable(${TARGET}_firmware_w
$ENV{PICO_CYW43_DRIVER_CURRENT_PATH}/wifi_firmware.S)
add_executable(${TARGET}_firmware_w_tbyb
$ENV{PICO_CYW43_DRIVER_CURRENT_PATH}/wifi_firmware.S)
add_executable(${TARGET}_firmware_wb
$ENV{PICO_CYW43_DRIVER_CURRENT_PATH}/wifi_firmware.S)
add_executable(${TARGET}_firmware_wb_tbyb
$ENV{PICO_CYW43_DRIVER_CURRENT_PATH}/wifi_firmware.S)

add_dependencies(${TARGET}_firmware_w ${TARGET}_firmware_w_blob)
add_dependencies(${TARGET}_firmware_w_tbyb ${TARGET}_firmware_w_blob)
add_dependencies(${TARGET}_firmware_wb ${TARGET}_firmware_wb_blob)
add_dependencies(${TARGET}_firmware_wb_tbyb ${TARGET}_firmware_wb_blob)

target_include_directories(${TARGET}_firmware_w PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(${TARGET}_firmware_w_tbyb PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(${TARGET}_firmware_wb PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(${TARGET}_firmware_wb_tbyb PRIVATE ${CMAKE_CURRENT_BINARY_DIR})

target_compile_definitions(${TARGET}_firmware_w PRIVATE
NO_PICO_PLATFORM=1
)
target_compile_definitions(${TARGET}_firmware_w_tbyb PRIVATE
NO_PICO_PLATFORM=1
PICO_CRT0_IMAGE_TYPE_TBYB=1
)
target_compile_definitions(${TARGET}_firmware_wb PRIVATE
NO_PICO_PLATFORM=1
WB_FIRMWARE=1
)
target_compile_definitions(${TARGET}_firmware_wb_tbyb PRIVATE
NO_PICO_PLATFORM=1
PICO_CRT0_IMAGE_TYPE_TBYB=1
WB_FIRMWARE=1
)

target_link_options(${TARGET}_firmware_w PRIVATE -nostartfiles -nodefaultlibs -Ttext=0x20000000)
target_link_options(${TARGET}_firmware_w_tbyb PRIVATE -nostartfiles -nodefaultlibs -Ttext=0x20000000)
target_link_options(${TARGET}_firmware_wb PRIVATE -nostartfiles -nodefaultlibs -Ttext=0x20000000)
target_link_options(${TARGET}_firmware_wb_tbyb PRIVATE -nostartfiles -nodefaultlibs -Ttext=0x20000000)

target_link_libraries(${TARGET}_firmware_w boot_picobin_headers)
target_link_libraries(${TARGET}_firmware_w_tbyb boot_picobin_headers)
target_link_libraries(${TARGET}_firmware_wb boot_picobin_headers)
target_link_libraries(${TARGET}_firmware_wb_tbyb boot_picobin_headers)

get_target_property(hasSigfile ${TARGET} PICOTOOL_SIGFILE)
if (hasSigfile)
pico_sign_binary(${TARGET}_firmware_w ${sigfile})
pico_sign_binary(${TARGET}_firmware_w_tbyb ${sigfile})
pico_sign_binary(${TARGET}_firmware_wb ${sigfile})
pico_sign_binary(${TARGET}_firmware_wb_tbyb ${sigfile})
endif()

pico_hash_binary(${TARGET}_firmware_w)
pico_hash_binary(${TARGET}_firmware_w_tbyb)
pico_hash_binary(${TARGET}_firmware_wb)
pico_hash_binary(${TARGET}_firmware_wb_tbyb)

pico_set_uf2_family(${TARGET}_firmware_w 0x12345678)
pico_set_uf2_family(${TARGET}_firmware_w_tbyb 0x12345678)
pico_set_uf2_family(${TARGET}_firmware_wb 0x12345678)
pico_set_uf2_family(${TARGET}_firmware_wb_tbyb 0x12345678)

pico_package_uf2_output(${TARGET}_firmware_w 0x10000000)
pico_package_uf2_output(${TARGET}_firmware_w_tbyb 0x10000000)
pico_package_uf2_output(${TARGET}_firmware_wb 0x10000000)
pico_package_uf2_output(${TARGET}_firmware_wb_tbyb 0x10000000)

pico_add_extra_outputs(${TARGET}_firmware_w)
pico_add_extra_outputs(${TARGET}_firmware_w_tbyb)
pico_add_extra_outputs(${TARGET}_firmware_wb)
pico_add_extra_outputs(${TARGET}_firmware_wb_tbyb)

add_dependencies(${TARGET}
${TARGET}_firmware_w ${TARGET}_firmware_w_tbyb
${TARGET}_firmware_wb ${TARGET}_firmware_wb_tbyb)
endfunction()
endif()
95 changes: 87 additions & 8 deletions src/rp2_common/pico_cyw43_driver/cyw43_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,17 @@
#define CYW43_SLEEP_CHECK_MS 50
#endif

static async_context_t *cyw43_async_context;
static async_context_t *cyw43_async_context = NULL;

#if CYW43_USE_PARTITION_FIRMWARE
#include "pico/bootrom.h"
#include "boot/picobin.h"
#include <stdlib.h>

int32_t cyw43_wifi_fw_len;
int32_t cyw43_clm_len;
uintptr_t fw_data;
#endif

static void cyw43_sleep_timeout_reached(async_context_t *context, async_at_time_worker_t *worker);
static void cyw43_do_poll(async_context_t *context, async_when_pending_worker_t *worker);
Expand Down Expand Up @@ -104,6 +114,73 @@ static void cyw43_sleep_timeout_reached(async_context_t *context, __unused async
}

bool cyw43_driver_init(async_context_t *context) {
#if CYW43_USE_PARTITION_FIRMWARE
const int buf_words = (16 * 4) + 1; // maximum of 16 partitions, each with maximum of 4 words returned, plus 1
uint32_t* buffer = malloc(buf_words * 4);
int ret = rom_get_partition_table_info(buffer, buf_words, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_PARTITION_ID);

assert(buffer[0] == (PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_PARTITION_ID));

if (ret > 0) {
int i = 1;
int p = 0;
int picked_p = -1;
while (i < ret) {
i++;
uint32_t flags_and_permissions = buffer[i++];
bool has_id = (flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_ID_BITS);
if (has_id) {
uint64_t id = 0;
id |= buffer[i++];
id |= ((uint64_t)(buffer[i++]) << 32ull);
if (id == 0x123456789abcdef0) {
picked_p = p;
}
}

p++;
}

if (picked_p >= 0) {
uint32_t* workarea = malloc(0x1000);
picked_p = rom_pick_ab_update_partition(workarea, 0x1000, picked_p);
free(workarea);

if (picked_p < 0) {
if (picked_p == BOOTROM_ERROR_NOT_FOUND) {
CYW43_DEBUG("Chosen CYW43 firmware partition was not verified\n");
} else if (picked_p == BOOTROM_ERROR_NOT_PERMITTED) {
CYW43_DEBUG("Too many update boots going on at once\n");
}
return false;
}

CYW43_DEBUG("Chosen CYW43 firmware in partition %d\n", picked_p);
int ret = rom_get_partition_table_info(buffer, buf_words, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (picked_p << 24));
assert(buffer[0] == (PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION));
assert(ret == 3);

uint32_t location_and_permissions = buffer[1];
uint32_t saddr = ((location_and_permissions >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB) & 0x1fffu) * 4096;
uint32_t eaddr = (((location_and_permissions >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB) & 0x1fffu) + 1) * 4096;
// Starts with metadata block
while(saddr < eaddr && *(uint32_t*)(XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE + saddr) != PICOBIN_BLOCK_MARKER_END) {
saddr += 4;
}
saddr += 4;
// Now onto data
cyw43_wifi_fw_len = *(uint32_t*)(XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE + saddr);
cyw43_clm_len = *(uint32_t*)(XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE + saddr + 4);
fw_data = XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE + saddr + 8;
}
free(buffer);
} else {
free(buffer);
CYW43_DEBUG("No partition table, so cannot get firmware from partition - get_partition_table_info returned %d\n", ret);
return false;
}

#endif
cyw43_init(&cyw43_state);
cyw43_async_context = context;
// we need the IRQ to be on the same core as the context, because we need to be able to enable/disable the IRQ
Expand All @@ -114,13 +191,15 @@ bool cyw43_driver_init(async_context_t *context) {
}

void cyw43_driver_deinit(async_context_t *context) {
assert(context == cyw43_async_context);
async_context_remove_at_time_worker(context, &sleep_timeout_worker);
async_context_remove_when_pending_worker(context, &cyw43_poll_worker);
// the IRQ IS on the same core as the context, so must be de-initialized there
async_context_execute_sync(context, cyw43_irq_deinit, NULL);
cyw43_deinit(&cyw43_state);
cyw43_async_context = NULL;
if (cyw43_async_context != NULL) {
assert(context == cyw43_async_context);
async_context_remove_at_time_worker(context, &sleep_timeout_worker);
async_context_remove_when_pending_worker(context, &cyw43_poll_worker);
// the IRQ IS on the same core as the context, so must be de-initialized there
async_context_execute_sync(context, cyw43_irq_deinit, NULL);
cyw43_deinit(&cyw43_state);
cyw43_async_context = NULL;
}
}

// todo maybe add an #ifdef in cyw43_driver
Expand Down
32 changes: 32 additions & 0 deletions src/rp2_common/pico_cyw43_driver/cyw43_firmware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import sys

with open(sys.argv[1], "r") as f:
data = f.read()
lines = data.split(";")
for line in lines[1].split("\n"):
if "#define CYW43_WIFI_FW_LEN" in line:
cyw43_wifi_fw_len = int(line.split(")")[0].split("(")[-1])
if "#define CYW43_CLM_LEN" in line:
cyw43_clm_len = int(line.split(")")[0].split("(")[-1])
data = lines[0]
bits = data.split(",")
bits[0] = bits[0].split("{")[-1]
bits[-1] = bits[-1].split("}")[0]
for i in range(len(bits)):
bits[i] = bits[i].strip()
bits[i] = bits[i].strip(',')
bits[i] = int(bits[i], base=0)
print(f"Start {bits[4]}, end {bits[-1]}, num {len(bits)}")
print(bits[:10])

print(f"Wifi {cyw43_wifi_fw_len}, clm {cyw43_clm_len}")

data = (
cyw43_wifi_fw_len.to_bytes(4, 'little', signed=True) +
cyw43_clm_len.to_bytes(4, 'little', signed=True) +
bytearray(bits)
)

with open(sys.argv[2], "w") as f:
for b in data:
f.write(f".byte 0x{b:02x}\n")
4 changes: 4 additions & 0 deletions src/rp2_common/pico_cyw43_driver/include/cyw43_configport.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,16 @@ extern "C" {
#endif

#ifndef CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE
#if CYW43_USE_PARTITION_FIRMWARE
#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "cyw43_partition_firmware.h"
#else
#if CYW43_ENABLE_BLUETOOTH
#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "wb43439A0_7_95_49_00_combined.h"
#else
#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "w43439A0_7_95_49_00_combined.h"
#endif
#endif
#endif

#ifndef CYW43_WIFI_NVRAM_INCLUDE_FILE
#define CYW43_WIFI_NVRAM_INCLUDE_FILE "wifi_nvram_43439.h"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

extern int cyw43_wifi_fw_len;
extern int cyw43_clm_len;

#define CYW43_WIFI_FW_LEN (cyw43_wifi_fw_len)
#define CYW43_CLM_LEN (cyw43_clm_len)
extern uintptr_t fw_data;

#include "boot/picobin.h"
#include "pico/bootrom.h"
63 changes: 63 additions & 0 deletions src/rp2_common/pico_cyw43_driver/wifi_firmware.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "boot/picobin.h"

#if PICO_CRT0_IMAGE_TYPE_TBYB
#define CRT0_TBYB_FLAG PICOBIN_IMAGE_TYPE_EXE_TBYB_BITS
#else
#define CRT0_TBYB_FLAG 0
#endif

.section .text
.global _start
_start:
.word 0
.word 0
.word 0
.word 0

.p2align 2
embedded_block:
.word PICOBIN_BLOCK_MARKER_START

.byte PICOBIN_BLOCK_ITEM_1BS_IMAGE_TYPE
.byte 0x1 // 1 word
.hword PICOBIN_IMAGE_TYPE_IMAGE_TYPE_AS_BITS(EXE) | \
PICOBIN_IMAGE_TYPE_EXE_CPU_AS_BITS(RISCV) | \
PICOBIN_IMAGE_TYPE_EXE_CHIP_AS_BITS(RP2350) | \
CRT0_TBYB_FLAG

// Entry point into SRAM
.byte PICOBIN_BLOCK_ITEM_1BS_ENTRY_POINT
.byte 0x3 // word size to next item
.byte 0 // pad
.byte 0 // pad
.word _start
.word 0x20082000 // stack pointer

_lm_item:
.byte PICOBIN_BLOCK_ITEM_LOAD_MAP
.byte 7
.byte 0 // pad
.byte 2 // 2 entries
// To sign the firmware
.word (_start - _lm_item)
.word _start
.word (firmware_end - _start)
// But clear SRAM if actually running this, so it doesn't boot
.word 0
.word _start
.word 0x00082000

.byte PICOBIN_BLOCK_ITEM_2BS_LAST
.hword (embedded_block_end - embedded_block - 16 ) / 4 // total size of all
.byte 0
.word 0
.word PICOBIN_BLOCK_MARKER_END
embedded_block_end:

#if WB_FIRMWARE
#include "firmware_wb_blob.S"
#else
#include "firmware_w_blob.S"
#endif

firmware_end:
52 changes: 52 additions & 0 deletions src/rp2_common/pico_cyw43_driver/wifi_pt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"version": [1, 0],
"unpartitioned": {
"families": ["absolute"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
"partitions": [
{
"name": "Main",
"id": 0,
"start": 0,
"size": "3500K",
"families": ["rp2350-arm-s", "rp2350-riscv"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
{
"name": "Wi-Fi Firmware",
"id": "0x123456789abcdef0",
"start": "3500k",
"size": "240K",
"families": ["0x12345678"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
},
"ignored_during_riscv_boot": true,
"no_reboot_on_uf2_download": true
},
{
"start": "3500k",
"size": "240k",
"families": ["0x12345678"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
},
"link": ["a", 1],
"ignored_during_riscv_boot": true,
"no_reboot_on_uf2_download": true
}
]
}

0 comments on commit f109303

Please sign in to comment.