mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
Separate read function into blocking and async portions
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
10
src/kernel/block_device.h
Normal 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;
|
||||||
|
};
|
||||||
@@ -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];
|
||||||
|
|||||||
Reference in New Issue
Block a user