Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions builder/esp.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,18 @@ func makeESPFirmwareImage(infile, outfile, format string) error {
}
segments = ramSegments

case "esp32c3":
var ramSegments []*espImageSegment
for _, seg := range segments {
if (seg.addr >= 0x3C000000 && seg.addr < 0x3C800000) ||
(seg.addr >= 0x42000000 && seg.addr < 0x42800000) {
flashSegments = append(flashSegments, seg)
} else {
ramSegments = append(ramSegments, seg)
}
}
segments = ramSegments

case "esp32s3":
var ramSegments []*espImageSegment
for _, seg := range segments {
Expand Down Expand Up @@ -480,6 +492,22 @@ func makeESPFirmwareImage(infile, outfile, format string) error {
outf.Write(esp32s3DromSegment.data)
}

// ESP32-C3 IROM and DROM are mapped 1:1, so the offset in the 8 MB flash
// address space is the offset in the image. See targets/esp32c3.ld.
if chip == "esp32c3" {
sort.SliceStable(flashSegments, func(i, j int) bool {
return flashSegments[i].addr&0x7FFFFF < flashSegments[j].addr&0x7FFFFF
})
for _, seg := range flashSegments {
offset := int(seg.addr & 0x7FFFFF)
if outf.Len() > offset {
return fmt.Errorf("ESP32-C3: segment at 0x%x overlaps the previous one", seg.addr)
}
outf.Write(make([]byte, offset-outf.Len()))
outf.Write(seg.data)
}
}

// QEMU (or more precisely, qemu-system-xtensa from Espressif) expects the
// image to be a certain size.
if makeImage {
Expand Down
4 changes: 2 additions & 2 deletions builder/testdata/binary-size.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ pico examples/serial z 7737 1071 112 5616
pico examples/serial 2 16346 862 108 5616
pico2 examples/serial z 6532 1172 112 5608
pico2 examples/serial 2 15957 979 108 5608
esp32c3-generic examples/serial z 5864 768 0 8664
esp32c3-generic examples/serial 2 9888 600 8 8672
esp32c3-generic examples/serial z 5844 772 0 8664
esp32c3-generic examples/serial 2 9956 604 8 8672
cortex-m-qemu ./testdata/size-slice z 3087 793 4 4168
cortex-m-qemu ./testdata/size-slice 2 7331 341 4 4168
cortex-m-qemu ./testdata/size-defer z 3782 818 4 4176
Expand Down
84 changes: 41 additions & 43 deletions targets/esp32c3.ld
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,11 @@
* - Memory in DRAM and IRAM is loaded at reset by the ROM bootloader.
* Luckily, this doesn't have significant alignment requirements.
*
* This linker script has been written to carefully work around (or with) these
* limitations:
* - It adds dummy sections so that the bottom 16 bits of the virtual address
* and the physical address (in the generated firmware image) match.
* - It also offsets sections that share an address space using those same
* dummy sections.
* - It sorts the sections by load address, to avoid surprises as esptool.py
* also does it.
* This way, it's possible to create a very small firmware image that still
* conforms to the expectations of esptool.py and the ROM bootloader.
* This linker script works with these limitations:
* - The ROM bootloader rejects IROM or DROM segments of 1 MiB or more, so
* it only loads DRAM and IRAM. IROM and then DROM follow in flash.
* - IROM and DROM are mapped 1:1, so the bottom 16 bits of the virtual
* address and the flash offset match, and they don't overlap.
*/

MEMORY
Expand All @@ -48,24 +43,6 @@ ENTRY(call_start_cpu0)

SECTIONS
{
/* Dummy section to make sure the .rodata section starts exactly behind the
* image header.
*/
.rodata_dummy (NOLOAD): ALIGN(4)
{
. += 0x18; /* image header at start of flash: esp_image_header_t */
. += 0x8; /* DROM segment header (8 bytes) */
} > DROM

/* Constant global variables, stored in DROM.
*/
.rodata : ALIGN(4)
{
*(.rodata*)
*(.srodata*)
. = ALIGN (4);
} >DROM

/* Put the stack at the bottom of DRAM, so that the application will
* crash on stack overflow instead of silently corrupting memory.
* See: http://blog.japaric.io/stack-overflow-protection/
Expand Down Expand Up @@ -138,37 +115,58 @@ SECTIONS
__init_start = .;
*(.init)
__init_end = .;
. = ALIGN (4);
} >IRAM

/* Dummy section to put the IROM segment exactly behind the IRAM segment.
* This has to follow the app image format exactly.
*/
/* Size of the RAM part of the image. Header, segments, padding to 16 bytes
* and the SHA-256 digest, as written by builder/esp.go. */
_ram_image_payload_size =
0x18 +
SIZEOF(.data) + ((SIZEOF(.data) != 0) ? 0x8 : 0) +
SIZEOF(.iram) + 0x8;

_ram_image_size =
_ram_image_payload_size +
16 - (_ram_image_payload_size % 16) +
0x20;

/* The ROM only loads the RAM part of the image. IROM and DROM follow it
* in flash and esp32c3.S maps them 1:1, so each VMA offset is its flash
* offset. */
.text_dummy (NOLOAD): ALIGN(4)
{
/* Note: DRAM and DROM are not always present so the header should only
* be inserted if it actually exists.
*/
. += 0x18; /* esp_image_header_t */
. += SIZEOF(.rodata) + ((SIZEOF(.rodata) != 0) ? 0x8 : 0); /* DROM segment (optional) */
. += SIZEOF(.data) + ((SIZEOF(.data) != 0) ? 0x8 : 0); /* DRAM segment (optional) */
. += SIZEOF(.iram) + 0x8; /* IRAM segment */
. += 0x8; /* IROM segment header */
. += _ram_image_size;
} > IROM

/* IROM segment. This contains all the actual code and is placed right after
* the DROM segment.
/* IROM segment. This contains all the actual code.
*/
.text : ALIGN(4)
{
. = ALIGN (256);
*(.text.exception_vectors)
. = ALIGN (4);
*(.text .text.*)
. = ALIGN (4);
_irom_end = .;
} >IROM

/* The 64 bytes skip the image footer written by builder/esp.go. */
PROVIDE(__flash_data_start = ALIGN(_irom_end - 0x42000000 + 0x3C000000 + 64, 4096));
/* DROM and IROM share one address space, so DROM starts after IROM. */
.rodata_dummy (NOLOAD): ALIGN(4)
{
. += _ram_image_size + SIZEOF(.text);
} > DROM

/* Constant global variables, stored in DROM.
*/
.rodata : ALIGN(4)
{
*(.rodata*)
*(.srodata*)
. = ALIGN (4);
_drom_end = .;
} >DROM

PROVIDE(__flash_data_start = ALIGN(_drom_end, 4096));
PROVIDE(__flash_data_end = 0x3C000000 + 4M);
PROVIDE(__flash_data_phys = __flash_data_start - 0x3C000000);

Expand Down
Loading