kernel+init: Create a device node in /dev to access the CDROM from userspace!

Still using PIO, though.
This commit is contained in:
apio 2023-05-17 18:15:01 +02:00
parent dceb6be559
commit c477f85c19
Signed by: apio
GPG Key ID: B8A7D06E42258954
3 changed files with 117 additions and 10 deletions

View File

@ -4,6 +4,7 @@
#include "arch/Timer.h"
#include "arch/x86_64/IO.h"
#include "memory/MemoryManager.h"
#include <luna/Alignment.h>
#include <luna/CType.h>
#include <luna/SafeArithmetic.h>
#include <luna/Vector.h>
@ -329,6 +330,12 @@ namespace ATA
m_drives[drive] = {};
return false;
}
if (ATADevice::create(m_drives[drive]).has_error())
{
kwarnln("ata: Failed to register ATA drive %d:%d in DeviceRegistry", m_channel_index, drive);
continue;
}
}
}
@ -675,6 +682,25 @@ namespace ATA
return send_packet_atapi_pio(&read_packet, out, (u16)size);
}
Result<void> Drive::read_lba(u64 lba, void* out, usize nblocks)
{
const usize blocks_per_page = ARCH_PAGE_SIZE / m_block_size;
if (m_is_atapi)
{
kdbgln("ata: Reading %zu blocks from ATAPI drive using PIO, at LBA %ld", nblocks, lba);
while (nblocks > blocks_per_page)
{
TRY(atapi_read_pio(lba, out, ARCH_PAGE_SIZE));
lba += blocks_per_page;
nblocks -= blocks_per_page;
out = offset_ptr(out, ARCH_PAGE_SIZE);
}
return atapi_read_pio(lba, out, nblocks * m_block_size);
}
else
todo();
}
void Drive::irq_handler()
{
// Clear the IRQ flag.
@ -694,3 +720,61 @@ namespace ATA
}
}
}
static u32 next_minor = 0;
Result<void> ATADevice::create(SharedPtr<ATA::Drive> drive)
{
auto device = TRY(adopt_shared_if_nonnull(new (std::nothrow) ATADevice()));
device->m_drive = drive;
return DeviceRegistry::register_special_device(DeviceRegistry::Disk, next_minor++, device);
}
Result<u64> ATADevice::read(u8* buf, usize offset, usize size) const
{
if (size == 0) return 0;
if (offset > m_drive->capacity()) return 0;
if (offset + size > m_drive->capacity()) size = m_drive->capacity() - offset;
usize length = size;
auto block_size = m_drive->block_size();
auto* temp = TRY(make_array<u8>(block_size));
auto guard = make_scope_guard([temp] { delete[] temp; });
if (offset % block_size)
{
usize extra_size = block_size - (offset % block_size);
TRY(m_drive->read_lba(offset / block_size, temp, 1));
memcpy(buf, temp + (offset % block_size), extra_size);
offset += extra_size;
size -= extra_size;
buf += extra_size;
}
while (size >= ARCH_PAGE_SIZE)
{
TRY(m_drive->read_lba(offset / block_size, buf, ARCH_PAGE_SIZE / block_size));
offset += ARCH_PAGE_SIZE;
size -= ARCH_PAGE_SIZE;
buf += ARCH_PAGE_SIZE;
}
while (size >= block_size)
{
TRY(m_drive->read_lba(offset / block_size, buf, 1));
offset += block_size;
size -= block_size;
buf += block_size;
}
if (size)
{
TRY(m_drive->read_lba(offset / block_size, temp, 1));
memcpy(buf, temp, size);
}
return length;
}

View File

@ -142,6 +142,23 @@ namespace ATA
void irq_handler();
usize block_size() const
{
return m_block_size;
}
usize block_count() const
{
return m_block_count;
}
usize capacity() const
{
return m_block_count * m_block_size;
}
Result<void> read_lba(u64 lba, void* out, usize nblocks);
private:
bool identify_ata();
@ -265,23 +282,28 @@ class ATADevice : public Device
{
public:
// Initializer for DeviceRegistry.
static Result<void> create(SharedPtr<ATA::Controller> controller, int channel, int drive);
static Result<void> create(SharedPtr<ATA::Drive> drive);
Result<usize> read(u8*, usize, usize) const override;
Result<usize> write(const u8*, usize, usize) override;
Result<usize> write(const u8*, usize, usize) override
{
return err(ENOTSUP);
}
bool blocking() const override;
bool blocking() const override
{
return false;
}
Result<u64> ioctl(int request, void* arg) override;
usize size() const override;
usize size() const override
{
return m_drive->capacity();
}
virtual ~ATADevice() = default;
private:
ATADevice(SharedPtr<ATA::Controller> controller);
SharedPtr<ATA::Controller> m_controller;
int m_channel;
int m_drive;
ATADevice() = default;
SharedPtr<ATA::Drive> m_drive;
};

View File

@ -12,6 +12,7 @@ namespace DeviceRegistry
Console = 1,
Memory = 2,
Framebuffer = 3,
Disk = 4,
};
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor);