# Learnings — guomi-smart-card ## Architecture - C*Core C0 architecture (NOT ARM), little endian - Bare-metal while(1) super-loop, no RTOS - eFlash 512KB @ 0x00400000, RAM 64KB @ 0x00800000 - SPI FIFO only 8 bytes — MUST use DMA for any real data transfer ## Crypto API Conventions - Gen2 `_2` APIs (byte-buffer based) preferred over Gen1 struct-based - EDMAC clock discipline: ModuleClk_On before crypto, ModuleClk_Off after - TRNG must init first before any SM2 key generation - SM2/SM4/SHA share EDMAC channel — do not nest crypto operations ## SPI/DMA Critical Details (VERIFIED via .map file) - `dma_spitran()` binten hardcoded FALSE — interrupt branch is DEAD CODE - Must use `dma_spi_LLIReceive()` for continuous async receive - LLI `next_lli` points to itself for auto-loop - **`dmac_isr()` from `dmac_drv.c` is DISCARDED by linker — NOT in binary** - **Actual IRQ4 handler = `DMA_IRQHandler` from `libCUni360S_mcc.a(mcc_bsp.o)` at 0x0041b2ac** - **MUST modify `vector_table.h` ISR24** to repoint IRQ4 to our own DMA handler - **Vector table is `void *const` in flash** — `interrupt_setup()` only sets EIC priority, NOT the vector - SPI1+SPI2+PIT32 share IRQ3 (ISR23 = PIT32_SPI1_SPI2_ISR) - DMA completion interrupt goes through IRQ4 (ISR24) - DMAC_INT_NUM = 0x24 = VecTable[36] = ISR24 - SPI1 base = 0x70000000, SPIDR offset = 0x12 (verified in spi_reg.h and dmac_drv.c) - SPI instances spaced 0x10000 apart: SPI1=0x70000000, SPI2=0x70010000, SPI3=0x70020000 ## CRC Hardware (VERIFIED) - Hardware CRC engine does NOT support configurable polynomials - CRC_CR has NO polynomial field — only mode (CRC-8/16/32), source, endianness - **CRC16-CCITT (0x1021) MUST be implemented in SOFTWARE** - CRC0_BASE_ADDR = 0x78000000, CRC1_BASE_ADDR = 0x7c000000 ## RAM Budget (VERIFIED via .map file) - .data = 2,992 bytes (0xBB0) at 0x00800000-0x00800BB0 - .bss = 6,740 bytes (0x1A54) at 0x00800BB0-0x00802604 - Total used: 9,732 bytes (14.8%) - Free heap: 47,608 bytes (0xB9F8) from 0x00802604 to 0x0080DFFC - Stack: 8,192 bytes from 0x0080DFFC to 0x0080FFFC - _bss_end = 0x00802604, _end = 0x0080DFFC, STACK_LOCATION = 0x0080FFFC ## eFlash Budget (VERIFIED via .map file) - Firmware end: 0x0041C098 (.text_entry + .rodata + .text + .data LMA) - .bin size = 114,840 bytes = 0x1C098 (matches) - Key storage 0x00470000-0x00470800 = 100% free, page-aligned (pages 896-899) - EFLASH_END per alg_drv.h = 0x0047F000 (4KB reserved at top) - 343KB gap between firmware end and key storage region ## eFlash Key Storage - EFLASH_SetWritePermission() is GLOBAL — no per-page protection - Must verify address range BEFORE enabling write, clear IMMEDIATELY after - 512 bytes per page, log-structured wear leveling across 4 pages ## Git Strategy - Remote: http://gogs.weclouds.xyz:3000/kennyh/encryption_sm.git - Branch: main - Commit + push after each task completion ## GMSP Transport Layer (Task 3+4) ¡ª Implementation Details ### DMA LLI Ping-Pong Pattern - Existing `dma_spi_LLIReceive()` creates a SELF-LOOP LLI (next points to itself) - For Ping-Pong, need TWO LLI nodes: node[0].next_lli = &node[1], node[1].next_lli = &node[0] - DMA_LLI struct has 7 fields but hardware only reads first 5 (src_addr, dst_addr, next_lli, control0, len) - Extra fields (hs_sel, per) are software metadata ¡ª NOT loaded by DMA hardware - CFG and CFG_HIGH registers persist across LLI transitions (set once, not per-node) - control0 value: `DMA_IE | SNC | DI | LLP_DST_EN | LLP_SRC_EN | P2M_DMA` = 0x18200401 ### Buffer Completion Tracking - Cannot reliably determine completed buffer from DMA_DADDR (race with ongoing transfer) - Cannot read DMA_LLP register (may not update during LLI operation) - SOLUTION: toggle counter `gmsp_currently_filling` ¡ª starts at 0 (buf_A), XOR'd in ISR after each completion - `gmsp_completed_buf = gmsp_currently_filling` captures the just-finished buffer before toggling ### ISR Variable Scope - ALL ISR-shared variables MUST be non-static if accessed from a different .c file - `gmsp_currently_filling` was initially `static volatile` ¡ú broke extern in gmsp_isr.c - Pattern: define in spi_slave.c, `extern volatile` in gmsp_isr.c ### Response Path Design - Short responses (<=8 bytes = SPI_FIFO_SIZE): SPI_SlaveSendData (CPU register loop) - Long responses (>8 bytes): dma_spitran(0, resp, dummy, len, FALSE) ¡ª blocking DMA - dma_spitran uses BOTH CH0 (TX) and CH1 (RX) ¡ª must stop LLI RX on CH1 first - After response: caller must call gmsp_transport_rearm() to restart LLI - dma_spitran disables DMAC (DMA_CONFIG=0, DMA_CHEN=0) at end ¡ª rearm must re-enable ### IRQ3/IRQ4 Vector Table Repointing - ISR23 (IRQ3): was `PIT32_SPI1_SPI2_ISR` ¡ú now `gmsp_irq3_handler` - ISR24 (IRQ4): was `DMA_IRQHandler` (from .a lib) ¡ú now `gmsp_dma_irq_handler` - Must add `extern void` declarations in vector_table.h for new handlers - Original `PIT32_SPI1_SPI2_ISR` in pit32_drv.c still exists but is no longer called - Original `DMA_IRQHandler` in libCUni360S_mcc.a still exists but vector no longer points to it ### PIT32 Interrupt Flag Clearing - PIT32 PCSR register: PCSR_PIF (0x04) = interrupt pending flag - Clear by: `PIT32->PCSR |= PIT_PIF` (write 1 to clear, same as original handler) - PIT_PIF = (1<<2) = 0x04, same as PCSR_PIF ### SPI Status Register Access - SPISR is at offset 0x16 in SPI_TypeDef, union with SPISRHW (16-bit) at same offset - Read `SPI1->SPISRHW` for full 16-bit status in IRQ3 handler - Error bits: SPISR_RXFOVF(0x0400), SPISR_RXFUDF(0x0200), SPISR_TXFOVF(0x4000), SPISR_TXFUDF(0x2000), SPISR_MODF(0x0010), SPISR_FLOST(0x0040) - In DMA mode, SPI interrupt enables should be off ¡ª IRQ3 only fires for PIT32 ### LSP Diagnostics - clangd cannot resolve Eclipse CDT include paths ¡ª ALL source files show "file not found" for type.h, memmap.h etc. - This is project-wide, NOT a code error. Same errors exist on dmac_drv.c, spi_demo.c etc. - Verification: compare new file errors against existing file errors ¡ª if same pattern, code is correct