Jelajahi Sumber

feat(ata): impl. init. ata and read sectors

greatbridf 2 tahun lalu
induk
melakukan
462ec39241
4 mengubah file dengan 152 tambahan dan 9 penghapusan
  1. 2 0
      CMakeLists.txt
  2. 56 0
      include/kernel/hw/ata.hpp
  3. 92 0
      src/kernel/hw/ata.cpp
  4. 2 9
      src/kernel/process.cpp

+ 2 - 0
CMakeLists.txt

@@ -50,6 +50,7 @@ set(KERNEL_MAIN_SOURCES src/kernel_main.c
                         src/kernel/mem.cpp
                         src/kernel/vfs.cpp
                         src/kernel/vga.c
+                        src/kernel/hw/ata.cpp
                         src/kernel/hw/keyboard.cpp
                         src/kernel/hw/serial.c
                         src/kernel/hw/timer.c
@@ -70,6 +71,7 @@ set(KERNEL_MAIN_SOURCES src/kernel_main.c
                         include/kernel/mm.hpp
                         include/kernel/vfs.h
                         include/kernel/vga.h
+                        include/kernel/hw/ata.hpp
                         include/kernel/hw/keyboard.h
                         include/kernel/hw/port.hpp
                         include/kernel/hw/serial.h

+ 56 - 0
include/kernel/hw/ata.hpp

@@ -0,0 +1,56 @@
+#pragma once
+
+#include <asm/port_io.h>
+#include <kernel/syscall.hpp>
+#include <kernel/hw/port.hpp>
+#include <types/cplusplus.hpp>
+
+constexpr port_id_t ATA_PRIMARY_BUS_BASE = 0x1f0;
+constexpr port_id_t ATA_PRIMARY_BUS_DEV_CONTROL_OR_ALTER_STATUS = 0x1f0;
+
+constexpr port_id_t ATA_SECONDARY_BUS_BASE = 0x170;
+constexpr port_id_t ATA_SECONDARY_BUS_DEV_CONTROL_OR_ALTER_STATUS = 0x1f0;
+
+namespace hw {
+class ata {
+public:
+    union stat_t {
+        uint8_t v;
+        struct {
+            uint8_t err : 1;
+            uint8_t idx : 1;
+            uint8_t corr : 1;
+            uint8_t drq : 1;
+            uint8_t srv : 1;
+            uint8_t df : 1;
+            uint8_t rdy : 1;
+            uint8_t bsy : 1;
+        } in;
+    };
+
+private:
+    p16 data;
+    p16r error;
+    p16w feats;
+    p8 count;
+    p8 lbalo;
+    p8 lbami;
+    p8 lbahi;
+    p8 drive;
+    p8r stats;
+    p8w comms;
+
+public:
+    ata(port_id_t port_base);
+
+    stat_t status(void) const;
+
+    void identify(void) const;
+
+    size_t read_data(char* buf, size_t n) const;
+
+    int read_sector(char* buf, uint32_t lba_low, uint16_t lba_high) const;
+};
+
+void init_ata(void* data);
+} // namespace hw

+ 92 - 0
src/kernel/hw/ata.cpp

@@ -0,0 +1,92 @@
+#include <asm/port_io.h>
+#include <kernel/stdio.h>
+#include <kernel/syscall.hpp>
+#include <kernel/tty.h>
+#include <kernel/hw/ata.hpp>
+
+hw::ata::ata(port_id_t p)
+    : data(p)
+    , error(p + 1)
+    , feats(p + 1)
+    , count(p + 2)
+    , lbalo(p + 3)
+    , lbami(p + 4)
+    , lbahi(p + 5)
+    , drive(p + 6)
+    , stats(p + 7)
+    , comms(p + 7)
+{}
+
+hw::ata::stat_t hw::ata::status(void) const
+{
+    return hw::ata::stat_t { *stats };
+}
+
+void hw::ata::identify(void) const
+{
+    char buf[512] {};
+
+    drive = 0xa0;
+    count = 0;
+    lbalo = 0;
+    lbami = 0;
+    lbahi = 0;
+    comms = 0xec;
+
+    stat_t stat {};
+    while ((stat = status()).in.bsy)
+        ;
+
+    if (stat.in.err)
+        syscall(0x03);
+
+    read_data(buf, 512);
+
+    if (!status().in.rdy)
+        syscall(0x03);
+}
+
+size_t hw::ata::read_data(char* buf, size_t n) const
+{
+    size_t orig_n = n;
+    n /= 2;
+    while (status().in.drq && n--) {
+        *(uint16_t*)buf = *data;
+        buf += sizeof(uint16_t);
+    }
+    return orig_n - n * 2;
+}
+
+int hw::ata::read_sector(char* buf, uint32_t lba_low, uint16_t lba_high) const
+{
+    drive = 0x40;                   // SELECT MASTER DRIVE AND LBA48
+    count = 0x00;                   // HIGH BYTE
+    lbalo = (lba_low >> 24) & 0xff;
+    lbami = lba_high & 0xff;
+    lbahi = (lba_high >> 8) & 0xff;
+    count = 0x01;                   // LOW BYTE
+    lbalo = lba_low & 0xff;
+    lbami = (lba_low >> 8) & 0xff;
+    lbahi = (lba_low >> 16) & 0xff;
+    comms = 0x24;                   // READ SECTORS EXT
+
+    while (status().in.bsy)
+        ;
+    if (status().in.drq)
+        read_data(buf, 512);
+    return GB_OK;
+}
+
+void hw::init_ata(void* data)
+{
+    if (data != nullptr)
+        syscall(0x03);
+
+    ata ata_pri(ATA_PRIMARY_BUS_BASE);
+    ata_pri.identify();
+    char buf[512] {};
+    ata_pri.read_sector(buf, 0, 0);
+    tty_print(console, "sector 0 read\n");
+    ata_pri.read_sector(buf, 1, 0);
+    tty_print(console, "sector 1 read\n");
+}

+ 2 - 9
src/kernel/process.cpp

@@ -4,6 +4,7 @@
 #include <kernel/process.hpp>
 #include <kernel/stdio.h>
 #include <kernel/tty.h>
+#include <kernel/hw/ata.hpp>
 #include <kernel_main.h>
 #include <types/types.h>
 #include <types/lock.h>
@@ -152,18 +153,10 @@ process::process(void* start_eip, uint8_t* image, size_t image_size, bool system
     }
 }
 
-void _example_io_thread(void* _d)
-{
-    const char* data = reinterpret_cast<const char*>(_d);
-    tty_print(console, data);
-    // syscall_sleep
-    asm volatile("movl $0x02, %%eax\nint $0x80":::"eax");
-}
-
 void kernel_threadd_main(void)
 {
     tty_print(console, "kernel thread daemon started\n");
-    k_new_thread(_example_io_thread, (void*)"data in io thread\n");
+    k_new_thread(hw::init_ata, nullptr);
     for (;;) {
         if (kthreadd_new_thd_func) {
             spin_lock(&kthreadd_lock);