From 7e326b5039bff4d422f66bb8e51267f785193985 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Wed, 6 Oct 2021 22:15:02 +0200 Subject: kernel/i386: implement part of ATA IDENTIFY --- src/kernel/arch/i386/ata.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/kernel/arch/i386/ata.c (limited to 'src/kernel/arch/i386/ata.c') diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c new file mode 100644 index 0000000..996fa3a --- /dev/null +++ b/src/kernel/arch/i386/ata.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#include + +enum { + LBAlo = 3, + LBAmid = 4, + LBAhi = 5, + DRV = 6, + CMD = 7, + STATUS = 7, +}; // offsets + +// get I/O port base for drive +static uint16_t ata_iobase(int drive) { + bool secondary = drive&2; + return secondary ? 0x170 : 0x1F0; +} + +static void ata_driveselect(int drive, int block) { + uint8_t v = 0xE0; + if (drive&1) // slave? + v |= 0x10; // set drive number bit + // TODO account for block + port_outb(ata_iobase(drive) + DRV, v); +} + +static bool ata_identify(int drive) { + uint16_t iobase = ata_iobase(drive); + uint8_t v; + + ata_driveselect(drive, 0); + for (int i = 2; i < 6; i++) + port_outb(iobase + i, 0); + port_outb(iobase + CMD, 0xEC); // IDENTIFY + + v = port_inb(iobase + STATUS); + if (v == 0) return false; // nonexistent drive + while (port_inb(iobase + STATUS) & 0x80); + + /* check for uncomformant devices, quit early */ + if (port_inb(iobase + LBAmid) || port_inb(iobase + LBAhi)) { + // TODO atapi + return true; + } + /* pool until bit 3 (DRQ) or 0 (ERR) is set */ + while (!((v = port_inb(iobase + STATUS) & 0x9))); + if (v & 1) return false; /* ERR was set, bail */ + + // now I can read 512 bytes of data, TODO + return true; +} + +void ata_init(void) { + tty_const("\n"); + for (int i = 0; i < 4; i++) { + tty_const("probing drive "); + _tty_var(i); + if (ata_identify(i)) + tty_const(" - exists"); + tty_const("\n"); + } +} -- cgit v1.2.3 From fbf6183ef8c9d49a14bd3ff01f378d67eaebc300 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Oct 2021 06:25:02 +0000 Subject: kernel/i386: rename the port io functions with their bit length --- src/kernel/arch/i386/ata.c | 14 +++++++------- src/kernel/arch/i386/port_io.h | 4 ++-- src/kernel/arch/i386/tty/serial.c | 28 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src/kernel/arch/i386/ata.c') diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index 996fa3a..aaf05ff 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -24,7 +24,7 @@ static void ata_driveselect(int drive, int block) { if (drive&1) // slave? v |= 0x10; // set drive number bit // TODO account for block - port_outb(ata_iobase(drive) + DRV, v); + port_out8(ata_iobase(drive) + DRV, v); } static bool ata_identify(int drive) { @@ -33,20 +33,20 @@ static bool ata_identify(int drive) { ata_driveselect(drive, 0); for (int i = 2; i < 6; i++) - port_outb(iobase + i, 0); - port_outb(iobase + CMD, 0xEC); // IDENTIFY + port_out8(iobase + i, 0); + port_out8(iobase + CMD, 0xEC); // IDENTIFY - v = port_inb(iobase + STATUS); + v = port_in8(iobase + STATUS); if (v == 0) return false; // nonexistent drive - while (port_inb(iobase + STATUS) & 0x80); + while (port_in8(iobase + STATUS) & 0x80); /* check for uncomformant devices, quit early */ - if (port_inb(iobase + LBAmid) || port_inb(iobase + LBAhi)) { + if (port_in8(iobase + LBAmid) || port_in8(iobase + LBAhi)) { // TODO atapi return true; } /* pool until bit 3 (DRQ) or 0 (ERR) is set */ - while (!((v = port_inb(iobase + STATUS) & 0x9))); + while (!((v = port_in8(iobase + STATUS) & 0x9))); if (v & 1) return false; /* ERR was set, bail */ // now I can read 512 bytes of data, TODO diff --git a/src/kernel/arch/i386/port_io.h b/src/kernel/arch/i386/port_io.h index a4d640f..bcf2358 100644 --- a/src/kernel/arch/i386/port_io.h +++ b/src/kernel/arch/i386/port_io.h @@ -1,10 +1,10 @@ #include -static inline void port_outb(uint16_t port, uint8_t val) { +static inline void port_out8(uint16_t port, uint8_t val) { asm volatile("outb %0, %1" : : "a" (val), "Nd" (port)); } -static inline uint8_t port_inb(uint16_t port) { +static inline uint8_t port_in8(uint16_t port) { uint8_t val; asm volatile("inb %1, %0" : "=a" (val) : "Nd" (port)); return val; diff --git a/src/kernel/arch/i386/tty/serial.c b/src/kernel/arch/i386/tty/serial.c index 2b89ecf..f9bb252 100644 --- a/src/kernel/arch/i386/tty/serial.c +++ b/src/kernel/arch/i386/tty/serial.c @@ -7,37 +7,37 @@ static const int COM1 = 0x3f8; static void serial_selftest(void) { char b = 0x69; - port_outb(COM1 + 4, 0b00011110); // enable loopback mode - port_outb(COM1, b); - assert(port_inb(COM1) == b); + port_out8(COM1 + 4, 0b00011110); // enable loopback mode + port_out8(COM1, b); + assert(port_in8(COM1) == b); } void serial_init(void) { // see https://www.sci.muni.cz/docs/pc/serport.txt - port_outb(COM1 + 1, 0x00); // disable interrupts, we won't be using them + port_out8(COM1 + 1, 0x00); // disable interrupts, we won't be using them // set baud rate divisor - port_outb(COM1 + 3, 0b10000000); // enable DLAB - port_outb(COM1 + 0, 0x01); // divisor = 1 (low byte) - port_outb(COM1 + 1, 0x00); // (high byte) + port_out8(COM1 + 3, 0b10000000); // enable DLAB + port_out8(COM1 + 0, 0x01); // divisor = 1 (low byte) + port_out8(COM1 + 1, 0x00); // (high byte) - port_outb(COM1 + 3, 0b00000011); // 8 bits, no parity, one stop bit - port_outb(COM1 + 2, 0b11000111); // enable FIFO with 14-bit trigger level (???) + port_out8(COM1 + 3, 0b00000011); // 8 bits, no parity, one stop bit + port_out8(COM1 + 2, 0b11000111); // enable FIFO with 14-bit trigger level (???) serial_selftest(); - port_outb(COM1 + 4, 0b00001111); // enable everything in the MCR + port_out8(COM1 + 4, 0b00001111); // enable everything in the MCR } static void serial_putchar(char c) { - while ((port_inb(COM1 + 5) & 0x20) == 0); // wait for THRE - port_outb(COM1, c); + while ((port_in8(COM1 + 5) & 0x20) == 0); // wait for THRE + port_out8(COM1, c); } char serial_read(void) { - while ((port_inb(COM1 + 5) & 0x01) == 0); // wait for DR - return port_inb(COM1); + while ((port_in8(COM1 + 5) & 0x01) == 0); // wait for DR + return port_in8(COM1); } void serial_write(const char *buf, size_t len) { -- cgit v1.2.3 From 1ad3593c1b97027ffae0f1a97f58508d2980df00 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Oct 2021 21:53:35 +0200 Subject: ATA: read identify data, detect drive size --- src/kernel/arch/i386/ata.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src/kernel/arch/i386/ata.c') diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index aaf05ff..e33b5af 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -4,6 +4,10 @@ #include +static struct { + uint32_t sectors; +} ata_drives[4]; + enum { LBAlo = 3, LBAmid = 4, @@ -29,8 +33,11 @@ static void ata_driveselect(int drive, int block) { static bool ata_identify(int drive) { uint16_t iobase = ata_iobase(drive); + uint16_t data[256]; uint8_t v; + // TODO test for float + ata_driveselect(drive, 0); for (int i = 2; i < 6; i++) port_out8(iobase + i, 0); @@ -49,7 +56,9 @@ static bool ata_identify(int drive) { while (!((v = port_in8(iobase + STATUS) & 0x9))); if (v & 1) return false; /* ERR was set, bail */ - // now I can read 512 bytes of data, TODO + for (int i = 0; i < 256; i++) + data[i] = port_in16(iobase); + ata_drives[drive].sectors = data[60] | (data[61] << 16); return true; } @@ -58,8 +67,11 @@ void ata_init(void) { for (int i = 0; i < 4; i++) { tty_const("probing drive "); _tty_var(i); - if (ata_identify(i)) - tty_const(" - exists"); + if (ata_identify(i)) { + tty_const(" - "); + _tty_var(ata_drives[i].sectors); + tty_const(" sectors (512b)"); + } tty_const("\n"); } } -- cgit v1.2.3 From 574d2cf63006cabbf9db4a80c55a407b5b33a700 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Oct 2021 21:59:22 +0200 Subject: ATA: detect device type --- src/kernel/arch/i386/ata.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'src/kernel/arch/i386/ata.c') diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index e33b5af..4bc4293 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -5,6 +5,11 @@ #include static struct { + enum { + DEV_UNKNOWN, + DEV_PATA, + DEV_PATAPI, + } type; uint32_t sectors; } ata_drives[4]; @@ -47,11 +52,19 @@ static bool ata_identify(int drive) { if (v == 0) return false; // nonexistent drive while (port_in8(iobase + STATUS) & 0x80); - /* check for uncomformant devices, quit early */ - if (port_in8(iobase + LBAmid) || port_in8(iobase + LBAhi)) { - // TODO atapi - return true; + /* detect device type */ + switch (port_in8(iobase + LBAmid)) { + case 0: + ata_drives[drive].type = DEV_PATA; + break; + case 0x14: + ata_drives[drive].type = DEV_PATAPI; + return true; + default: + ata_drives[drive].type = DEV_UNKNOWN; + return false; } + /* pool until bit 3 (DRQ) or 0 (ERR) is set */ while (!((v = port_in8(iobase + STATUS) & 0x9))); if (v & 1) return false; /* ERR was set, bail */ -- cgit v1.2.3 From 0c000a03560eeab06154c1fb80b7a59a5c0f9ac7 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 8 Oct 2021 13:06:42 +0000 Subject: ata: proper drive type detection; soft reset; 400ns delay function --- src/kernel/arch/i386/ata.c | 67 +++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 18 deletions(-) (limited to 'src/kernel/arch/i386/ata.c') diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index 4bc4293..916b918 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -20,6 +20,10 @@ enum { DRV = 6, CMD = 7, STATUS = 7, + + /* note: the OSDev wiki uses a different base port for the control port + * however i can just use this offset and stuff will just work tm */ + CTRL = 0x206, }; // offsets // get I/O port base for drive @@ -28,6 +32,12 @@ static uint16_t ata_iobase(int drive) { return secondary ? 0x170 : 0x1F0; } +static void ata_400ns(void) { + uint16_t base = ata_iobase(0); // doesn't matter + for (int i = 0; i < 4; i++) + port_in8(base + STATUS); +} + static void ata_driveselect(int drive, int block) { uint8_t v = 0xE0; if (drive&1) // slave? @@ -36,6 +46,38 @@ static void ata_driveselect(int drive, int block) { port_out8(ata_iobase(drive) + DRV, v); } +static void ata_softreset(int drive) { + uint16_t iobase = ata_iobase(drive); + port_out8(iobase + CTRL, 4); + port_out8(iobase + CTRL, 0); + ata_400ns(); + + uint16_t timeout = 10000; + while (--timeout) { // TODO separate polling function + uint8_t v = port_in8(iobase + STATUS); + if (v & 0x80) continue; // still BSY, continue + if (v & 0x40) break; // RDY, break + // TODO check for ERR + } +} + +static void ata_detecttype(int drive) { + ata_softreset(drive); + ata_driveselect(drive, 0); + ata_400ns(); + switch (port_in8(ata_iobase(drive) + LBAmid)) { + case 0: + ata_drives[drive].type = DEV_PATA; + break; + case 0x14: + ata_drives[drive].type = DEV_PATAPI; + return true; + default: + ata_drives[drive].type = DEV_UNKNOWN; + return false; + } +} + static bool ata_identify(int drive) { uint16_t iobase = ata_iobase(drive); uint16_t data[256]; @@ -52,19 +94,6 @@ static bool ata_identify(int drive) { if (v == 0) return false; // nonexistent drive while (port_in8(iobase + STATUS) & 0x80); - /* detect device type */ - switch (port_in8(iobase + LBAmid)) { - case 0: - ata_drives[drive].type = DEV_PATA; - break; - case 0x14: - ata_drives[drive].type = DEV_PATAPI; - return true; - default: - ata_drives[drive].type = DEV_UNKNOWN; - return false; - } - /* pool until bit 3 (DRQ) or 0 (ERR) is set */ while (!((v = port_in8(iobase + STATUS) & 0x9))); if (v & 1) return false; /* ERR was set, bail */ @@ -80,11 +109,13 @@ void ata_init(void) { for (int i = 0; i < 4; i++) { tty_const("probing drive "); _tty_var(i); - if (ata_identify(i)) { - tty_const(" - "); - _tty_var(ata_drives[i].sectors); - tty_const(" sectors (512b)"); - } + ata_detecttype(i); + _tty_var(ata_drives[i].type); + // if (ata_identify(i)) { + // tty_const(" - "); + // _tty_var(ata_drives[i].sectors); + // tty_const(" sectors (512b)"); + // } tty_const("\n"); } } -- cgit v1.2.3 From 6a90401ccb0d5a830772b8669113e1a17b6f40b7 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 8 Oct 2021 13:18:18 +0000 Subject: remove return statements from void function --- src/kernel/arch/i386/ata.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/kernel/arch/i386/ata.c') diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index 916b918..60dbb15 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -71,10 +71,10 @@ static void ata_detecttype(int drive) { break; case 0x14: ata_drives[drive].type = DEV_PATAPI; - return true; + break; default: ata_drives[drive].type = DEV_UNKNOWN; - return false; + break; } } -- cgit v1.2.3 From acf41ff6fee44dd24f9383d96fecd992dcb072e2 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 8 Oct 2021 19:29:12 +0200 Subject: ATA: implement the IDENTIFY PACKET DEVICE command --- src/kernel/arch/i386/ata.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'src/kernel/arch/i386/ata.c') diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index 60dbb15..9224ed6 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -83,12 +84,18 @@ static bool ata_identify(int drive) { uint16_t data[256]; uint8_t v; - // TODO test for float - ata_driveselect(drive, 0); for (int i = 2; i < 6; i++) port_out8(iobase + i, 0); - port_out8(iobase + CMD, 0xEC); // IDENTIFY + switch (ata_drives[drive].type) { + case DEV_PATA: + port_out8(iobase + CMD, 0xEC); // IDENTIFY + break; + case DEV_PATAPI: + port_out8(iobase + CMD, 0xA1); // IDENTIFY PACKET DEVICE + break; + default: panic_invalid_state(); + } v = port_in8(iobase + STATUS); if (v == 0) return false; // nonexistent drive @@ -110,12 +117,15 @@ void ata_init(void) { tty_const("probing drive "); _tty_var(i); ata_detecttype(i); - _tty_var(ata_drives[i].type); - // if (ata_identify(i)) { - // tty_const(" - "); - // _tty_var(ata_drives[i].sectors); - // tty_const(" sectors (512b)"); - // } + if (ata_drives[i].type != DEV_UNKNOWN) { + if (ata_identify(i)) { + tty_const(" - "); + _tty_var(ata_drives[i].sectors); + tty_const(" sectors (512b)"); + } else { + tty_const(" identify failed"); + } + } tty_const("\n"); } } -- cgit v1.2.3