Skip to content

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:

  1. atapi.read_block(16, buf) succeeds (LBA 16 = Primary Volume Descriptor).
  2. buf[0] == 0x01 (PVD type byte).
  3. 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