This repository has been archived by the owner on Nov 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ata.c
86 lines (68 loc) · 2.06 KB
/
ata.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include "bootloader.h"
/* TODO: Add support for drives other than the master on the primary bus. */
static const int ata_io_base = 0x1F0;
static const int ata_control_base = 0x3F6;
static uint16_t ata_identify_data[256];
static void ata_delay()
{
for (int i = 0; i < 15; i++)
inb(ata_io_base + 7);
}
static void ata_poll()
{
/* Wait for either ERR, DF, or DRQ */
uint8_t status;
while (true) {
status = inb(ata_io_base + 7);
if (!(status & 0x80) && (status & 0x29)) break;
}
if (status & 0x21) {
boot_error("Boot device I/O error");
}
}
void ata_init()
{
/* Check for floating bus. */
if (inb(ata_io_base + 7) == 0xFF) goto fail;
/* Select the master drive. */
outb(ata_io_base + 6, 0xA0);
ata_delay();
outb(ata_io_base + 2, 0);
outb(ata_io_base + 3, 0);
outb(ata_io_base + 4, 0);
outb(ata_io_base + 5, 0);
/* Issue IDENTIFY DEVICE command. */
outb(ata_io_base + 7, 0xEC);
if (inb(ata_io_base + 7) == 0) goto fail;
/* Wait for BSY to clear. */
while (inb(ata_io_base + 7) & 0x80) {}
if (inb(ata_io_base + 4) || inb(ata_io_base + 5)) goto fail;
ata_poll();
for (int i = 0; i < 256; i++) {
ata_identify_data[i] = inw(ata_io_base);
}
screen_println("Found hard drive");
outb(ata_control_base, 0);
return;
fail:
boot_error("Boot device not found");
return;
}
void ata_read_sector(uint32_t lba, void *buffer)
{
/* Select drive, LBA bit on */
outb(ata_io_base + 6, 0xE0 | ((lba >> 24) & 0x0F));
ata_delay();
outb(ata_io_base + 2, 1); /* sector count */
outb(ata_io_base + 3, lba & 0xFF); /* LBAlo */
outb(ata_io_base + 4, (lba >> 8) & 0xFF); /* LBAmid */
outb(ata_io_base + 5, (lba >> 16) & 0xFF); /* LBAhi */
outb(ata_io_base + 7, 0x20); /* READ SECTORS command */
ata_poll();
for (int i = 0; i < 256; i++) {
uint16_t word = inw(ata_io_base);
((unsigned char *)buffer)[i * 2] = word & 0xFF;
((unsigned char *)buffer)[i * 2 + 1] = (word >> 8) & 0xFF;
}
ata_delay();
}