Sixty-five headers sat side by side in include/, so `#include "irq.h"` said nothing about where irq.h was or what it belonged to, and errno.h, stat.h and fcntl.h at the top shadowed the system's for any host tool built with -I./include. They are in folders now -- arch/ core/ fs/ dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and every include names the folder, as Linux's do: "core/proc.h". Done mechanically and checked the hard way: the kernel built from this tree disassembles identically to the one built from the tree before it. The full image boots, and userland is the same set of programs. Paths in docs and comments follow; docs/guides/layout.md has a table of what is where, and tools/fix-includes.py rewrites old-style includes from the folders in the tree, for code written before this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
92 lines
2.8 KiB
C
92 lines
2.8 KiB
C
// Memory-backed block device.
|
|
//
|
|
// Serves an entire SCHFS image out of RAM, so the system can boot and run a
|
|
// shell with the physical disk untouched. That is what makes destructive work
|
|
// on the real disk survivable: reformatting, running mkfs, or bringing up a new
|
|
// on-disk format cannot take away the root you are running from. It is also the
|
|
// first piece of the installer -- an install environment is exactly "a root in
|
|
// RAM plus a disk you are allowed to destroy".
|
|
//
|
|
// The image is linked into the kernel as a binary blob (see the ramdisk_obj
|
|
// rule in the Makefile) and is served in place: the blob lives in writable
|
|
// kernel memory, so writes to the ramdisk simply modify it. They are lost on
|
|
// reboot, which is the expected behaviour for this kind of root.
|
|
//
|
|
// Enabled by building with RAMROOT=1. Without it this file still compiles, the
|
|
// device reports zero size, and the kernel boots from the IDE disk as before.
|
|
|
|
#include "core/types.h"
|
|
#include "core/defs.h"
|
|
#include "core/param.h"
|
|
#include "arch/memlayout.h"
|
|
#include "arch/mmu.h"
|
|
#include "core/spinlock.h"
|
|
#include "core/sleeplock.h"
|
|
#include "fs/fs.h"
|
|
#include "fs/buf.h"
|
|
|
|
#ifdef RAMDISK_ROOT
|
|
// Supplied by `ld -r -b binary` over build/fs-ram.img, renamed by objcopy.
|
|
extern uchar _binary_ramdisk_start[];
|
|
extern uchar _binary_ramdisk_size[];
|
|
#endif
|
|
|
|
static uchar *rd_base;
|
|
static uint64 rd_size; // bytes
|
|
static uint rd_blocks; // rd_size / BSIZE
|
|
|
|
void
|
|
ramdiskinit(void)
|
|
{
|
|
#ifdef RAMDISK_ROOT
|
|
rd_base = _binary_ramdisk_start;
|
|
rd_size = (uint64)_binary_ramdisk_size;
|
|
rd_blocks = (uint)(rd_size / BSIZE);
|
|
|
|
if(rd_blocks == 0)
|
|
panic("ramdiskinit: embedded image is empty");
|
|
|
|
// A truncated image is worth catching here rather than as a confusing
|
|
// "invalid file system" panic later: the superblock lives in block 1.
|
|
if(rd_blocks < 2)
|
|
panic("ramdiskinit: embedded image smaller than a superblock");
|
|
|
|
cprintf("ramdisk: %u blocks (%u KB) at %p\n",
|
|
rd_blocks, (uint)(rd_size / 1024), rd_base);
|
|
#else
|
|
rd_base = 0;
|
|
rd_size = 0;
|
|
rd_blocks = 0;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
ramdisk_present(void)
|
|
{
|
|
return rd_blocks != 0;
|
|
}
|
|
|
|
// Sync buf with the in-memory image. Mirrors iderw()'s contract: on a read,
|
|
// fill b->data and set B_VALID; on a write, copy out and clear B_DIRTY.
|
|
void
|
|
ramdiskrw(struct buf *b)
|
|
{
|
|
if(!holdingsleep(&b->lock))
|
|
panic("ramdiskrw: buf not locked");
|
|
if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
|
|
panic("ramdiskrw: nothing to do");
|
|
if(rd_base == 0)
|
|
panic("ramdiskrw: no ramdisk");
|
|
if(b->blockno >= rd_blocks)
|
|
panic("ramdiskrw: block out of range");
|
|
|
|
uchar *p = rd_base + (uint64)b->blockno * BSIZE;
|
|
|
|
if(b->flags & B_DIRTY){
|
|
memmove(p, b->data, BSIZE);
|
|
b->flags &= ~B_DIRTY;
|
|
} else {
|
|
memmove(b->data, p, BSIZE);
|
|
}
|
|
b->flags |= B_VALID;
|
|
}
|