/* SPDX-License-Identifier: LicenseRef-Starship-1.0 * Copyright (c) 2023-2026 Robert A. James */ /* fakes.c -- see fakes.h. */ #include "fakes.h" #include #include /* ---- the console ---- */ #define FAKE_LINES 256 #define FAKE_LINE 256 static char lines[FAKE_LINES][FAKE_LINE]; static unsigned n_lines; void fake_console_reset(void) { n_lines = 0; } unsigned fake_console_lines(void) { return n_lines; } const char *fake_console_line(unsigned i) { return i < n_lines ? lines[i] : ""; } int fake_console_said(const char *text) { unsigned i; for (i = 0; i < n_lines; i++) if (strstr(lines[i], text)) return 1; return 0; } static void take(const char *s) { if (n_lines < FAKE_LINES) { strncpy(lines[n_lines], s, FAKE_LINE - 1); lines[n_lines][FAKE_LINE - 1] = '\0'; n_lines++; } } void console_println(const char *s) { take(s); } void console_puts(const char *s) { take(s); } void console_putc(char c) { (void)c; } /* ---- the RNG ---- */ static uint32_t rng_state = 1u; static int rng_fails; void fake_rng_reset(void) { rng_state = 1u; rng_fails = 0; } void fake_rng_fail(int fail) { rng_fails = fail; } int rng_get_bytes(uint8_t *buf, size_t n) { size_t i; if (rng_fails) return -1; for (i = 0; i < n; i++) { rng_state = rng_state * 1103515245u + 12345u; buf[i] = (uint8_t)(rng_state >> 16); } return 0; } /* ---- the disk ---- */ static int listed(const uint32_t *list, uint32_t n, uint32_t block) { uint32_t i; for (i = 0; i < n; i++) if (list[i] == block) return 1; return 0; } static int d_open(blkio_dev_t *dev, const blkio_params_t *p) { dev->state = p->opaque; return BLKIO_OK; } static int d_close(blkio_dev_t *dev) { (void)dev; return BLKIO_OK; } static int d_read(blkio_dev_t *dev, uint32_t fblock, void *dst) { fake_disk *d = (fake_disk *)dev->state; if (fblock >= d->blocks) return BLKIO_EINVAL; if (listed(d->fail_read, d->n_fail_read, fblock)) return BLKIO_EIO; memcpy(dst, d->bytes + (size_t)fblock * BLKIO_FORTH_BLOCK_SIZE, BLKIO_FORTH_BLOCK_SIZE); return BLKIO_OK; } static int d_write(blkio_dev_t *dev, uint32_t fblock, const void *src) { fake_disk *d = (fake_disk *)dev->state; if (fblock >= d->blocks) return BLKIO_EINVAL; if (listed(d->fail_write, d->n_fail_write, fblock)) return BLKIO_EIO; memcpy(d->bytes + (size_t)fblock * BLKIO_FORTH_BLOCK_SIZE, src, BLKIO_FORTH_BLOCK_SIZE); d->writes++; return BLKIO_OK; } static int d_flush(blkio_dev_t *dev) { fake_disk *d = (fake_disk *)dev->state; d->flushes++; return d->fail_flush ? BLKIO_EIO : BLKIO_OK; } static int d_info(blkio_dev_t *dev, blkio_info_t *out) { fake_disk *d = (fake_disk *)dev->state; memset(out, 0, sizeof *out); out->forth_block_size = BLKIO_FORTH_BLOCK_SIZE; out->total_blocks = d->blocks; out->phys_sector_size = 512u; out->phys_size_bytes = (uint64_t)d->blocks * BLKIO_FORTH_BLOCK_SIZE; return BLKIO_OK; } static const blkio_vtable_t fake_vt = { d_open, d_close, d_read, d_write, d_flush, d_info }; int fake_disk_open(blkio_dev_t *dev, fake_disk *d, uint32_t blocks) { blkio_params_t p; memset(d, 0, sizeof *d); d->bytes = (uint8_t *)calloc(blocks, BLKIO_FORTH_BLOCK_SIZE); d->blocks = blocks; if (!d->bytes) return BLKIO_EIO; memset(&p, 0, sizeof p); p.forth_block_size = BLKIO_FORTH_BLOCK_SIZE; p.total_blocks = blocks; p.opaque = d; return blkio_open(dev, &fake_vt, &p); } int fake_disk_bind(blkio_dev_t *dev, fake_disk *d) { blkio_params_t p; memset(&p, 0, sizeof p); p.forth_block_size = BLKIO_FORTH_BLOCK_SIZE; p.total_blocks = d->blocks; p.opaque = d; return blkio_open(dev, &fake_vt, &p); } void fake_disk_free(fake_disk *d) { free(d->bytes); d->bytes = 0; } void fake_disk_fail_read(fake_disk *d, uint32_t block) { if (d->n_fail_read < FAKE_DISK_MAX_FAULTS) d->fail_read[d->n_fail_read++] = block; } void fake_disk_fail_write(fake_disk *d, uint32_t block) { if (d->n_fail_write < FAKE_DISK_MAX_FAULTS) d->fail_write[d->n_fail_write++] = block; } uint8_t *fake_disk_sector(fake_disk *d, uint64_t lba) { return d->bytes + (size_t)lba * 512u; }