amiga-bootcamp/05_reversing/case_studies/ramdrive_device.md
Ilia Sharin 21751c0025 docs(amiga): complete AmigaOS 3.1/3.2 developer reference — 172 files across 17 sections
Comprehensive technical documentation covering:
- Hardware: OCS/ECS/AGA custom chip registers, Copper & Blitter deep dives
- Boot sequence: cold boot through startup-sequence
- Binary format: HUNK executable spec, relocation, debug info
- Linking & ABI: .fd files, LVO tables, register calling conventions
- Exec kernel: tasks, interrupts, memory, signals, semaphores
- AmigaDOS: file I/O, FFS/OFS layout, CLI/Shell scripting
- Graphics: planar bitmaps, Copper programming, HAM/EHB modes
- Intuition: screens, windows, IDCMP, BOOPSI
- Devices: trackdisk, SCSI, serial, timer, audio, keyboard
- Libraries: utility, expansion, IFFParse, locale, ARexx
- Networking: bsdsocket API, SANA-II, TCP/IP stack comparison
- Toolchain: GCC, vasm/vlink, SAS/C, NDK, debugging
- Reverse engineering: IDA/Ghidra setup, compiler fingerprints, case studies
- CPU & MMU: 68040/060 emulation libs, PMMU, cache management
- Driver development: SANA-II, Picasso96/RTG, AHI audio

All files include breadcrumb navigation. No local paths or proprietary content.
2026-04-23 12:17:35 -04:00

129 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[← Home](../../README.md) · [Reverse Engineering](../README.md)
# Case Study — ramdrive.device Structure Analysis
## Overview
`ramdrive.device` is the Amiga's built-in RAM disk device. It ships in Kickstart ROM and implements the `trackdisk.device`-compatible interface on top of allocated Chip/Fast RAM. Analysing it teaches exec device architecture, IORequest handling, and the device-as-library pattern.
---
## Locating ramdrive.device in ROM
```bash
# Find the resident tag in Kickstart ROM dump:
python3 - <<'EOF'
import struct, sys
rom = open("kick31.rom", "rb").read()
for i in range(0, len(rom)-4, 2):
tag = struct.unpack_from(">H", rom, i)[0]
if tag == 0x4AFC: # RomTag magic
rt_matchword = struct.unpack_from(">H", rom, i)[0]
rt_matchtag = struct.unpack_from(">I", rom, i+2)[0]
rt_name = struct.unpack_from(">I", rom, i+14)[0]
# print offset and map rt_name to string
print(f"RomTag @ ROM+{i:#x}")
EOF
```
The RomTag for `ramdrive.device` has `RT_TYPE=NT_DEVICE` and `RT_NAME="ramdrive.device"`.
---
## Device Structure Layout
`ramdrive.device` extends `struct Device` (which extends `struct Library`):
```c
struct RAMDriveBase {
struct Device rd_Device; /* standard device base */
/* private fields follow */
APTR rd_RAMStart; /* pointer to allocated RAM block */
ULONG rd_RAMSize; /* total size */
ULONG rd_BlockSize; /* always 512 */
ULONG rd_NumBlocks; /* RAMSize / BlockSize */
struct MinList rd_Units; /* list of open units */
};
```
---
## Standard Device Vectors (LVO)
| Offset | Vector | Description |
|---|---|---|
| 6 | `Open` | Open a unit (unit number in io_Unit) |
| 12 | `Close` | Close unit, decrement open count |
| 18 | `Expunge` | Unload if no users |
| 24 | `Reserved` | NULL |
| 30 | `BeginIO` | Queue or execute an IORequest |
| 36 | `AbortIO` | Cancel pending IORequest |
`BeginIO` is the heart of any device driver — it dispatches on `io_Command`.
---
## IORequest Command Handling
```c
void BeginIO(struct IORequest *ior) {
struct IOStdReq *io = (struct IOStdReq *)ior;
switch (io->io_Command) {
case CMD_READ: rd_Read(io); break;
case CMD_WRITE: rd_Write(io); break;
case CMD_CLEAR: rd_Clear(io); break;
case TD_FORMAT: rd_Format(io); break;
case TD_GETGEOMETRY: rd_Geometry(io); break;
default:
io->io_Error = IOERR_NOCMD;
ReplyMsg(&io->io_Message);
}
}
```
### `CMD_READ` Implementation
```c
void rd_Read(struct IOStdReq *io) {
UBYTE *src = rdbase->rd_RAMStart + io->io_Offset;
CopyMem(src, io->io_Data, io->io_Length);
io->io_Actual = io->io_Length;
io->io_Error = 0;
ReplyMsg(&io->io_Message);
}
```
---
## Memory Allocation Strategy
On initialisation, `ramdrive.device` uses `AllocMem`:
```c
rdbase->rd_RAMStart = AllocMem(rdbase->rd_RAMSize,
MEMF_PUBLIC | MEMF_CLEAR);
```
Later requests can pass `MEMF_CHIP` to force chip RAM allocation (useful for audio/graphics DMA sources).
---
## Disassembly Landmarks in IDA
After loading Kickstart ROM in IDA with M68k + HUNK/ROM loader:
1. Search for string `"ramdrive.device"` → find RomTag
2. `RT_INIT` pointer → initialization function
3. `RT_INIT` calls `MakeLibrary` then `AddDevice`
4. The device base is stored — follow to find `BeginIO` function
5. `BeginIO` switch table → individual command handlers
---
## References
- NDK39: `exec/devices.h`, `exec/io.h`, `devices/trackdisk.h`
- `06_exec_os/io_requests.md` — IORequest structure and dispatch
- `10_devices/trackdisk_device.md` — TD_* command codes
- Kickstart 3.1 ROM dump (required for disassembly)