From 5a620a6e811cb0bbd0eeb44ead3a778a492c56a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=22xq=22=20Quei=C3=9Fner?= Date: Sun, 22 Jun 2025 12:23:26 -0400 Subject: [PATCH 01/12] Add pico2 arm flashless target board --- port/raspberrypi/rp2xxx/build.zig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/port/raspberrypi/rp2xxx/build.zig b/port/raspberrypi/rp2xxx/build.zig index f5b28f743..6f2be49a0 100644 --- a/port/raspberrypi/rp2xxx/build.zig +++ b/port/raspberrypi/rp2xxx/build.zig @@ -17,6 +17,7 @@ boards: struct { pico: *const microzig.Target, pico_flashless: *const microzig.Target, pico2_arm: *const microzig.Target, + pico2_arm_flashless: *const microzig.Target, pico2_riscv: *const microzig.Target, }, waveshare: struct { @@ -191,6 +192,14 @@ pub fn init(dep: *std.Build.Dependency) Self { .root_source_file = b.path("src/boards/raspberry_pi_pico2.zig"), }, }), + .pico2_arm_flashless = chip_rp2350_arm.derive(.{ + .ram_image = true, + .board = .{ + .name = "RaspberryPi Pico 2 (ram image)", + .url = "https://www.raspberrypi.com/products/raspberry-pi-pico2/", + .root_source_file = b.path("src/boards/raspberry_pi_pico2.zig"), + }, + }), .pico2_riscv = chip_rp2350_riscv.derive(.{ .board = .{ .name = "RaspberryPi Pico 2", From 1743aa4cf7ccf46d3ff28955b847d3016e572393 Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 09:38:56 +0300 Subject: [PATCH 02/12] add linker script --- port/raspberrypi/rp2xxx/build.zig | 11 +++- .../ld/rp2350/arm_ram_image_sections.ld | 51 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 port/raspberrypi/rp2xxx/ld/rp2350/arm_ram_image_sections.ld diff --git a/port/raspberrypi/rp2xxx/build.zig b/port/raspberrypi/rp2xxx/build.zig index 6f2be49a0..66a64a72e 100644 --- a/port/raspberrypi/rp2xxx/build.zig +++ b/port/raspberrypi/rp2xxx/build.zig @@ -177,12 +177,15 @@ pub fn init(dep: *std.Build.Dependency) Self { }), .pico_flashless = chip_rp2040.derive(.{ .entry = .{ .symbol_name = "_entry_point" }, - .linker_script = .{ .generate = .none, .file = b.path("ld/rp2040/ram_image_linker.ld") }, + .linker_script = .{ + .generate = .none, + .file = b.path("ld/rp2040/ram_image_linker.ld"), + }, .ram_image = true, .board = .{ .name = "RaspberryPi Pico (ram image)", .url = "https://www.raspberrypi.com/products/raspberry-pi-pico/", - .root_source_file = b.path("src/boards/raspberry_pi_pico2.zig"), + .root_source_file = b.path("src/boards/raspberry_pi_pico.zig"), }, }), .pico2_arm = chip_rp2350_arm.derive(.{ @@ -194,6 +197,10 @@ pub fn init(dep: *std.Build.Dependency) Self { }), .pico2_arm_flashless = chip_rp2350_arm.derive(.{ .ram_image = true, + .linker_script = .{ + .generate = .memory_regions, + .file = b.path("ld/rp2350/arm_ram_image_sections.ld"), + }, .board = .{ .name = "RaspberryPi Pico 2 (ram image)", .url = "https://www.raspberrypi.com/products/raspberry-pi-pico2/", diff --git a/port/raspberrypi/rp2xxx/ld/rp2350/arm_ram_image_sections.ld b/port/raspberrypi/rp2xxx/ld/rp2350/arm_ram_image_sections.ld new file mode 100644 index 000000000..842847df2 --- /dev/null +++ b/port/raspberrypi/rp2xxx/ld/rp2350/arm_ram_image_sections.ld @@ -0,0 +1,51 @@ +SECTIONS +{ + /DISCARD/ : + { + *(.entry) + } + + .flash_start : + { + KEEP(*(microzig_flash_start)) + } > ram0 + + .bootmeta : + { + __bootmeta_start__ = .; + KEEP(*(.bootmeta)) + __bootmeta_end__ = .; + } > ram0 + + .text : + { + *(.text*) + KEEP(*(.ram_text)) + *(.rodata*) + } > ram0 + + .ARM.extab : { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > ram0 + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > ram0 + + .data : + { + *(.data*) + } > ram0 + + .bss : + { + *(.bss*) + } > ram0 + + /* Unused, but set as extern in startup_logic */ + microzig_data_start = .; + microzig_data_end = .; + microzig_bss_start = .; + microzig_bss_end = .; + microzig_data_load_start = .; +} From b6a0e7ab8687fce51e3e3a8713546596f42d1355 Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 11:21:13 +0300 Subject: [PATCH 03/12] update image_def and generate linker script --- build.zig | 1 + core/src/cpus/cortex_m.zig | 14 +-- port/raspberrypi/rp2xxx/build.zig | 2 +- .../ld/rp2350/arm_ram_image_sections.ld | 49 ++------ port/raspberrypi/rp2xxx/src/cpus/hazard3.zig | 43 ++++--- port/raspberrypi/rp2xxx/src/hal.zig | 16 ++- port/raspberrypi/rp2xxx/src/hal/bootmeta.zig | 111 ++++++++++++++++++ port/raspberrypi/rp2xxx/src/hal/image_def.zig | 37 ------ tools/generate_linker_script.zig | 93 +++++++++++---- 9 files changed, 231 insertions(+), 135 deletions(-) create mode 100644 port/raspberrypi/rp2xxx/src/hal/bootmeta.zig delete mode 100644 port/raspberrypi/rp2xxx/src/hal/image_def.zig diff --git a/build.zig b/build.zig index 6ab583ece..6ec7e01b2 100644 --- a/build.zig +++ b/build.zig @@ -569,6 +569,7 @@ pub fn MicroBuild(port_select: PortSelect) type { .chip_name = target.chip.name, .memory_regions = target.chip.memory_regions, .generate = linker_script_options.generate, + .ram_image = target.ram_image, }; const args_str = std.json.stringifyAlloc( diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig index b7411b7a5..44dc146ce 100644 --- a/core/src/cpus/cortex_m.zig +++ b/core/src/cpus/cortex_m.zig @@ -591,7 +591,7 @@ pub const startup_logic = struct { extern var microzig_bss_end: u8; extern const microzig_data_load_start: u8; - pub fn ram_image_entrypoint() linksection(".entry") callconv(.naked) void { + pub fn ram_image_entrypoint() linksection("microzig_ram_start") callconv(.naked) void { asm volatile ( \\ // Set VTOR to point to ram table @@ -687,17 +687,17 @@ pub fn export_startup_logic() void { @export(&startup_logic.ram_image_entrypoint, .{ .name = "_entry_point", .linkage = .strong, + }) + else + @export(&startup_logic._vector_table, .{ + .name = "_vector_table", + .section = "microzig_flash_start", + .linkage = .strong, }); @export(&startup_logic._start, .{ .name = "_start", }); - - @export(&startup_logic._vector_table, .{ - .name = "_vector_table", - .section = "microzig_flash_start", - .linkage = .strong, - }); } const scs_base = 0xE000E000; diff --git a/port/raspberrypi/rp2xxx/build.zig b/port/raspberrypi/rp2xxx/build.zig index 66a64a72e..757a51b81 100644 --- a/port/raspberrypi/rp2xxx/build.zig +++ b/port/raspberrypi/rp2xxx/build.zig @@ -196,9 +196,9 @@ pub fn init(dep: *std.Build.Dependency) Self { }, }), .pico2_arm_flashless = chip_rp2350_arm.derive(.{ + .entry = .{ .symbol_name = "_entry_point" }, .ram_image = true, .linker_script = .{ - .generate = .memory_regions, .file = b.path("ld/rp2350/arm_ram_image_sections.ld"), }, .board = .{ diff --git a/port/raspberrypi/rp2xxx/ld/rp2350/arm_ram_image_sections.ld b/port/raspberrypi/rp2xxx/ld/rp2350/arm_ram_image_sections.ld index 842847df2..ca3b22f40 100644 --- a/port/raspberrypi/rp2xxx/ld/rp2350/arm_ram_image_sections.ld +++ b/port/raspberrypi/rp2xxx/ld/rp2350/arm_ram_image_sections.ld @@ -1,51 +1,18 @@ -SECTIONS -{ - /DISCARD/ : - { - *(.entry) - } - - .flash_start : - { - KEEP(*(microzig_flash_start)) - } > ram0 - +SECTIONS { .bootmeta : { __bootmeta_start__ = .; KEEP(*(.bootmeta)) __bootmeta_end__ = .; } > ram0 +} +INSERT AFTER .ram_start; - .text : - { - *(.text*) - KEEP(*(.ram_text)) - *(.rodata*) - } > ram0 - - .ARM.extab : { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > ram0 - - .ARM.exidx : { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > ram0 - - .data : - { - *(.data*) - } > ram0 - - .bss : +SECTIONS { + .ram_vectors (NOLOAD) : { - *(.bss*) + KEEP(*(ram_vectors)) } > ram0 - - /* Unused, but set as extern in startup_logic */ - microzig_data_start = .; - microzig_data_end = .; - microzig_bss_start = .; - microzig_bss_end = .; - microzig_data_load_start = .; } +INSERT AFTER .bss; + diff --git a/port/raspberrypi/rp2xxx/src/cpus/hazard3.zig b/port/raspberrypi/rp2xxx/src/cpus/hazard3.zig index 197156e02..b42e5ae1f 100644 --- a/port/raspberrypi/rp2xxx/src/cpus/hazard3.zig +++ b/port/raspberrypi/rp2xxx/src/cpus/hazard3.zig @@ -169,7 +169,10 @@ var ram_vectors: [vector_count]Handler = undefined; pub const startup_logic = struct { extern fn microzig_main() noreturn; - pub export fn _start() linksection("microzig_flash_start") callconv(.naked) noreturn { + pub export fn _start() linksection(if (microzig.config.ram_image) + "microzig_ram_start" + else + "microzig_flash_start") callconv(.naked) noreturn { asm volatile ( \\.option push \\.option norelax @@ -199,24 +202,26 @@ pub const startup_logic = struct { } pub export fn _start_c() callconv(.c) noreturn { - root.initialize_system_memories(); - - // Move vector table to RAM if requested - if (interrupt.has_ram_vectors()) { - if (interrupt.has_ram_vectors_section()) { - @export(&ram_vectors, .{ - .name = "_ram_vectors", - .section = "ram_vectors", - .linkage = .strong, - }); - } else { - @export(&ram_vectors, .{ - .name = "_ram_vectors", - .linkage = .strong, - }); + if (!microzig.config.ram_image) { + root.initialize_system_memories(); + + // Move vector table to RAM if requested + if (interrupt.has_ram_vectors()) { + if (interrupt.has_ram_vectors_section()) { + @export(&ram_vectors, .{ + .name = "_ram_vectors", + .section = "ram_vectors", + .linkage = .strong, + }); + } else { + @export(&ram_vectors, .{ + .name = "_ram_vectors", + .linkage = .strong, + }); + } + + @memcpy(&ram_vectors, &startup_logic.external_interrupt_table); } - - @memcpy(&ram_vectors, &startup_logic.external_interrupt_table); } microzig_main(); @@ -316,7 +321,7 @@ pub fn export_startup_logic() void { @export(&startup_logic.external_interrupt_table, .{ .name = "_external_interrupt_table", - .section = "flash_vectors", + .section = if (!microzig.config.ram_image) "flash_vectors" else ".data", .linkage = .strong, }); } diff --git a/port/raspberrypi/rp2xxx/src/hal.zig b/port/raspberrypi/rp2xxx/src/hal.zig index 2063d807f..d4238ab89 100644 --- a/port/raspberrypi/rp2xxx/src/hal.zig +++ b/port/raspberrypi/rp2xxx/src/hal.zig @@ -30,12 +30,12 @@ pub const watchdog = @import("hal/watchdog.zig"); pub const cyw49_pio_spi = @import("hal/cyw43_pio_spi.zig"); pub const drivers = @import("hal/drivers.zig"); pub const compatibility = @import("hal/compatibility.zig"); -pub const image_def = @import("hal/image_def.zig"); +pub const bootmeta = @import("hal/bootmeta.zig"); comptime { // HACK: tests can't access microzig. maybe there's a better way to do this. if (!builtin.is_test and compatibility.chip == .RP2350) { - _ = image_def; + _ = bootmeta; } // On the RP2040, we need to import the `atomic.zig` file to export some global @@ -46,8 +46,16 @@ comptime { } } -pub const HAL_Options = struct { - image_def_security: image_def.Security = .secure, +pub const HAL_Options = switch (compatibility.chip) { + .RP2040 => struct {}, + .RP2350 => struct { + image_def_exe_security: bootmeta.ImageDef.ImageTypeFlags.ExeSecurity = .secure, + + /// Next metadata block to link after image_def. **Last block in the + /// chain must link back to the first one** (to + /// `bootmeta.image_def_block`). + next_metadata_block: ?*const anyopaque = null, + }, }; /// A default clock configuration with sensible defaults that will work diff --git a/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig b/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig new file mode 100644 index 000000000..d44da4daf --- /dev/null +++ b/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig @@ -0,0 +1,111 @@ +/// Documentation taken from section 5.9.5.1 of the rp2350 datasheet. +const std = @import("std"); +const root = @import("root"); +const microzig = @import("microzig"); +const arch = @import("compatibility.zig").arch; + +pub const image_def_block: Block(extern struct { + image_def: ImageDef, + entry_point: EntryPoint(false), +}) = .{ + .items = .{ + .image_def = .{ + .image_type_flags = .{ + .image_type = .exe, + .exe_security = root.microzig_options.hal.image_def_exe_security, + .cpu = std.meta.stringToEnum(ImageDef.ImageTypeFlags.Cpu, @tagName(arch)).?, + .chip = .RP2350, + .try_before_you_buy = false, + }, + }, + .entry_point = .{ + .entry = if (microzig.config.ram_image and arch == .arm) + µzig.cpu.startup_logic.ram_image_entrypoint + else + µzig.cpu.startup_logic._start, + .sp = microzig.config.end_of_stack, + }, + }, + .link = root.microzig_options.hal.next_metadata_block, +}; + +comptime { + @export(&image_def_block, .{ + .name = "_image_def_block", + .section = ".bootmeta", + .linkage = .strong, + }); +} + +pub fn Block(Items: type) type { + return extern struct { + header: u32 = 0xffffded3, + items: Items, + last_item: u32 = 0x000000ff | ((@sizeOf(Items) / 4) << 8), + link: ?*const anyopaque = null, + footer: u32 = 0xab123579, + }; +} + +pub const ImageDef = packed struct { + item_type: u8 = 0x42, + block_size: u8 = 0x01, + image_type_flags: ImageTypeFlags, + + pub const ImageTypeFlags = packed struct { + image_type: ImageType, + exe_security: ExeSecurity, + reserved0: u2 = 0, + cpu: Cpu, + reserved1: u1 = 0, + chip: Chip, + try_before_you_buy: bool, + + pub const ImageType = enum(u4) { + invalid = 0, + exe = 1, + data = 2, + }; + + pub const ExeSecurity = enum(u2) { + unspecified = 0, + non_secure = 1, + secure = 2, + }; + + pub const Cpu = enum(u3) { + arm = 0, + riscv = 1, + }; + + pub const Chip = enum(u3) { + RP2040 = 0, + RP2350 = 1, + }; + }; +}; + +pub fn EntryPoint(with_stack_limit: bool) type { + if (with_stack_limit) { + return extern struct { + header: packed struct { + item_type: u8 = 0x44, + block_size: u8 = 0x04, + padding: u16 = 0, + } = .{}, + entry: *const anyopaque, + sp: u32, + sp_limit: u32, + }; + } else { + return extern struct { + header: packed struct { + item_type: u8 = 0x44, + block_size: u8 = 0x03, + padding: u16 = 0, + } = .{}, + entry: *const anyopaque, + sp: u32, + }; + } +} diff --git a/port/raspberrypi/rp2xxx/src/hal/image_def.zig b/port/raspberrypi/rp2xxx/src/hal/image_def.zig deleted file mode 100644 index 1750c543b..000000000 --- a/port/raspberrypi/rp2xxx/src/hal/image_def.zig +++ /dev/null @@ -1,37 +0,0 @@ -const std = @import("std"); -const root = @import("root"); -const microzig = @import("microzig"); -const arch = @import("compatibility.zig").arch; - -pub const Security = enum(u2) { - non_secure = 1, - secure = 2, -}; - -const Cpu = enum(u3) { - arm = 0, - riscv = 1, -}; - -const security = root.microzig_options.hal.image_def_security; -const cpu: Cpu = std.meta.stringToEnum(Cpu, @tagName(arch)).?; - -const image_def = init(); - -comptime { - @export(&image_def, .{ - .name = "_image_def", - .section = ".bootmeta", - .linkage = .strong, - }); -} - -fn init() [5]u32 { - return .{ - 0xffffded3, - 0x10010142 | (@as(u32, @intFromEnum(security)) << 20) | (@as(u32, @intFromEnum(cpu)) << 24), - 0x000001ff, - 0x00000000, - 0xab123579, - }; -} diff --git a/tools/generate_linker_script.zig b/tools/generate_linker_script.zig index 7f3b16483..12fd8c13f 100644 --- a/tools/generate_linker_script.zig +++ b/tools/generate_linker_script.zig @@ -9,6 +9,7 @@ pub const Args = struct { chip_name: []const u8, memory_regions: []const MemoryRegion, generate: GenerateOptions, + ram_image: bool, }; pub fn main() !void { @@ -113,23 +114,55 @@ pub fn main() !void { } } else return error.NoRamRegion; + if (parsed_args.ram_image and !ram_region.access.execute) { + return error.RamRegionNotExecutableInRamImage; + } + const options = parsed_args.generate.memory_regions_and_sections; - try writer.print( + try writer.writeAll( \\SECTIONS - \\{{ - \\ .flash_start : - \\ {{ - \\ KEEP(*(microzig_flash_start)) - \\ }} > {s} + \\{ \\ + ); + + if (parsed_args.ram_image) { + try writer.print( + \\ .ram_start : + \\ {{ + \\ KEEP(*(microzig_ram_start)) + \\ }} > {s} + \\ + , + .{ram_region_name}, + ); + } else { + try writer.print( + \\ .flash_start : + \\ {{ + \\ KEEP(*(microzig_flash_start)) + \\ }} > {s} + \\ + , + .{flash_region_name}, + ); + } + + try writer.writeAll( \\ .text : - \\ {{ + \\ { \\ *(.text*) \\ - , .{flash_region_name}); + ); - if (options.rodata_location == .flash) { + if (parsed_args.ram_image) { + try writer.writeAll( + \\ *(.ram_text*) + \\ + ); + } + + if (options.rodata_location == .flash and !parsed_args.ram_image) { try writer.writeAll( \\ *(.srodata*) \\ *(.rodata*) @@ -140,8 +173,7 @@ pub fn main() !void { try writer.print( \\ }} > {s} \\ - \\ - , .{flash_region_name}); + , .{if (parsed_args.ram_image) ram_region_name else flash_region_name}); switch (parsed_args.cpu_arch) { .arm, .thumb => try writer.print( @@ -153,8 +185,7 @@ pub fn main() !void { \\ *(.ARM.exidx* .gnu.linkonce.armexidx.*) \\ }} > {[flash]s} \\ - \\ - , .{ .flash = flash_region_name }), + , .{ .flash = if (parsed_args.ram_image) ram_region_name else flash_region_name }), else => {}, } @@ -167,7 +198,7 @@ pub fn main() !void { \\ ); - if (options.rodata_location == .ram) { + if (options.rodata_location == .ram or parsed_args.ram_image) { try writer.writeAll( \\ *(.srodata*) \\ *(.rodata*) @@ -175,7 +206,7 @@ pub fn main() !void { ); } - if (ram_region.access.execute) { + if (ram_region.access.execute and !parsed_args.ram_image) { try writer.writeAll( // NOTE: should this be `microzig_ram_text`? \\ KEEP(*(.ram_text)) @@ -185,7 +216,7 @@ pub fn main() !void { try writer.print( \\ microzig_data_end = .; - \\ }} > {[ram]s} AT> {[flash]s} + \\ }} > {s} \\ \\ .bss (NOLOAD) : \\ {{ @@ -193,20 +224,30 @@ pub fn main() !void { \\ *(.sbss*) \\ *(.bss*) \\ microzig_bss_end = .; - \\ }} > {[ram]s} - \\ - \\ .flash_end : - \\ {{ - \\ microzig_flash_end = .; - \\ }} > {[flash]s} - \\ - \\ microzig_data_load_start = LOADADDR(.data); + \\ }} > {s} \\ , .{ - .flash = flash_region_name, - .ram = ram_region_name, + if (parsed_args.ram_image) + ram_region_name + else + try std.fmt.allocPrint(allocator, "{s} AT> {s}", .{ ram_region_name, flash_region_name }), + ram_region_name, }); + if (!parsed_args.ram_image) { + try writer.print( + \\ .flash_end : + \\ {{ + \\ microzig_flash_end = .; + \\ }} > {s} + \\ + , .{flash_region_name}); + } + + try writer.writeAll( + \\ microzig_data_load_start = LOADADDR(.data); + \\ + ); switch (parsed_args.cpu_arch) { .riscv32, .riscv64 => try writer.writeAll( \\ PROVIDE(__global_pointer$ = microzig_data_start + 0x800); From 371b6724641441f1d67a9eda09b415a90612fccb Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 11:32:49 +0300 Subject: [PATCH 04/12] fixes --- port/raspberrypi/rp2xxx/build.zig | 21 ++++++++++++------- .../boards/raspberry_pi_pico_flashless.zig | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 port/raspberrypi/rp2xxx/src/boards/raspberry_pi_pico_flashless.zig diff --git a/port/raspberrypi/rp2xxx/build.zig b/port/raspberrypi/rp2xxx/build.zig index 757a51b81..c12547164 100644 --- a/port/raspberrypi/rp2xxx/build.zig +++ b/port/raspberrypi/rp2xxx/build.zig @@ -176,16 +176,13 @@ pub fn init(dep: *std.Build.Dependency) Self { }, }), .pico_flashless = chip_rp2040.derive(.{ - .entry = .{ .symbol_name = "_entry_point" }, - .linker_script = .{ - .generate = .none, - .file = b.path("ld/rp2040/ram_image_linker.ld"), - }, .ram_image = true, + // we do not need any modifications to the default generated linker script + .linker_script = .{}, .board = .{ .name = "RaspberryPi Pico (ram image)", .url = "https://www.raspberrypi.com/products/raspberry-pi-pico/", - .root_source_file = b.path("src/boards/raspberry_pi_pico.zig"), + .root_source_file = b.path("src/boards/raspberry_pi_pico_flashless.zig"), }, }), .pico2_arm = chip_rp2350_arm.derive(.{ @@ -196,7 +193,6 @@ pub fn init(dep: *std.Build.Dependency) Self { }, }), .pico2_arm_flashless = chip_rp2350_arm.derive(.{ - .entry = .{ .symbol_name = "_entry_point" }, .ram_image = true, .linker_script = .{ .file = b.path("ld/rp2350/arm_ram_image_sections.ld"), @@ -214,6 +210,17 @@ pub fn init(dep: *std.Build.Dependency) Self { .root_source_file = b.path("src/boards/raspberry_pi_pico2.zig"), }, }), + // .pico2_riscv_flashless = chip_rp2350_riscv.derive(.{ + // .ram_image = true, + // .linker_script = .{ + // .file = b.path("ld/rp2350/arm_ram_image_sections.ld"), + // }, + // .board = .{ + // .name = "RaspberryPi Pico 2 (ram image)", + // .url = "https://www.raspberrypi.com/products/raspberry-pi-pico2/", + // .root_source_file = b.path("src/boards/raspberry_pi_pico2.zig"), + // }, + // }), }, .waveshare = .{ .rp2040_plus_4m = chip_rp2040.derive(.{ diff --git a/port/raspberrypi/rp2xxx/src/boards/raspberry_pi_pico_flashless.zig b/port/raspberrypi/rp2xxx/src/boards/raspberry_pi_pico_flashless.zig new file mode 100644 index 000000000..aa428ccb3 --- /dev/null +++ b/port/raspberrypi/rp2xxx/src/boards/raspberry_pi_pico_flashless.zig @@ -0,0 +1 @@ +pub const xosc_freq = 12_000_000; From 529adadaaca9f2dfe0d3edb867493ea382f26db0 Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 11:55:41 +0300 Subject: [PATCH 05/12] fixes and support for riscv --- port/raspberrypi/rp2xxx/build.zig | 23 +++++++------ .../ld/rp2350/riscv_ram_image_sections.ld | 23 +++++++++++++ .../rp2xxx/ld/rp2350/riscv_sections.ld | 2 +- port/raspberrypi/rp2xxx/src/cpus/hazard3.zig | 34 +++++++++---------- tools/generate_linker_script.zig | 9 ++--- 5 files changed, 58 insertions(+), 33 deletions(-) create mode 100644 port/raspberrypi/rp2xxx/ld/rp2350/riscv_ram_image_sections.ld diff --git a/port/raspberrypi/rp2xxx/build.zig b/port/raspberrypi/rp2xxx/build.zig index c12547164..9678d75fd 100644 --- a/port/raspberrypi/rp2xxx/build.zig +++ b/port/raspberrypi/rp2xxx/build.zig @@ -19,6 +19,7 @@ boards: struct { pico2_arm: *const microzig.Target, pico2_arm_flashless: *const microzig.Target, pico2_riscv: *const microzig.Target, + pico2_riscv_flashless: *const microzig.Target, }, waveshare: struct { rp2040_plus_4m: *const microzig.Target, @@ -210,17 +211,17 @@ pub fn init(dep: *std.Build.Dependency) Self { .root_source_file = b.path("src/boards/raspberry_pi_pico2.zig"), }, }), - // .pico2_riscv_flashless = chip_rp2350_riscv.derive(.{ - // .ram_image = true, - // .linker_script = .{ - // .file = b.path("ld/rp2350/arm_ram_image_sections.ld"), - // }, - // .board = .{ - // .name = "RaspberryPi Pico 2 (ram image)", - // .url = "https://www.raspberrypi.com/products/raspberry-pi-pico2/", - // .root_source_file = b.path("src/boards/raspberry_pi_pico2.zig"), - // }, - // }), + .pico2_riscv_flashless = chip_rp2350_riscv.derive(.{ + .ram_image = true, + .linker_script = .{ + .file = b.path("ld/rp2350/riscv_ram_image_sections.ld"), + }, + .board = .{ + .name = "RaspberryPi Pico 2 (ram image)", + .url = "https://www.raspberrypi.com/products/raspberry-pi-pico2/", + .root_source_file = b.path("src/boards/raspberry_pi_pico2.zig"), + }, + }), }, .waveshare = .{ .rp2040_plus_4m = chip_rp2040.derive(.{ diff --git a/port/raspberrypi/rp2xxx/ld/rp2350/riscv_ram_image_sections.ld b/port/raspberrypi/rp2xxx/ld/rp2350/riscv_ram_image_sections.ld new file mode 100644 index 000000000..2c38646a6 --- /dev/null +++ b/port/raspberrypi/rp2xxx/ld/rp2350/riscv_ram_image_sections.ld @@ -0,0 +1,23 @@ +SECTIONS { + .bootmeta : + { + __bootmeta_start__ = .; + KEEP(*(.bootmeta)) + __bootmeta_end__ = .; + } > ram0 + + .vectors : + { + KEEP(*(core_vectors)) + } > ram0 +} +INSERT AFTER .ram_start; + +SECTIONS { + .ram_vectors (NOLOAD) : + { + KEEP(*(ram_vectors)) + } > ram0 +} +INSERT AFTER .bss; + diff --git a/port/raspberrypi/rp2xxx/ld/rp2350/riscv_sections.ld b/port/raspberrypi/rp2xxx/ld/rp2350/riscv_sections.ld index e2965fb9d..b6498e39b 100644 --- a/port/raspberrypi/rp2xxx/ld/rp2350/riscv_sections.ld +++ b/port/raspberrypi/rp2xxx/ld/rp2350/riscv_sections.ld @@ -15,7 +15,7 @@ SECTIONS { INSERT AFTER .flash_start; SECTIONS { - .ram_vectors (NOLOAD) : + .ram_vectors (NOLOAD) : { KEEP(*(ram_vectors)) } > ram0 diff --git a/port/raspberrypi/rp2xxx/src/cpus/hazard3.zig b/port/raspberrypi/rp2xxx/src/cpus/hazard3.zig index b42e5ae1f..0fa7e4d01 100644 --- a/port/raspberrypi/rp2xxx/src/cpus/hazard3.zig +++ b/port/raspberrypi/rp2xxx/src/cpus/hazard3.zig @@ -204,24 +204,24 @@ pub const startup_logic = struct { pub export fn _start_c() callconv(.c) noreturn { if (!microzig.config.ram_image) { root.initialize_system_memories(); + } - // Move vector table to RAM if requested - if (interrupt.has_ram_vectors()) { - if (interrupt.has_ram_vectors_section()) { - @export(&ram_vectors, .{ - .name = "_ram_vectors", - .section = "ram_vectors", - .linkage = .strong, - }); - } else { - @export(&ram_vectors, .{ - .name = "_ram_vectors", - .linkage = .strong, - }); - } - - @memcpy(&ram_vectors, &startup_logic.external_interrupt_table); + // Move vector table to RAM if requested + if (interrupt.has_ram_vectors()) { + if (interrupt.has_ram_vectors_section()) { + @export(&ram_vectors, .{ + .name = "_ram_vectors", + .section = "ram_vectors", + .linkage = .strong, + }); + } else { + @export(&ram_vectors, .{ + .name = "_ram_vectors", + .linkage = .strong, + }); } + + @memcpy(&ram_vectors, &startup_logic.external_interrupt_table); } microzig_main(); @@ -321,7 +321,7 @@ pub fn export_startup_logic() void { @export(&startup_logic.external_interrupt_table, .{ .name = "_external_interrupt_table", - .section = if (!microzig.config.ram_image) "flash_vectors" else ".data", + .section = if (!microzig.config.ram_image) "flash_vectors" else null, .linkage = .strong, }); } diff --git a/tools/generate_linker_script.zig b/tools/generate_linker_script.zig index 12fd8c13f..01b4496e3 100644 --- a/tools/generate_linker_script.zig +++ b/tools/generate_linker_script.zig @@ -218,7 +218,7 @@ pub fn main() !void { \\ microzig_data_end = .; \\ }} > {s} \\ - \\ .bss (NOLOAD) : + \\ .bss {s}: \\ {{ \\ microzig_bss_start = .; \\ *(.sbss*) @@ -227,10 +227,11 @@ pub fn main() !void { \\ }} > {s} \\ , .{ - if (parsed_args.ram_image) - ram_region_name + if (!parsed_args.ram_image) + try std.fmt.allocPrint(allocator, "{s} AT> {s}", .{ ram_region_name, flash_region_name }) else - try std.fmt.allocPrint(allocator, "{s} AT> {s}", .{ ram_region_name, flash_region_name }), + ram_region_name, + if (!parsed_args.ram_image) "(NOLOAD) " else "", ram_region_name, }); From dfcbaa3cf0ca97f6d15082d4d193d1ec3bfc9380 Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 12:01:59 +0300 Subject: [PATCH 06/12] cleanup --- .../rp2xxx/ld/rp2040/ram_image_linker.ld | 47 ------------------- tools/generate_linker_script.zig | 4 +- 2 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 port/raspberrypi/rp2xxx/ld/rp2040/ram_image_linker.ld diff --git a/port/raspberrypi/rp2xxx/ld/rp2040/ram_image_linker.ld b/port/raspberrypi/rp2xxx/ld/rp2040/ram_image_linker.ld deleted file mode 100644 index dbe46f358..000000000 --- a/port/raspberrypi/rp2xxx/ld/rp2040/ram_image_linker.ld +++ /dev/null @@ -1,47 +0,0 @@ -/* TODO: maybe memory regions can be auto-generated */ -MEMORY -{ - entry (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00000100 - ram0 (rwx) : ORIGIN = 0x20000100, LENGTH = 0x0003ff00 -} - -SECTIONS -{ - .entry : - { - KEEP(*(.entry)) - } > entry - - .text : - { - KEEP(*(microzig_flash_start)) - *(.text*) - KEEP(*(.ram_text)) - *(.rodata*) - } > ram0 - - .ARM.extab : { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > ram0 - - .ARM.exidx : { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > ram0 - - .data : - { - *(.data*) - } > ram0 - - .bss : - { - *(.bss*) - } > ram0 - - /* Unused, but set as extern in startup_logic */ - microzig_data_start = .; - microzig_data_end = .; - microzig_bss_start = .; - microzig_bss_end = .; - microzig_data_load_start = .; -} diff --git a/tools/generate_linker_script.zig b/tools/generate_linker_script.zig index 01b4496e3..929853df6 100644 --- a/tools/generate_linker_script.zig +++ b/tools/generate_linker_script.zig @@ -173,7 +173,7 @@ pub fn main() !void { try writer.print( \\ }} > {s} \\ - , .{if (parsed_args.ram_image) ram_region_name else flash_region_name}); + , .{if (!parsed_args.ram_image) flash_region_name else ram_region_name}); switch (parsed_args.cpu_arch) { .arm, .thumb => try writer.print( @@ -185,7 +185,7 @@ pub fn main() !void { \\ *(.ARM.exidx* .gnu.linkonce.armexidx.*) \\ }} > {[flash]s} \\ - , .{ .flash = if (parsed_args.ram_image) ram_region_name else flash_region_name }), + , .{ .flash = if (!parsed_args.ram_image) flash_region_name else ram_region_name }), else => {}, } From b9e19f42142b9729fed5c2b933360a1e69b8744a Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 12:05:20 +0300 Subject: [PATCH 07/12] cleanup2 --- port/raspberrypi/rp2xxx/build.zig | 2 +- tools/generate_linker_script.zig | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/port/raspberrypi/rp2xxx/build.zig b/port/raspberrypi/rp2xxx/build.zig index 9678d75fd..66a440009 100644 --- a/port/raspberrypi/rp2xxx/build.zig +++ b/port/raspberrypi/rp2xxx/build.zig @@ -178,7 +178,7 @@ pub fn init(dep: *std.Build.Dependency) Self { }), .pico_flashless = chip_rp2040.derive(.{ .ram_image = true, - // we do not need any modifications to the default generated linker script + // we can use the default generated linker script .linker_script = .{}, .board = .{ .name = "RaspberryPi Pico (ram image)", diff --git a/tools/generate_linker_script.zig b/tools/generate_linker_script.zig index 929853df6..a2868a91b 100644 --- a/tools/generate_linker_script.zig +++ b/tools/generate_linker_script.zig @@ -126,25 +126,25 @@ pub fn main() !void { \\ ); - if (parsed_args.ram_image) { + if (!parsed_args.ram_image) { try writer.print( - \\ .ram_start : + \\ .flash_start : \\ {{ - \\ KEEP(*(microzig_ram_start)) + \\ KEEP(*(microzig_flash_start)) \\ }} > {s} \\ , - .{ram_region_name}, + .{flash_region_name}, ); } else { try writer.print( - \\ .flash_start : + \\ .ram_start : \\ {{ - \\ KEEP(*(microzig_flash_start)) + \\ KEEP(*(microzig_ram_start)) \\ }} > {s} \\ , - .{flash_region_name}, + .{ram_region_name}, ); } From 420df35c0c64d2f488e432216e61fcdee043e269 Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 12:13:20 +0300 Subject: [PATCH 08/12] prettify linker script --- tools/generate_linker_script.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/generate_linker_script.zig b/tools/generate_linker_script.zig index a2868a91b..c40a47af5 100644 --- a/tools/generate_linker_script.zig +++ b/tools/generate_linker_script.zig @@ -149,6 +149,7 @@ pub fn main() !void { } try writer.writeAll( + \\ \\ .text : \\ { \\ *(.text*) @@ -177,6 +178,7 @@ pub fn main() !void { switch (parsed_args.cpu_arch) { .arm, .thumb => try writer.print( + \\ \\ .ARM.extab : {{ \\ *(.ARM.extab* .gnu.linkonce.armextab.*) \\ }} > {[flash]s} @@ -190,6 +192,7 @@ pub fn main() !void { } try writer.writeAll( + \\ \\ .data : \\ { \\ microzig_data_start = .; @@ -237,6 +240,7 @@ pub fn main() !void { if (!parsed_args.ram_image) { try writer.print( + \\ \\ .flash_end : \\ {{ \\ microzig_flash_end = .; @@ -246,6 +250,7 @@ pub fn main() !void { } try writer.writeAll( + \\ \\ microzig_data_load_start = LOADADDR(.data); \\ ); From 882b5610edd485a3c4ca0412ad94c3286e489bf5 Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 12:18:20 +0300 Subject: [PATCH 09/12] add flashless blinky examples for pico2 --- examples/raspberrypi/rp2xxx/build.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/raspberrypi/rp2xxx/build.zig b/examples/raspberrypi/rp2xxx/build.zig index 7da4bf5cb..46607bd32 100644 --- a/examples/raspberrypi/rp2xxx/build.zig +++ b/examples/raspberrypi/rp2xxx/build.zig @@ -26,6 +26,8 @@ pub fn build(b: *std.Build) void { .{ .target = raspberrypi.pico, .name = "pico_pcf8574", .file = "src/rp2040_only/pcf8574.zig" }, .{ .target = raspberrypi.pico, .name = "pico_i2c_slave", .file = "src/rp2040_only/i2c_slave.zig" }, .{ .target = raspberrypi.pico_flashless, .name = "pico_flashless_blinky", .file = "src/blinky.zig" }, + .{ .target = raspberrypi.pico2_arm_flashless, .name = "pico2_arm_flashless_blinky", .file = "src/blinky.zig" }, + .{ .target = raspberrypi.pico2_riscv_flashless, .name = "pico2_riscv_flashless_blinky", .file = "src/blinky.zig" }, .{ .target = raspberrypi.pico2_arm, .name = "pico2_arm_random_data", .file = "src/rp2350_only/random_data.zig" }, .{ .target = raspberrypi.pico2_riscv, .name = "pico2_riscv_random_data", .file = "src/rp2350_only/random_data.zig" }, From d35b780f9c2ef1ecb01a5ddcebbc61effb9d5de6 Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 20:17:05 +0300 Subject: [PATCH 10/12] update image_def_block --- port/raspberrypi/rp2xxx/src/hal/bootmeta.zig | 28 +++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig b/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig index d44da4daf..2ac73fc0a 100644 --- a/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig +++ b/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig @@ -4,29 +4,43 @@ const root = @import("root"); const microzig = @import("microzig"); const arch = @import("compatibility.zig").arch; -pub const image_def_block: Block(extern struct { +pub const image_def_block = if (microzig.config.ram_image and arch == .arm) Block(extern struct { image_def: ImageDef, entry_point: EntryPoint(false), -}) = .{ +}){ .items = .{ .image_def = .{ .image_type_flags = .{ .image_type = .exe, .exe_security = root.microzig_options.hal.image_def_exe_security, - .cpu = std.meta.stringToEnum(ImageDef.ImageTypeFlags.Cpu, @tagName(arch)).?, + .cpu = .arm, .chip = .RP2350, .try_before_you_buy = false, }, }, + //We must specify a custom entry point since by default RP2350 expects + //the vector table at the start of the image. .entry_point = .{ - .entry = if (microzig.config.ram_image and arch == .arm) - µzig.cpu.startup_logic.ram_image_entrypoint - else - µzig.cpu.startup_logic._start, + .entry = µzig.cpu.startup_logic.ram_image_entrypoint, .sp = microzig.config.end_of_stack, }, }, .link = root.microzig_options.hal.next_metadata_block, +} else Block(extern struct { + image_def: ImageDef, +}){ + .items = .{ + .image_def = .{ + .image_type_flags = .{ + .image_type = .exe, + .exe_security = root.microzig_options.hal.image_def_exe_security, + .cpu = std.meta.stringToEnum(ImageDef.ImageTypeFlags.Cpu, @tagName(arch)).?, + .chip = .RP2350, + .try_before_you_buy = false, + }, + }, + }, + .link = root.microzig_options.hal.next_metadata_block, }; comptime { From 5cdd6dd8ed525f2ab85ec4c014b71a883700bde2 Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 20:24:26 +0300 Subject: [PATCH 11/12] update comment --- port/raspberrypi/rp2xxx/src/hal/bootmeta.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig b/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig index 2ac73fc0a..f9a03c8b7 100644 --- a/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig +++ b/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig @@ -18,8 +18,8 @@ pub const image_def_block = if (microzig.config.ram_image and arch == .arm) Bloc .try_before_you_buy = false, }, }, - //We must specify a custom entry point since by default RP2350 expects - //the vector table at the start of the image. + // We must specify a custom entry point since by default RP2350 expects + // the vector table at the start of the image. .entry_point = .{ .entry = µzig.cpu.startup_logic.ram_image_entrypoint, .sp = microzig.config.end_of_stack, From 0ece330dc74e1372ba101630edf3df7581bdb0aa Mon Sep 17 00:00:00 2001 From: tact1m4n3 Date: Tue, 24 Jun 2025 21:15:25 +0300 Subject: [PATCH 12/12] final touches --- core/src/cpus/cortex_m.zig | 4 ++-- port/raspberrypi/rp2xxx/src/hal.zig | 14 ++++++++------ port/raspberrypi/rp2xxx/src/hal/bootmeta.zig | 12 ++++++------ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig index 44dc146ce..bff8eb749 100644 --- a/core/src/cpus/cortex_m.zig +++ b/core/src/cpus/cortex_m.zig @@ -591,7 +591,7 @@ pub const startup_logic = struct { extern var microzig_bss_end: u8; extern const microzig_data_load_start: u8; - pub fn ram_image_entrypoint() linksection("microzig_ram_start") callconv(.naked) void { + pub fn ram_image_entry_point() linksection("microzig_ram_start") callconv(.naked) void { asm volatile ( \\ // Set VTOR to point to ram table @@ -684,7 +684,7 @@ fn is_ramimage() bool { pub fn export_startup_logic() void { if (is_ramimage()) - @export(&startup_logic.ram_image_entrypoint, .{ + @export(&startup_logic.ram_image_entry_point, .{ .name = "_entry_point", .linkage = .strong, }) diff --git a/port/raspberrypi/rp2xxx/src/hal.zig b/port/raspberrypi/rp2xxx/src/hal.zig index d4238ab89..7e4fd5c77 100644 --- a/port/raspberrypi/rp2xxx/src/hal.zig +++ b/port/raspberrypi/rp2xxx/src/hal.zig @@ -49,12 +49,14 @@ comptime { pub const HAL_Options = switch (compatibility.chip) { .RP2040 => struct {}, .RP2350 => struct { - image_def_exe_security: bootmeta.ImageDef.ImageTypeFlags.ExeSecurity = .secure, - - /// Next metadata block to link after image_def. **Last block in the - /// chain must link back to the first one** (to - /// `bootmeta.image_def_block`). - next_metadata_block: ?*const anyopaque = null, + bootmeta: struct { + image_def_exe_security: bootmeta.ImageDef.ImageTypeFlags.ExeSecurity = .secure, + + /// Next metadata block to link after image_def. **Last block in the + /// chain must link back to the first one** (to + /// `bootmeta.image_def_block`). + next_block: ?*const anyopaque = null, + } = .{}, }, }; diff --git a/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig b/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig index f9a03c8b7..b2ca8f5b7 100644 --- a/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig +++ b/port/raspberrypi/rp2xxx/src/hal/bootmeta.zig @@ -12,7 +12,7 @@ pub const image_def_block = if (microzig.config.ram_image and arch == .arm) Bloc .image_def = .{ .image_type_flags = .{ .image_type = .exe, - .exe_security = root.microzig_options.hal.image_def_exe_security, + .exe_security = root.microzig_options.hal.bootmeta.image_def_exe_security, .cpu = .arm, .chip = .RP2350, .try_before_you_buy = false, @@ -21,11 +21,11 @@ pub const image_def_block = if (microzig.config.ram_image and arch == .arm) Bloc // We must specify a custom entry point since by default RP2350 expects // the vector table at the start of the image. .entry_point = .{ - .entry = µzig.cpu.startup_logic.ram_image_entrypoint, - .sp = microzig.config.end_of_stack, + .entry = µzig.cpu.startup_logic.ram_image_entry_point, + .sp = microzig.cpu.startup_logic._vector_table.initial_stack_pointer, }, }, - .link = root.microzig_options.hal.next_metadata_block, + .link = root.microzig_options.hal.bootmeta.next_block, } else Block(extern struct { image_def: ImageDef, }){ @@ -33,14 +33,14 @@ pub const image_def_block = if (microzig.config.ram_image and arch == .arm) Bloc .image_def = .{ .image_type_flags = .{ .image_type = .exe, - .exe_security = root.microzig_options.hal.image_def_exe_security, + .exe_security = root.microzig_options.hal.bootmeta.image_def_exe_security, .cpu = std.meta.stringToEnum(ImageDef.ImageTypeFlags.Cpu, @tagName(arch)).?, .chip = .RP2350, .try_before_you_buy = false, }, }, }, - .link = root.microzig_options.hal.next_metadata_block, + .link = root.microzig_options.hal.bootmeta.next_block, }; comptime {