27#include <linux/falloc.h>
35typedef enum : uint32_t {
52 if ((fd !=
nullptr) && (*fd >= 0)) {
93 if ((out_fd ==
nullptr) || (bytes == 0U) || (bytes > (uint64_t)INT64_MAX)) {
96 char path[] =
"/tmp/ra8_emulator_sd.XXXXXX";
97 int fd = mkstemp(path);
102 if (ftruncate(fd, (off_t)bytes) != 0) {
129 uint64_t offset = 0U;
130 while (offset < bytes) {
131 const uint64_t remaining = bytes - offset;
133 (remaining < (uint64_t)
sizeof(scratch)) ? (
size_t)remaining :
sizeof(scratch);
144 offset += (uint64_t)count;
187 (offset > (uint64_t)INT64_MAX)) {
190 return (uint64_t)count <= (
g_board_sd.image_len - offset);
232 while (done < count) {
233 const uint64_t remaining = count - done;
234 const size_t chunk = (remaining < (uint64_t)
sizeof(zeros)) ? (
size_t)remaining :
sizeof(zeros);
238 done += (uint64_t)chunk;
246 (count > (
g_board_sd.image_len - offset)) || (offset > (uint64_t)INT64_MAX) ||
247 (count > (uint64_t)INT64_MAX)) {
255 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
257 (off_t)count) == 0) {
260 if ((errno != EOPNOTSUPP) && (errno != ENOSYS) && (errno != EINVAL)) {
269 if (path ==
nullptr) {
277 if (source.
size <= 0) {
282 const uint64_t bytes = (uint64_t)source.
size;
284 const bool prepared =
289 (void)
priv_emu_io_errf(
"ra8_emulator: --sd: cannot prepare private image '%s'\n", path);
293 (void)
priv_emu_io_errf(
"ra8_emulator: SD card attached (%llu bytes) from %s\n",
321 "ra8_emulator: SD card created (%llu GiB FAT%u, %u sec/clus) sparse + attached\n",
322 (
unsigned long long)(bytes /
328 "ra8_emulator: SD card created (%llu MiB FAT%u, %u sec/clus) sparse + attached\n",
338 (void)
priv_emu_io_errf(
"ra8_emulator: --sd-new: size too small (need >= 32 KiB)\n");
341 const uint64_t bytes = (uint64_t)total_sectors * (uint64_t)
k_fmt_sec_bytes;
344 (void)
priv_emu_io_errf(
"ra8_emulator: --sd-new: cannot create %llu-byte sparse image\n",
345 (
unsigned long long)bytes);
349 const bool formatted = (fat_bits == (uint8_t)
k_fat32_bits)
354 (void)
priv_emu_io_errf(
"ra8_emulator: --sd-new: FAT format write failed\n");
373 "ra8_emulator: --save-sd: card is %llu MiB (> %u MiB cap) -- skipped\n",
380 (void)
priv_emu_io_errf(
"ra8_emulator: --save-sd: cannot write '%s'\n", path);
388 (void)
priv_emu_io_errf(
"ra8_emulator: SD card image saved (%llu bytes) to %s\n",
394void board_sd_info(
bool* attached, uint64_t* bytes, uint8_t* fat_bits,
const char** label)
396 if (attached !=
nullptr) {
399 if (bytes !=
nullptr) {
402 if (fat_bits !=
nullptr) {
405 if (label !=
nullptr) {
SD-card-over-SPI device model for ra8_emulator (attached to SPI_B).
bool priv_board_sd_storage_write(uint64_t offset, const void *src, size_t count)
Write exactly to the current sparse backend at a checked byte offset.
bool priv_board_sd_storage_zero(uint64_t offset, uint64_t count)
Make a checked byte range read as zero while preserving sparse storage.
static RA8_INTERNAL void internal_close_fd(int *fd)
Close a descriptor when owned and invalidate the caller's slot.
static RA8_INTERNAL void internal_adopt_image(int image_fd, uint64_t bytes)
Replace the active card with a prepared working file.
static RA8_INTERNAL void internal_release_image(void)
Release the currently attached anonymous working file.
bool board_sd_save(const char *path)
Transactionally publish the current SD-card image to a file.
bool board_sd_attached(void)
Report whether an SD-card image is currently attached.
static RA8_INTERNAL bool internal_copy_bytes(int source_fd, int target_fd, uint64_t bytes)
Copy a descriptor range with one fixed scratch buffer.
bool board_sd_attach(const char *path)
Attach an SD-card image from a host file.
bool priv_board_sd_storage_read(uint64_t offset, void *dst, size_t count)
Read exactly from the current sparse backend at a checked byte offset.
bool board_sd_attach_blank(uint32_t total_sectors, uint8_t fat_bits, const char *label)
Create a blank, FAT-formatted sparse SD card and attach it.
static RA8_INTERNAL bool internal_create_sparse(uint64_t bytes, int *out_fd)
Create, unlink, and size an anonymous sparse working file.
static RA8_INTERNAL bool internal_write_zeros(uint64_t offset, uint64_t count)
Portably zero a range with bounded memory when hole punching is unavailable.
board_sd_io_const_t
Fixed transfer size for card-image copies and portable zeroing.
@ k_sd_io_chunk
Bounded stack scratch; independent of card size.
void board_sd_info(bool *attached, uint64_t *bytes, uint8_t *fat_bits, const char **label)
Read back the attached card's summary (for the status view / report).
static RA8_INTERNAL bool internal_range_valid(uint64_t offset, size_t count)
Validate a positioned operation against descriptor and card bounds.
static RA8_INTERNAL void internal_report_created(uint64_t bytes, uint8_t fat_bits, uint32_t spc)
Emit the stable blank-card geometry diagnostic.
Module-private FAT formatter shared by the board_periph_sd TUs.
board_sd_state_t g_board_sd
The single modelled SD card (defined in board_periph_sd.c).
@ k_fat32_bits
FAT32 selector / label width.
@ k_fat16_bits
FAT16 selector.
@ k_sd_min_sectors
–sd-new floor: 32 KiB of sectors.
@ k_sd_save_max_bytes
–save-sd cap: 2 GiB.
@ k_unit_kib
Binary kilo multiplier (KiB).
@ k_fmt_sec_bytes
Bytes per sector.
bool priv_board_sd_format_fat16(int image_fd, uint32_t total_sectors, const char *label, uint32_t *out_spc)
Format the attached sparse backend as a FAT16 volume.
void priv_board_sd_label_field(uint8_t *dst, const char *label)
Copy a volume label into an 11-char space-padded 8.3 field.
bool priv_board_sd_format_fat32(int image_fd, uint32_t total_sectors, const char *label, uint32_t *out_spc)
Format the attached sparse backend as a FAT32 volume.
Bounded raw-descriptor I/O seam for the RA8 emulator.
@ k_emu_io_ok
The complete operation succeeded.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
emu_io_result_t priv_emu_io_pread_exact(int fd, void *buf, size_t count, off_t offset)
Read exactly count bytes at offset without changing the cursor.
emu_io_result_t priv_emu_io_pwrite_exact(int fd, const void *buf, size_t count, off_t offset)
Write exactly count bytes at offset without changing the cursor.
void priv_emu_io_txn_abort(emu_io_txn_t *txn)
Close and unlink an active sibling transaction without publication.
emu_io_result_t priv_emu_io_txn_commit(emu_io_txn_t *txn)
Sync, close, and atomically rename an active sibling transaction.
emu_io_result_t priv_emu_io_close(emu_io_file_t *file)
Close and invalidate an owned raw file descriptor.
emu_io_result_t priv_emu_io_txn_begin(const char *path, emu_io_txn_t *txn)
Create a sibling temporary output for failure-atomic publication.
emu_io_result_t priv_emu_io_open_read(const char *path, emu_io_file_t *file)
Open and stat a regular file for bounded raw reading.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_fmt_label_len
Volume-label field width (bytes).
The modelled card: backing image + command/response framing.
Raw descriptor plus its stat-derived byte length.
int64_t size
Non-negative regular-file length.
int fd
Owned descriptor, or -1 when closed.
Complete, caller-visible result of a raw host-I/O operation.
emu_io_status_t status
Semantic completion status.
Sibling temporary file used for failure-atomic publication.
int fd
Owned temporary descriptor, or -1 when inactive.