Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add design doc for hard drive #7

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions docs/architecture/_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ creation-date: "yyyy-mm-dd"
authors: [ "@username" ]
coach: "@username"
approvers: [ "@product-manager", "@engineering-manager" ]
owning-stage: "~devops::<stage>"
participating-stages: []
---

<!--
Expand Down
3 changes: 0 additions & 3 deletions docs/architecture/example/index.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/architecture/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ These documents propose how the system should work, and after they are implement
:maxdepth: 2
:caption: Contents:

example/index.md
piix3/index
65 changes: 65 additions & 0 deletions docs/architecture/piix3/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
status: proposed
creation-date: "2024-02-27"
authors: [ "@stephengrice" ]
coach: "n/a"
approvers: [ "@jonstrong", "@tonyprogrammer" ]
---

# IDE Hard Drive Driver

## Summary

In order to store persistent data, we need a hard drive driver. The QEMU i386 system contains a PIIX3 hard drive, so we'll start by writing some code to interface with it directly. Once this driver is available, we can use it for higher level abstractions such as filesystems. Also, we can use what we learn from this to add support for other hard drive models.

## Motivation

We need to store persistent data or else this is really boring and useless.

### Goals

- Be able to write a string to the QEMU-provided hard drive
- Be able to read the string back from the hard drive (even after shutdown if same drive is attached)

### Non-Goals

Out of scope:

- Filesystem development
- Any other device except for the PIIX3 that comes with `qemu-system-i386`

## Proposal

Hard-code the exact messages that need to be sent to the IDE controller. Then, generalize them into a driver that will work with more devices and in more modes.

## Design and implementation details

### Detecting IDE Devices

(class code, blah)

### Detecting Mode

(compatibility vs native mode)

### Command Ports for Compatibility Mode

When in compatibility mode, `0x1F0` is the start address for the master IDE controller [^1].

Offset 0 from the start address is the command I/O port [^2].

Therefore, in compatibility mode, `IDE_MASTER_COMMAND` port is `0x1F0`.

The status port is at offset `0x2` [^2]. Therefore, `IDE_MASTER_STATUS` is `0x1F2` in compatibility mode.

### Sending Commands

TODO

## Alternative Solutions

Cry.


[^1]: <https://wiki.osdev.org/IDE>
[^2]: [PIIX3 Technical Manual](https://pdf.datasheetcatalog.com/datasheet/Intel/mXvqwzr.pdf). See page 30 for I/O ports.
74 changes: 74 additions & 0 deletions docs/architecture/piix3/notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# PIIX Notes / Research

## IDE Driver Tutorial - OSDev Forums

<https://forum.osdev.org/viewtopic.php?f=1&t=21151>
- BAR (Base Address Register)
- PCI devices have 6 BARs
- IDE devices use only 5 BARs
- Parallel IDE has preset BARs: `0x1F0, 0x3F4, 0x170, 0x374, 0x000`
- Serial: You must figure it out


## Wikipedia

<https://en.wikipedia.org/wiki/PIIX>
- PIIX: PCI IDE ISA Xcelerator
- aka: Intel 82371
- IDE = PATA
- Contains
- 2 DMA (direct memory access) controllers
- 1 PIT (programmable interval timer)
- 2 PICs (programmable interrupt chip)
- PCI-to-ISA bus bridge
- PIIX3: adds USB 1.0, I/O APIC

## Technical Specification

<https://pdf.datasheetcatalog.com/datasheet/Intel/mXvqwzr.pdf>
- Page 30 / Table 6: I/O registers
- Offset from base address

## IDE on OSDev Wiki

<https://wiki.osdev.org/IDE>
- IDE controller: Class Code = 1, Subclass Code = 1
- ProgIf: determine mode
- Bit 0-1: primary channel
- Bit 2-3: secondary channel
- Bit 7: Master (DMA enabled)
- Compatibility mode: pre-set ports
- 0x1F0 to 0x1F7
- 0x3F6
- IRQ14
- Native mode: read the BAR to figure out I/O addresses / IRQs

## I/O Ports on OSDev Wiki

- <https://wiki.osdev.org/I/O_Ports>
- 0x1F0: Primary ATA controller (IDE)

## ATA Driver - RTEMS

<https://docs.rtems.org/branches/master/bsp-howto/ata.html>

## ATA Driver - OSDev

<https://github.com/levex/osdev/blob/master/drivers/ata.c>

- Note: `ATA_PRIMARY_IO` matches addr for master IDE controller in compat mode
- `ide_identify` function
- Sets a bunch of register values up
- Sends an IDENTIFY command
- Reads status
- If status is 0, done
- Waits until "busy" bit is not set
- Reads status again
- Checks error bit
- Waits for something?
- Reads 256 words into memory at `ide_buf` - could this be the IDE Descriptor Table?

## Paul

- PIO = Slow but easy
- DMA = Performance
83 changes: 83 additions & 0 deletions src/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,75 @@ void lspci() {
}
}


#define IDE_MASTER_COMMAND 0x1F0
#define IDE_MASTER_STATUS 0x1F2

// Source: https://forum.osdev.org/viewtopic.php?f=1&t=21151
// State (ready?)
#define ATA_SR_BSY 0x80
#define ATA_SR_DRDY 0x40
#define ATA_SR_DF 0x20
#define ATA_SR_DSC 0x10
#define ATA_SR_DRQ 0x08
#define ATA_SR_CORR 0x04
#define ATA_SR_IDX 0x02
#define ATA_SR_ERR 0x01
// Error states
#define ATA_ER_BBK 0x80
#define ATA_ER_UNC 0x40
#define ATA_ER_MC 0x20
#define ATA_ER_IDNF 0x10
#define ATA_ER_MCR 0x08
#define ATA_ER_ABRT 0x04
#define ATA_ER_TK0NF 0x02
#define ATA_ER_AMNF 0x01
// Commands
#define ATA_CMD_READ_PIO 0x20
#define ATA_CMD_READ_PIO_EXT 0x24
#define ATA_CMD_READ_DMA 0xC8
#define ATA_CMD_READ_DMA_EXT 0x25
#define ATA_CMD_WRITE_PIO 0x30
#define ATA_CMD_WRITE_PIO_EXT 0x34
#define ATA_CMD_WRITE_DMA 0xCA
#define ATA_CMD_WRITE_DMA_EXT 0x35
#define ATA_CMD_CACHE_FLUSH 0xE7
#define ATA_CMD_CACHE_FLUSH_EXT 0xEA
#define ATA_CMD_PACKET 0xA0
#define ATA_CMD_IDENTIFY_PACKET 0xA1
#define ATA_CMD_IDENTIFY 0xEC
// Reading the identification space
#define ATA_IDENT_DEVICETYPE 0
#define ATA_IDENT_CYLINDERS 2
#define ATA_IDENT_HEADS 6
#define ATA_IDENT_SECTORS 12
#define ATA_IDENT_SERIAL 20
#define ATA_IDENT_MODEL 54
#define ATA_IDENT_CAPABILITIES 98
#define ATA_IDENT_FIELDVALID 106
#define ATA_IDENT_MAX_LBA 120
#define ATA_IDENT_COMMANDSETS 164
#define ATA_IDENT_MAX_LBA_EXT 200
// Task file
#define ATA_REG_DATA 0x00
#define ATA_REG_ERROR 0x01
#define ATA_REG_FEATURES 0x01
#define ATA_REG_SECCOUNT0 0x02
#define ATA_REG_LBA0 0x03
#define ATA_REG_LBA1 0x04
#define ATA_REG_LBA2 0x05
#define ATA_REG_HDDEVSEL 0x06
#define ATA_REG_COMMAND 0x07
#define ATA_REG_STATUS 0x07
#define ATA_REG_SECCOUNT1 0x08
#define ATA_REG_LBA3 0x09
#define ATA_REG_LBA4 0x0A
#define ATA_REG_LBA5 0x0B
#define ATA_REG_CONTROL 0x0C
#define ATA_REG_ALTSTATUS 0x0C
#define ATA_REG_DEVADDRESS 0x0D
// End copied code

void idetest() {
struct PCI_Device ide_device = get_pci_device(0,1,1); // hard coded based on lspci output
println("Hello world");
Expand All @@ -79,4 +148,18 @@ void idetest() {
println(itoah(ide_device.status));
print("iface: 0x");
println(itoah(ide_device.prog_interface));

// Let's try reading the status
u8 status = ioport_in(IDE_MASTER_STATUS);
print("IDE Master Status: 0x");
println(itoah(status));

// Okay, now send a read DMA command just for fun
ioport_out(IDE_MASTER_COMMAND, 0xC8);

terrible_sleep_impl(1000);

status = ioport_in(IDE_MASTER_STATUS);
print("IDE Master Status: 0x");
println(itoah(status));
}
2 changes: 1 addition & 1 deletion src/screen/screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,4 @@ void print_message() {
}
print("-PKOS-");
cursor_row = 4;
}
}
2 changes: 1 addition & 1 deletion src/screen/screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#define ROWS 25
#define COLS 80
#define VIDMEM 0xB8000
#define VIDMEM 0xb8000
#define PROMPT "pkos> "
#define PROMPT_LENGTH 6

Expand Down