Separate read function into blocking and async portions

This commit is contained in:
Justin C. Miller
2018-05-12 20:16:25 -07:00
parent 289104cde0
commit 0684fcf7e9
4 changed files with 73 additions and 18 deletions

View File

@@ -154,6 +154,10 @@ port::update()
rebase(); rebase();
m_pending.set_size(32); m_pending.set_size(32);
for (auto &pend : m_pending) {
pend.type = command_type::none;
}
m_data->interrupt_enable = 1; m_data->interrupt_enable = 1;
} else { } else {
m_state = state::inactive; m_state = state::inactive;
@@ -195,14 +199,18 @@ port::make_command(size_t length)
int slot = -1; int slot = -1;
uint32_t used_slots = (m_data->serial_active | m_data->cmd_issue); uint32_t used_slots = (m_data->serial_active | m_data->cmd_issue);
for (int i = 0; i < 32; ++i) { for (int i = 0; i < 32; ++i) {
if ((used_slots & (1 << i)) == 0) { if (used_slots & (1 << i)) continue;
if (m_pending[i].type == command_type::none) {
slot = i; slot = i;
break; break;
} else {
log::debug(logs::driver, "Type is %d", m_pending[i].type);
} }
} }
if (slot < 0) { if (slot < 0) {
log::info(logs::driver, "AHCI could not get a free command slot."); log::error(logs::driver, "AHCI could not get a free command slot.");
return -1; return -1;
} }
@@ -240,12 +248,12 @@ port::make_command(size_t length)
return slot; return slot;
} }
bool int
port::read(uint64_t sector, size_t length, void *dest) port::read_async(uint64_t offset, size_t length, void *dest)
{ {
int slot = make_command(length); int slot = make_command(length);
if (slot < 0) if (slot < 0)
return false; return 0;
cmd_table &cmdt = m_cmd_table[slot]; cmd_table &cmdt = m_cmd_table[slot];
@@ -255,6 +263,7 @@ port::read(uint64_t sector, size_t length, void *dest)
fis->command = ata_cmd::read_dma_ext; fis->command = ata_cmd::read_dma_ext;
fis->device = 0x40; // ATA8-ACS p.175 fis->device = 0x40; // ATA8-ACS p.175
uint64_t sector = offset >> 9;
fis->lba0 = (sector ) & 0xff; fis->lba0 = (sector ) & 0xff;
fis->lba1 = (sector >> 8) & 0xff; fis->lba1 = (sector >> 8) & 0xff;
fis->lba2 = (sector >> 16) & 0xff; fis->lba2 = (sector >> 16) & 0xff;
@@ -270,8 +279,29 @@ port::read(uint64_t sector, size_t length, void *dest)
count, sector, sector*512); count, sector, sector*512);
m_pending[slot].type = command_type::read; m_pending[slot].type = command_type::read;
m_pending[slot].offset = offset % 512;
m_pending[slot].count = 0;
m_pending[slot].data = dest; m_pending[slot].data = dest;
return issue_command(slot); if(issue_command(slot))
return slot;
else
return -1;
}
size_t
port::read(uint64_t offset, size_t length, void *dest)
{
int slot = read_async(offset, length, dest);
while (m_pending[slot].type == command_type::read)
asm("hlt");
kassert(m_pending[slot].type == command_type::finished,
"Read got unexpected command type");
size_t count = m_pending[slot].count;
m_pending[slot].type = command_type::none;
m_pending[slot].count = 0;
return count;
} }
bool bool
@@ -322,8 +352,6 @@ port::handle_interrupt()
default: default:
break; break;
} }
p.type = command_type::none;
p.data = nullptr;
} }
m_data->interrupt_status = m_data->interrupt_status; m_data->interrupt_status = m_data->interrupt_status;
} }
@@ -335,7 +363,9 @@ port::finish_read(int slot)
cmd_table &cmdt = m_cmd_table[slot]; cmd_table &cmdt = m_cmd_table[slot];
cmd_list_entry &ent = m_cmd_list[slot]; cmd_list_entry &ent = m_cmd_list[slot];
size_t count = 0;
void *p = m_pending[slot].data; void *p = m_pending[slot].data;
uint8_t offset = m_pending[slot].offset;
for (int i = 0; i < ent.prd_table_length; ++i) { for (int i = 0; i < ent.prd_table_length; ++i) {
size_t prd_len = (cmdt.entries[i].byte_count & 0x7fffffff) + 1; size_t prd_len = (cmdt.entries[i].byte_count & 0x7fffffff) + 1;
@@ -343,13 +373,18 @@ port::finish_read(int slot)
static_cast<addr_t>(cmdt.entries[i].data_base_low) | static_cast<addr_t>(cmdt.entries[i].data_base_low) |
static_cast<addr_t>(cmdt.entries[i].data_base_high) << 32; static_cast<addr_t>(cmdt.entries[i].data_base_high) << 32;
void *mem = pm->offset_virt(phys); void *mem = kutil::offset_pointer(pm->offset_virt(phys), offset);
kutil::memcpy(p, mem, prd_len); kutil::memcpy(p, mem, prd_len);
p = kutil::offset_pointer(p, prd_len); p = kutil::offset_pointer(p, prd_len - offset);
count += (prd_len - offset);
offset = 0;
pm->unmap_pages(mem, page_count(prd_len)); pm->unmap_pages(mem, page_count(prd_len));
} }
m_pending[slot].count = count;
m_pending[slot].type = command_type::finished;
m_pending[slot].data = nullptr;
} }
void void

View File

@@ -4,6 +4,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "kutil/vector.h" #include "kutil/vector.h"
#include "block_device.h"
namespace ahci { namespace ahci {
@@ -15,7 +16,8 @@ struct port_data;
/// A port on an AHCI HBA /// A port on an AHCI HBA
class port class port :
public block_device
{ {
public: public:
/// Constructor. /// Constructor.
@@ -53,12 +55,19 @@ public:
/// Stop command processing from this port /// Stop command processing from this port
void stop_commands(); void stop_commands();
/// Read data from the drive. /// Start a read operation from the drive.
/// \arg sector Starting sector to read /// \arg offset Offset to start from
/// \arg length Number of bytes to read /// \arg length Number of bytes to read
/// \arg dest A buffer where the data will be placed /// \arg dest A buffer where the data will be placed
/// \returns True if the command succeeded /// \returns A handle to the read operation, or -1 on error
bool read(uint64_t sector, size_t length, void *dest); int read_async(uint64_t offset, size_t length, void *dest);
/// Read from the drive, blocking until finished.
/// \arg offset Offset to start from
/// \arg length Number of bytes to read
/// \arg dest A buffer where the data will be placed
/// \returns The number of bytes read
virtual size_t read(uint64_t offset, size_t length, void *dest);
/// Handle an incoming interrupt /// Handle an incoming interrupt
void handle_interrupt(); void handle_interrupt();
@@ -97,11 +106,13 @@ private:
cmd_list_entry *m_cmd_list; cmd_list_entry *m_cmd_list;
cmd_table *m_cmd_table; cmd_table *m_cmd_table;
enum class command_type : uint8_t { none, read, write }; enum class command_type : uint8_t { none, read, write, finished };
struct pending struct pending
{ {
command_type type; command_type type;
uint8_t offset;
size_t count;
void *data; void *data;
}; };

10
src/kernel/block_device.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
/// \file block_device.h
/// Interface definition for block devices
/// Interface for block devices
class block_device
{
public:
virtual size_t read(size_t offset, size_t length, void *buffer) = 0;
};

View File

@@ -103,8 +103,7 @@ kernel_main(popcorn_data *header)
uint8_t buf[512]; uint8_t buf[512];
kutil::memset(buf, 0, 512); kutil::memset(buf, 0, 512);
disk->read(1, sizeof(buf), buf); disk->read(0x200, sizeof(buf), buf);
while (buf[0] == 0) io_wait();
console *cons = console::get(); console *cons = console::get();
uint8_t *p = &buf[0]; uint8_t *p = &buf[0];