ISO9660
ISO9660 is the read-only CD-ROM filesystem, mounted at /mnt/iso. It is available only when a CD image is attached (QEMU -cdrom). The driver is probed at boot; if no disc is detected, /mnt/iso is not added to the mount table.
All paths under /mnt/iso/ are dispatched to this driver by the VFS. Write operations on ISO9660 paths return InvalidInput immediately — the filesystem is strictly read-only.
Hardware: ATAPI PIO (fs/iso9660/block.rs)
Atapi reads 2048-byte ISO9660 blocks from the secondary IDE master (0x170) using PIO mode (no DMA).
I/O Ports
| Offset | Register |
|---|---|
0x170 |
Data (16-bit) |
0x171 |
Features / Error |
0x174 |
Byte Count Low |
0x175 |
Byte Count High |
0x176 |
Drive/Head Select |
0x177 |
Command / Status |
0x376 |
Alt Status (4× reads = ~400 ns I/O delay) |
read_block(lba, buf) Sequence
1. port 0x176 ← 0xA0 Select secondary master
4× read 0x376 ~400 ns I/O delay
2. port 0x171 ← 0x00 PIO mode (no DMA)
port 0x174 ← 0x00 Transfer size = 2048 = 0x0800
port 0x175 ← 0x08
port 0x177 ← 0xA0 ATA PACKET command
3. wait_drq(): spin on status until BSY=0 and (DRQ=1 or ERR=1)
4. Write 12-byte READ(10) SCSI/ATAPI command as 6 × u16 to port 0x170:
[0x0028] opcode READ(10), flags=0
[LBA bits 31:16] big-endian halves of the 32-bit LBA
[LBA bits 15:0]
[0x0000]
[0x0001] transfer count = 1 block
[0x0000]
5. wait_drq() again
6. Read 1024 × u16 from port 0x170 → 2048 bytes into buf
7. wait_not_busy(): spin until BSY=0
Returns false if the device is absent, times out, or signals an error. write_sector is not implemented (no-op).
Probing (Iso9660::probe)
Iso9660::probe() returns Some(Iso9660) if:
atapi.read_block(16, buf)succeeds (LBA 16 = Primary Volume Descriptor).buf[0] == 0x01(PVD type byte).buf[1..6] == b"CD001"(ISO9660 magic).
On success, the root directory location is extracted from the PVD:
| PVD offset | Description |
|---|---|
| 158–161 | Root directory LBA (little-endian u32) |
| 166–169 | Root directory size in bytes (little-endian u32) |
These are stored as root_lba and root_size on the Iso9660 struct.
Directory Records
ISO9660 directory records have a variable-length structure packed directly into 2048-byte blocks:
| Offset | Size | Field |
|---|---|---|
| 0 | 1 | Record length (rec_len) |
| 2–5 | 4 | File LBA (little-endian) |
| 10–13 | 4 | File size in bytes (little-endian) |
| 25 | 1 | Flags (bit 1 = directory) |
| 32 | 1 | File name length |
| 33 | N | File name bytes |
Records shorter than 33 bytes or with rec_len == 0 (padding) indicate the end of usable data in a block.
Special Entries
| Name byte | Meaning |
|---|---|
0x00 |
. (current directory) — skipped |
0x01 |
.. (parent directory) — skipped |
Version Suffix Stripping
ISO9660 file names on disc include a version suffix (e.g. FILE.TXT;1). strip_version removes everything from the last ; onward before returning names to callers.
Case Folding
All returned names are lowercased (to_lower). Name matching via names_match is case-insensitive: both sides are uppercased before comparison.
IsoEntry
pub struct IsoEntry {
pub name: [u8; 32],
pub name_len: u8,
pub is_dir: bool,
pub lba: u32,
pub size: u32,
}
Returned by list_dir, find, and resolve. The name is lowercased, version-stripped, truncated to 32 bytes.
Operations
List Directory (list_dir)
Iterates blocks starting at lba, covering size bytes total. For each valid record: extracts name, LBA, size, and is_dir; copies to out[count]. Skips . and ... Stops at 64 entries or when size bytes are exhausted.
Find Entry (find)
Same block iteration as list_dir but performs names_match(stripped_name, query) on every record, returning the first match.
Path Resolution (resolve)
resolve(path) splits the path on / and calls find for each component, threading cur_lba/cur_size forward into each subdirectory. Returns None if any component is missing or if a non-final component is not a directory.
An empty path returns a synthetic IsoEntry for the root (root_lba, root_size).
Read File (read_file)
Reads blocks sequentially from entry.lba, copying BLOCK_SIZE (2048) bytes per block until entry.size bytes or the caller's buffer is filled. No cluster chain — ISO9660 files are stored in contiguous extents.
Syscall Integration
| Syscall | ISO9660 support |
|---|---|
0x20 read file |
Yes — dispatched when path resolves under /mnt/iso |
0x21 write file |
No — ISO9660 paths return InvalidInput |
0x22 rename |
No |
0x23 delete |
No |
0x27 mkdir |
No |
0x28 list dir (by cluster) |
No — uses FAT12 cluster numbers |
0x2D list dir (by path) |
Yes |
0x2E chdir |
Yes — validates directory exists, sets path_cluster = 0 |
Limits
| Resource | Value |
|---|---|
| Block size | 2048 bytes |
| IDE base address | 0x170 (secondary channel, hardcoded) |
Max entries per list_dir call |
64 |
| Max name length | 32 bytes (truncated) |
| Max path depth | Unlimited (iterative, not recursive) |
| Write support | None |