Give userspace a raw disk: /dev/hda and /dev/hdb
Nothing outside the kernel could touch a disk. sys_mount does not even look at the device it is handed -- it mounts the one SchFS volume found at boot and ignores `source` -- so a program had no way to read a partition table, format a volume or write a boot sector. An installer is a program that needs all three, so this is the first piece of it. A character device in devsw rather than a separate block layer, because that is where the offset already lives: fileread/filewrite pass f->off and advance it by what comes back, which is everything a seekable device needs. The minor is the IDE device number, the same numbering iderw() uses; two schemes for the same disks would be a bug waiting to happen. Writes bypass every filesystem above them, which is inherent to a raw device and why an installer must target a disk it has not mounted. The nodes are created unconditionally, like every other entry in /dev. That matters more than it looks: with no node, `echo x > /dev/hdb` silently creates an ordinary file of that name and appears to work. It did, and it agreed with itself on read-back; only the host's copy of the disk showed nothing had been written. st_rdev was never filled, so every node in /dev reported "0, 0" under ls -l. Harmless while nothing read it, wrong as soon as something has to tell two disks apart. Filled with the full Linux dev_t encoding rather than (major << 8 | minor), which only works while both stay small. Verified against the host as an independent oracle, both directions: the guest wrote to /dev/hdb and the host saw those bytes at offset 0; the host wrote at offset 4096 and the guest read them back with dd skip=. ls -l now shows 1,1 for console, 2,0 for fb0 and 8,1 for hdb. Known limit, commented in disk.c: devsw passes the offset as a 32-bit uint, so a raw disk is addressable to 4 GB. That must be widened before anyone installs onto a real disk. bootcheck 108 [ok] with -Fb -Tty -Usb -Sock -Evdev -Ps. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
b428a50145
commit
66152ad2f2
7 changed files with 148 additions and 1 deletions
|
|
@ -47,6 +47,17 @@ struct linux_stat {
|
|||
#define LINUX_S_IFREG 0100000
|
||||
#define LINUX_S_IFLNK 0120000
|
||||
|
||||
// Linux's dev_t: 12 bits of major and 8 of minor packed into the low 32, with
|
||||
// the overflow of each above that. Spelled out in full rather than as
|
||||
// (major << 8 | minor), because that is how the other side decodes it and a
|
||||
// shortcut here would only work while both numbers stayed small.
|
||||
static uint64
|
||||
linux_makedev(uint32 major, uint32 minor)
|
||||
{
|
||||
return ((uint64)(major & 0xfffu) << 8) | (uint64)(minor & 0xffu)
|
||||
| ((uint64)(major & ~0xfffu) << 32) | ((uint64)(minor & ~0xffu) << 12);
|
||||
}
|
||||
|
||||
static void
|
||||
stati_linux(struct inode *ip, struct linux_stat *st)
|
||||
{
|
||||
|
|
@ -74,6 +85,12 @@ stati_linux(struct inode *ip, struct linux_stat *st)
|
|||
}
|
||||
st->st_mode = type_bits | perm_bits;
|
||||
|
||||
// Which device this node actually is. Left at zero until now, so every
|
||||
// entry in /dev printed as "0, 0" under ls -l -- harmless while nothing
|
||||
// read it, and wrong the moment something has to tell two disks apart.
|
||||
if (ip->type == T_DEV)
|
||||
st->st_rdev = linux_makedev(ip->major, ip->minor);
|
||||
|
||||
st->st_atime = ip->atime; st->st_mtime = ip->mtime; st->st_ctime = ip->ctime;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue