ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_memmap.c
Go to the documentation of this file.
1
16
17#include "emu_memmap.h"
18
19#include <errno.h>
20#include <sys/mman.h>
21
22#include "emu_console.h"
24#include "emu_mmio.h"
25
26#ifndef MAP_ANONYMOUS
37#define MAP_ANONYMOUS MAP_ANON
38#endif
39
40/* RA8D2 memory map (EK board) -- from the linker script / HUM R01UH1065EJ. */
41static const mem_region_t s_regions[] = {
42 {"ITCM", 0x00000000UL, 0x00010000UL}, /* 64 KiB tightly-coupled code */
43 {"MRAM", 0x02000000UL, 0x00100000UL}, /* 1 MiB code flash + vectors */
44 {"TRIM", 0x02C1E000UL, 0x00001000UL}, /* MRAM factory-trim page: the
45 * on-chip temperature-sensor
46 * calibration cells (TSCDR/TSCDR2 at
47 * 0x02C1EDA0) live here. Mapped +
48 * seeded (see k_tsn_cal_*) so
49 * ra8_tsn reads a real two-point pair
50 * instead of bus-faulting on the
51 * previously-unmapped read. */
52 {"OFS_CFG", 0x02C9F000UL, 0x00001000UL}, /* Option-setting configuration words
53 * (OFS0/1/2/3, SAS, BPS, selectors) --
54 * HUM Ch 7 Figure 7.1 p 279, secure alias
55 * 0x02C9_F0xx. Replaces the phantom
56 * 0x0300A000 OFS block (#391). */
57 {"OFS_OTP", 0x02E07000UL, 0x00011000UL}, /* Option-setting OTP area + the extra-MRAM
58 * Program window: FSBL, code-cert, GPOTP,
59 * PBPS, POFSPS, REVOKE, ZHUK, anti-rollback
60 * (HUM Ch 59.7.4.5 Table 59.15 p 3592,
61 * 0x02E0_7600..0x02E1_79F0). Readable on
62 * silicon, so mapped; the MACI model
63 * (board_periph_mram.c) lands accepted
64 * Program payloads here. */
65 {"DTCM", 0x20000000UL, 0x00010000UL}, /* 64 KiB tightly-coupled data */
66 {"SRAM", 0x22000000UL, 0x001D4000UL}, /* On-chip SRAM: CPU0 bank + shared mailbox +
67 * CPU1 bank. The extent is BENCH-MEASURED, not
68 * assumed: over J-Link on an EK-RA8D2, words at
69 * 0x221D0000, 0x221D2000 and 0x221D3FFC read and
70 * write normally, while 0x221D4000 answers
71 * "Could not read memory" and 0x221E0000 /
72 * 0x22200000 answer "Failed to write memory".
73 * Distinct values written at 0x22030000 and
74 * 0x221B0000 survive independently, so the top
75 * of the window is real memory and not an alias
76 * of the bottom.
77 *
78 * This window used to be a deliberately wide
79 * 4 MiB "so every dual-core example maps
80 * cleanly", which made 2.2 MB of NONEXISTENT
81 * address space silently writable here. That is
82 * the exact defect shape that let
83 * ota_ab_orchestration hold hw_validated while
84 * its A/B slots went to an address the silicon
85 * does not decode (#397): a model permissive
86 * where the hardware is not cannot fail, so it
87 * validates nothing. */
88 {"NS_SRAM2", 0x32100000UL, 0x00080000UL}, /* SRAM2 Non-secure alias (bit[28]=1): the
89 * TrustZone NS image run region. The Secure
90 * boot copies the NS image here then BLXNS-es
91 * to it; mapping it lets two-image TZ apps
92 * run their NS world in ra8_emulator. */
93 /* No DATA_FLASH region. 0x27000000 was carried in every app linker script as a
94 * 16 KiB "data flash (EEPROM emulation)" MEMORY declaration inherited from
95 * other RA parts, and ra8_emulator used to map it as plain RAM -- so writes there
96 * succeeded in the emulator. They do not on this silicon: a J-Link
97 * `w4 0x27000000` on an EK-RA8D2 answers "Failed to write memory". That gap
98 * is what #397 found under ra8_io_mram_demo. #397 removed the phantom region
99 * from the linker scripts and repointed the extra-MRAM constant at the real
100 * option-setting window (OFS_OTP above, 0x02E0_7600); 0x27000000 stays
101 * unmapped so any straggler write still faults exactly where the bench does. */
102 {"SDRAM", 0x68000000UL, 0x04000000UL}, /* 64 MiB external SDRAM (Secure
103 * physical view). Host-backed so the
104 * NS alias below mirrors the bytes:
105 * the GLCDC model scans the
106 * framebuffer from here while the NS
107 * world draws it through 0x78000000. */
108 {"NS_SDRAM", 0x78000000UL, 0x04000000UL}, /* External SDRAM Non-secure alias
109 * (IDAU bit[28]=1): the SAME 64 MiB
110 * array as SDRAM. The Non-secure
111 * e-reader writes framebuffer pixels
112 * through this alias; sharing one
113 * host mapping makes them visible to
114 * the Secure GLCDC read at
115 * 0x68000000. */
116 {"OSPI", 0x80000000UL, 0x04000000UL}, /* 64 MiB Octo-SPI XIP flash (Secure
117 * physical view). Memory-mapped and
118 * executable: an NS reader image runs
119 * execute-in-place from here. Host-
120 * backed and shared with NS_OSPI so
121 * the alias below mirrors the bytes. */
122 {"NS_OSPI", 0x90000000UL, 0x04000000UL}, /* OSPI XIP Non-secure alias
123 * (IDAU bit[28]=1): the SAME 64 MiB
124 * flash array as OSPI. The XIP-linked
125 * NS image's .text/.rodata live at
126 * 0x90000000; the M85 fetches NS
127 * instructions from this alias. */
128 {"PPB", 0xE0000000UL, 0x00100000UL}, /* ARM private peripheral bus */
129};
130
131/* Octo-SPI (XSPI) execute-in-place flash window. The XSPI controller's register
132 * command-engine is modelled in peripheral space (board_periph_xspi.c, base
133 * 0x40268000); this is the SEPARATE memory-mapped, executable view of the 64 MiB
134 * flash array the controller exposes once the firmware enters XIP mode. The
135 * Secure physical window sits at 0x80000000; its TrustZone Non-secure alias
136 * (IDAU bit[28]=1) sits at 0x90000000. Both views address the same flash array,
137 * so ra8_emulator binds them to a single host mapping (mirrors the SRAM/NS_SRAM2
138 * alias pair). A Non-secure reader image linked for XIP places .text/.rodata at
139 * 0x90000000 and the CPU fetches Non-secure instructions from there. */
140typedef enum : uint64_t {
141 k_ospi_xip_base = 0x80000000UL,
142 k_ospi_ns_base = 0x90000000UL,
144
145/* On-chip temperature-sensor factory calibration. The TSN two-point trim words
146 * TSCDR (code at the high reference) and TSCDR2 (code at the low reference) live
147 * in the MRAM factory-trim region at 0x02C1EDA0 (HUM Ch 55.2.2 p 3498-3499).
148 * Real silicon ships them factory-programmed; ra8_emulator's blank map left the
149 * region unreadable, so ra8_tsn_convert_to_milli_c bus-faulted (UC_ERR_READ_-
150 * UNMAPPED) reading them and adc_diag_tsn_demo aborted. Seed a deterministic,
151 * plausible positive-slope pair (TSCDR @ +125C > TSCDR2 @ -40C) into the mapped
152 * TRIM page after mem-map. Paired with the ADC temperature code the ADC model
153 * reports (k_adc_temp_code = 1800 in board_periph_adc.c), the two-point math
154 * yields ~26 degC. This is factory-constant data, not a masked poll. */
155typedef enum : uint32_t {
156 k_tsn_cal_addr = 0x02C1EDA0U,
160
162typedef enum : size_t {
167
169typedef enum : uint64_t {
170 k_sram_size = 0x001D4000UL,
171 k_sdram_size = 0x04000000UL,
172 k_ospi_size = 0x04000000UL,
173 k_ns_sram2_offset = 0x00100000UL,
174 k_ns_sram2_size = 0x00080000UL,
178
180typedef enum : int {
184
186 "the SRAM2 Non-secure alias must lie inside the on-chip SRAM aperture");
188 "the reported logical geometry must be the sum of the three apertures");
189
196typedef struct {
197 uint64_t base;
198 size_t backing;
199 uint64_t offset;
201
219{
220 return (emu_memmap_result_t){.status = status,
221 .logical_backing_bytes = k_logical_bytes,
222 .os_error = os_error};
223}
224
243RA8_INTERNAL static uint8_t*
244internal_window_host(const emu_memmap_workspace_t* workspace, uint64_t base, uint64_t size)
245{
247 static const aliased_window_t k_aliased_windows[] = {
248 {(uint64_t)k_sram_base, k_backing_sram, 0U},
250 {(uint64_t)k_sdram_base, k_backing_sdram, 0U},
251 {(uint64_t)k_ns_sdram_base, k_backing_sdram, 0U},
252 {(uint64_t)k_ospi_xip_base, k_backing_ospi, 0U},
253 {(uint64_t)k_ospi_ns_base, k_backing_ospi, 0U},
254 };
255 for (size_t index = 0U; index < (sizeof(k_aliased_windows) / sizeof(k_aliased_windows[0]));
256 index++) {
257 const aliased_window_t* const window = &k_aliased_windows[index];
258 if (window->base != base) {
259 continue;
260 }
261 const emu_memmap_backing_t* const backing = &workspace->backings[window->backing];
262 if ((backing->host == nullptr) || (size > backing->size) ||
263 (window->offset > (backing->size - size))) {
264 return nullptr;
265 }
266 return &backing->host[window->offset];
267 }
268 return nullptr;
269}
270
289RA8_INTERNAL static bool internal_backing_open(uint64_t size, emu_memmap_backing_t* backing)
290{
291 void* const host = mmap(nullptr,
292 (size_t)size,
293 PROT_READ | PROT_WRITE,
294 MAP_PRIVATE | MAP_ANONYMOUS,
295 (int)k_mmap_no_fd,
296 (off_t)k_mmap_no_offset);
297 if (host == MAP_FAILED) {
298 return false;
299 }
300 *backing = (emu_memmap_backing_t){.host = (uint8_t*)host, .size = size};
301 return true;
302}
303
317{
318 for (size_t index = 0U; index < k_emu_memmap_backing_count; index++) {
319 emu_memmap_backing_t* const backing = &workspace->backings[index];
320 if (backing->host != nullptr) {
321 (void)munmap(backing->host, (size_t)backing->size);
322 }
323 *backing = (emu_memmap_backing_t){};
324 }
325}
326
340RA8_INTERNAL static void internal_seed_tsn(uc_engine* uc)
341{
342 const uint32_t tscdr = (uint32_t)k_tsn_cal_tscdr;
343 const uint32_t tscdr2 = (uint32_t)k_tsn_cal_tscdr2;
344 (void)emu_mem_write(uc, (uint64_t)k_tsn_cal_addr, &tscdr, sizeof(tscdr));
345 (void)emu_mem_write(uc, (uint64_t)k_tsn_cal_addr + sizeof(tscdr), &tscdr2, sizeof(tscdr2));
346}
347
363RA8_INTERNAL static bool internal_map_periph_mmio(uc_engine* uc)
364{
365 if (uc_mmio_map(uc,
366 (uint64_t)k_periph_base,
367 (size_t)k_periph_size,
368 mmio_read,
369 nullptr,
371 nullptr) != UC_ERR_OK) {
372 (void)priv_emu_io_errf("mmio_map failed\n");
373 return false;
374 }
375 /* IDAU bit[28]=1 Non-secure peripheral alias (0x50000000): the SAME silicon
376 * registers as 0x40000000, reached by TrustZone Non-secure code (an NS image
377 * built with RA8_PERIPH_NS_ALIAS -- MSTP at 0x5020_3000, USBFS at
378 * 0x5025_0000, USBHS at 0x5035_1000 -- or the NS-side IPC ping-pong at
379 * 0x5002_0000). The hooks rebuild the absolute address as k_periph_base +
380 * window-relative offset, so a 0x50020000 access (offset 0x20000) dispatches
381 * to 0x40020000 identically to a Secure one -- the exact mapping the cpu1
382 * engine already carries (see cpu1_engine_init). */
383 if (uc_mmio_map(uc,
384 (uint64_t)k_periph_base | (uint64_t)k_ns_alias_bit,
385 (size_t)k_periph_size,
386 mmio_read,
387 nullptr,
389 nullptr) != UC_ERR_OK) {
390 (void)priv_emu_io_errf("mmio_map (NS alias) failed\n");
391 return false;
392 }
393 return true;
394}
395
416 uc_engine* uc)
417{
418 for (size_t index = 0U; index < (sizeof(s_regions) / sizeof(s_regions[0])); index++) {
419 const mem_region_t* const region = &s_regions[index];
420 uint8_t* const host = internal_window_host(workspace, region->base, region->size);
421 const uc_err mapped =
422 (host != nullptr) ? uc_mem_map_ptr(uc, region->base, (size_t)region->size, UC_PROT_ALL, host)
423 : uc_mem_map(uc, region->base, (size_t)region->size, UC_PROT_ALL);
424 if (mapped != UC_ERR_OK) {
425 (void)priv_emu_io_errf("map %s @0x%08llX failed\n",
426 region->name,
427 (unsigned long long)region->base);
428 return false;
429 }
430 }
431 return true;
432}
433
438
440{
441 if ((workspace == nullptr) || workspace->open) {
443 }
444 emu_memmap_workspace_t candidate = {};
445 const uint64_t sizes[k_emu_memmap_backing_count] = {
449 };
450
451 for (size_t index = 0U; index < k_emu_memmap_backing_count; index++) {
452 if (!internal_backing_open(sizes[index], &candidate.backings[index])) {
453 const int failure = errno;
454 internal_backings_close(&candidate);
455 return internal_result(k_emu_memmap_backing, failure);
456 }
457 }
458 candidate.open = true;
459 *workspace = candidate;
461}
462
464{
465 if ((workspace == nullptr) || !workspace->open || (uc == nullptr)) {
467 }
468 emu_memmap_binding_t* binding = nullptr;
469 for (size_t index = 0U; index < k_emu_memmap_binding_count; index++) {
470 if (!workspace->bindings[index].active) {
471 binding = &workspace->bindings[index];
472 break;
473 }
474 }
475 if (binding == nullptr) {
477 }
478 if (!internal_map_regions(workspace, uc) || !internal_map_periph_mmio(uc)) {
480 }
481 *binding = (emu_memmap_binding_t){.uc = uc, .active = true};
484}
485
486bool emu_memmap_detach(emu_memmap_workspace_t* workspace, uc_engine* uc)
487{
488 if ((workspace == nullptr) || (uc == nullptr)) {
489 return false;
490 }
491 for (size_t index = 0U; index < k_emu_memmap_binding_count; index++) {
492 if (workspace->bindings[index].active && (workspace->bindings[index].uc == uc)) {
493 workspace->bindings[index] = (emu_memmap_binding_t){};
494 return true;
495 }
496 }
497 return false;
498}
499
501{
502 if ((workspace == nullptr) || !workspace->open) {
503 return true;
504 }
505 for (size_t index = 0U; index < k_emu_memmap_binding_count; index++) {
506 if (workspace->bindings[index].active) {
507 return false;
508 }
509 }
510 internal_backings_close(workspace);
511 *workspace = (emu_memmap_workspace_t){};
512 return true;
513}
514
516const mem_region_t* emu_memmap_regions(uint32_t* count)
517{
518 *count = (uint32_t)(sizeof(s_regions) / sizeof(s_regions[0]));
519 return s_regions;
520}
521
524{
525 return s_regions[1].base;
526}
Emulator text-console surfaces: UART echo, ITM/SWO echo, escapes.
@ k_ns_sram2_base
SRAM2 Non-secure alias (bit[28]=1).
Definition emu_console.h:54
@ k_ns_alias_bit
IDAU bit[28]: NS alias of a Secure addr.
Definition emu_console.h:55
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
emu_memmap_result_t emu_memmap_open(emu_memmap_workspace_t *workspace)
Create three independent, lazily-committed host aperture mappings.
Definition emu_memmap.c:439
static RA8_INTERNAL emu_memmap_result_t internal_result(emu_memmap_status_t status, int os_error)
Construct one exact lifecycle result.
Definition emu_memmap.c:218
emu_memmap_result_t emu_memmap_requirements(void)
Report the immutable aliased-aperture backing geometry.
Definition emu_memmap.c:434
static RA8_INTERNAL void internal_seed_tsn(uc_engine *uc)
Seed deterministic factory TSN calibration words.
Definition emu_memmap.c:340
static RA8_INTERNAL uint8_t * internal_window_host(const emu_memmap_workspace_t *workspace, uint64_t base, uint64_t size)
Resolve a guest region base to its shared host aperture address.
Definition emu_memmap.c:244
tsn_cal_seed_t
Definition emu_memmap.c:155
@ k_tsn_cal_addr
TSCDR (+0x00), TSCDR2 (+0x04).
Definition emu_memmap.c:156
@ k_tsn_cal_tscdr2
12-bit calibration code at -40 degC.
Definition emu_memmap.c:158
@ k_tsn_cal_tscdr
12-bit calibration code at +125 degC.
Definition emu_memmap.c:157
static RA8_INTERNAL void internal_backings_close(emu_memmap_workspace_t *workspace)
Release every acquired aperture mapping in a workspace.
Definition emu_memmap.c:316
mmap_argument_t
Fixed arguments for an anonymous host aperture mapping.
Definition emu_memmap.c:180
@ k_mmap_no_fd
Anonymous mappings are backed by no descriptor.
Definition emu_memmap.c:181
@ k_mmap_no_offset
Anonymous mappings start at offset zero.
Definition emu_memmap.c:182
emu_memmap_result_t emu_memmap_attach(emu_memmap_workspace_t *workspace, uc_engine *uc)
Map one Unicorn engine onto the shared aperture backing.
Definition emu_memmap.c:463
static RA8_INTERNAL bool internal_map_periph_mmio(uc_engine *uc)
Map the Secure peripheral window and its IDAU bit[28] NS alias.
Definition emu_memmap.c:363
ospi_xip_map_t
Definition emu_memmap.c:140
@ k_ospi_ns_base
OSPI XIP window: NS alias (IDAU bit[28]=1).
Definition emu_memmap.c:142
@ k_ospi_xip_base
OSPI XIP window: Secure physical base.
Definition emu_memmap.c:141
backing_index_t
Identity of each shared aperture within a workspace.
Definition emu_memmap.c:162
@ k_backing_sdram
External SDRAM aperture index.
Definition emu_memmap.c:164
@ k_backing_sram
On-chip SRAM aperture index.
Definition emu_memmap.c:163
@ k_backing_ospi
OSPI XIP aperture index.
Definition emu_memmap.c:165
bool emu_memmap_detach(emu_memmap_workspace_t *workspace, uc_engine *uc)
Remove one engine binding before closing that Unicorn engine.
Definition emu_memmap.c:486
static RA8_INTERNAL bool internal_map_regions(const emu_memmap_workspace_t *workspace, uc_engine *uc)
Map every guest region into one engine, sharing the apertures.
Definition emu_memmap.c:415
bool emu_memmap_close(emu_memmap_workspace_t *workspace)
Release every host aperture mapping after all engines detached.
Definition emu_memmap.c:500
uint64_t emu_memmap_mram_base(void)
Implementation of emu_memmap_mram_base() – named MRAM lookup.
Definition emu_memmap.c:523
static RA8_INTERNAL bool internal_backing_open(uint64_t size, emu_memmap_backing_t *backing)
Acquire one zero-filled, lazily-committed host aperture mapping.
Definition emu_memmap.c:289
const mem_region_t * emu_memmap_regions(uint32_t *count)
Implementation of emu_memmap_regions() – static table access.
Definition emu_memmap.c:516
backing_geometry_t
Exact logical extents of the three shared apertures.
Definition emu_memmap.c:169
@ k_sram_size
Exact on-chip SRAM extent.
Definition emu_memmap.c:170
@ k_logical_bytes
Total logical bytes the three shared apertures span.
Definition emu_memmap.c:176
@ k_ospi_size
Exact OSPI XIP extent.
Definition emu_memmap.c:172
@ k_ns_sram2_size
SRAM2 alias extent.
Definition emu_memmap.c:174
@ k_sdram_size
Exact external SDRAM extent.
Definition emu_memmap.c:171
@ k_ns_sram2_offset
SRAM offset the SRAM2 alias starts at.
Definition emu_memmap.c:173
#define MAP_ANONYMOUS
Portable spelling of the anonymous-mapping flag.
Definition emu_memmap.c:37
Shared aliased-memory backing and Unicorn memory-map bindings.
struct emu_memmap_workspace emu_memmap_workspace_t
Independent aperture backing with at most two engine bindings.
emu_memmap_status_t
Semantic result for backing lifecycle operations.
Definition emu_memmap.h:62
@ k_emu_memmap_ok
Operation completed exactly.
Definition emu_memmap.h:63
@ k_emu_memmap_backing
A host aperture mapping could not be made.
Definition emu_memmap.h:65
@ k_emu_memmap_invalid
Pointer, state, or engine was invalid.
Definition emu_memmap.h:64
@ k_emu_memmap_unicorn
Unicorn map or window install failed.
Definition emu_memmap.h:66
@ k_emu_memmap_binding_count
CPU0 and optional CPU1 engines.
Definition emu_memmap.h:58
@ k_emu_memmap_backing_count
SRAM, SDRAM, and OSPI host mappings.
Definition emu_memmap.h:57
@ k_sdram_base
External SDRAM start.
Definition emu_memmap.h:46
@ k_sram_base
On-chip SRAM start.
Definition emu_memmap.h:42
@ k_ns_sdram_base
Non-secure SDRAM alias.
Definition emu_memmap.h:50
uc_err emu_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t count)
Write guest memory through the central access seam.
Sparse MMIO model of the Renesas peripheral space.
void mmio_write(uc_engine *uc, uint64_t offset, unsigned size, uint64_t value, void *user)
UC_MMIO write callback for the peripheral window.
Definition emu_mmio.c:187
@ k_periph_size
0x40000000-0x4FFFFFFF: all Renesas peripherals.
Definition emu_mmio.h:48
@ k_periph_base
Peripheral window base.
Definition emu_mmio.h:47
uint64_t mmio_read(uc_engine *uc, uint64_t offset, unsigned size, void *user)
UC_MMIO read callback for the peripheral window.
Definition emu_mmio.c:129
static const ra8_mpu_region_t s_regions[]
One-region RO descriptor covering s_ro_buffer.
Definition main.c:155
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
One guest window that resolves onto a shared host aperture.
Definition emu_memmap.c:196
size_t backing
Aperture the window resolves onto.
Definition emu_memmap.c:198
uint64_t base
Guest base address of this window.
Definition emu_memmap.c:197
uint64_t offset
Byte offset of the window in the aperture.
Definition emu_memmap.c:199
One owned host aperture mapping.
Definition emu_memmap.h:77
uint8_t * host
Page-aligned host mapping, or nullptr.
Definition emu_memmap.h:78
uint64_t size
Exact logical byte length.
Definition emu_memmap.h:79
One caller-owned association between a Unicorn engine and backing.
Definition emu_memmap.h:83
bool active
Binding occupies this slot and must be undone.
Definition emu_memmap.h:85
uc_engine * uc
Bound Unicorn engine.
Definition emu_memmap.h:84
Exact requirements and operation outcome.
Definition emu_memmap.h:70
emu_memmap_binding_t bindings[k_emu_memmap_binding_count]
Active Unicorn engine views.
Definition emu_memmap.h:93
bool open
Whether the host mappings are owned.
Definition emu_memmap.h:95
emu_memmap_backing_t backings[k_emu_memmap_backing_count]
Owned host aperture mappings.
Definition emu_memmap.h:91
One emulated memory-region table row.
Definition emu_memmap.h:29
const char * name
Human-readable region name.
Definition emu_memmap.h:30
uint64_t size
Region byte length.
Definition emu_memmap.h:32
uint64_t base
Guest base address.
Definition emu_memmap.h:31