Compare commits

..

5 Commits

Author SHA1 Message Date
Bananymous 211cad03ff Kernel: Implement bare boness DMA Region
This does nothing but allocate contiguous physical and virtual memory
and map it as CacheDisable. Also memory is automatically freed RAII style.
2023-10-08 02:57:22 +03:00
Bananymous 8a9816d6e0 Kernel: Add API for getting contiguous physcial pages
This will be used to create DMA regions.
2023-10-08 02:57:22 +03:00
Bananymous 03d2bf4002 Kernel: Rework physical memory allocation
PhysicalRange is now much simpler bitmap. This makes expanding
PhysicalRange API much easier.
2023-10-08 02:50:23 +03:00
Bananymous f071240b33 Kernel: Fix PCI BarRegion offsets
Calculations accidentally assumed bar registers are 8 byte instead
of 4.
2023-10-08 02:50:23 +03:00
Bananymous 27364f64a6 Kernel: Rework whole ATA driver structure
Make ATA driver more compatible when we are adding SATA support
2023-10-08 02:50:23 +03:00
35 changed files with 654 additions and 476 deletions

Binary file not shown.

View File

@ -34,6 +34,7 @@ set(KERNEL_SOURCES
kernel/Input/PS2Keymap.cpp kernel/Input/PS2Keymap.cpp
kernel/InterruptController.cpp kernel/InterruptController.cpp
kernel/kernel.cpp kernel/kernel.cpp
kernel/Memory/DMARegion.cpp
kernel/Memory/FileBackedRegion.cpp kernel/Memory/FileBackedRegion.cpp
kernel/Memory/GeneralAllocator.cpp kernel/Memory/GeneralAllocator.cpp
kernel/Memory/Heap.cpp kernel/Memory/Heap.cpp
@ -52,9 +53,9 @@ set(KERNEL_SOURCES
kernel/Semaphore.cpp kernel/Semaphore.cpp
kernel/SpinLock.cpp kernel/SpinLock.cpp
kernel/SSP.cpp kernel/SSP.cpp
kernel/Storage/ATABus.cpp kernel/Storage/ATA/ATABus.cpp
kernel/Storage/ATAController.cpp kernel/Storage/ATA/ATAController.cpp
kernel/Storage/ATADevice.cpp kernel/Storage/ATA/ATADevice.cpp
kernel/Storage/DiskCache.cpp kernel/Storage/DiskCache.cpp
kernel/Storage/StorageDevice.cpp kernel/Storage/StorageDevice.cpp
kernel/Syscall.cpp kernel/Syscall.cpp

View File

@ -17,6 +17,8 @@ namespace Kernel
virtual dev_t rdev() const override = 0; virtual dev_t rdev() const override = 0;
virtual BAN::StringView name() const = 0;
protected: protected:
Device(mode_t, uid_t, gid_t); Device(mode_t, uid_t, gid_t);
}; };

View File

@ -1,3 +1,5 @@
#pragma once
#include <kernel/Device/Device.h> #include <kernel/Device/Device.h>
namespace Kernel namespace Kernel
@ -10,6 +12,8 @@ namespace Kernel
virtual dev_t rdev() const override { return m_rdev; } virtual dev_t rdev() const override { return m_rdev; }
virtual BAN::StringView name() const override { return "null"sv; }
protected: protected:
NullDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev) NullDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev)
: CharacterDevice(mode, uid, gid) : CharacterDevice(mode, uid, gid)

View File

@ -10,6 +10,8 @@ namespace Kernel
virtual dev_t rdev() const override { return m_rdev; } virtual dev_t rdev() const override { return m_rdev; }
virtual BAN::StringView name() const override { return "zero"sv; }
protected: protected:
ZeroDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev) ZeroDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev)
: CharacterDevice(mode, uid, gid) : CharacterDevice(mode, uid, gid)

View File

@ -15,10 +15,12 @@ namespace Kernel
void initialize_device_updater(); void initialize_device_updater();
void add_device(BAN::StringView path, BAN::RefPtr<RamInode>); void add_device(BAN::RefPtr<Device>);
void add_inode(BAN::StringView path, BAN::RefPtr<RamInode>);
void for_each_device(const BAN::Function<BAN::Iteration(Device*)>& callback); void for_each_device(const BAN::Function<BAN::Iteration(Device*)>& callback);
dev_t get_next_dev(); dev_t get_next_dev() const;
int get_next_input_device() const;
void initiate_sync(bool should_block); void initiate_sync(bool should_block);
@ -28,7 +30,7 @@ namespace Kernel
{ } { }
private: private:
SpinLock m_device_lock; mutable SpinLock m_device_lock;
Semaphore m_sync_done; Semaphore m_sync_done;
Semaphore m_sync_semaphore; Semaphore m_sync_semaphore;

View File

@ -9,12 +9,13 @@ namespace Kernel::Input
class PS2Device : public CharacterDevice, public Interruptable class PS2Device : public CharacterDevice, public Interruptable
{ {
public: public:
PS2Device();
virtual ~PS2Device() {} virtual ~PS2Device() {}
public: virtual BAN::StringView name() const override { return m_name; }
PS2Device()
: CharacterDevice(Mode::IRUSR | Mode::IRGRP, 0, 0) private:
{ } const BAN::String m_name;
}; };
class PS2Controller class PS2Controller

View File

@ -0,0 +1,27 @@
#pragma once
#include <kernel/Memory/MemoryRegion.h>
namespace Kernel
{
class DMARegion
{
public:
BAN::ErrorOr<BAN::UniqPtr<DMARegion>> create(size_t size);
~DMARegion();
size_t size() const { return m_size; }
vaddr_t vaddr() const { return m_vaddr; }
paddr_t paddr() const { return m_paddr; }
private:
DMARegion(size_t size, vaddr_t vaddr, paddr_t paddr);
private:
const size_t m_size;
const vaddr_t m_vaddr;
const paddr_t m_paddr;
};
}

View File

@ -21,6 +21,9 @@ namespace Kernel
paddr_t take_free_page(); paddr_t take_free_page();
void release_page(paddr_t); void release_page(paddr_t);
paddr_t take_free_contiguous_pages(size_t pages);
void release_contiguous_pages(paddr_t paddr, size_t pages);
size_t used_pages() const; size_t used_pages() const;
size_t free_pages() const; size_t free_pages() const;

View File

@ -3,7 +3,6 @@
#include <kernel/Memory/Types.h> #include <kernel/Memory/Types.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
namespace Kernel namespace Kernel
{ {
@ -12,42 +11,40 @@ namespace Kernel
{ {
public: public:
PhysicalRange(paddr_t, size_t); PhysicalRange(paddr_t, size_t);
paddr_t reserve_page(); paddr_t reserve_page();
void release_page(paddr_t); void release_page(paddr_t);
paddr_t reserve_contiguous_pages(size_t pages);
void release_contiguous_pages(paddr_t paddr, size_t pages);
paddr_t start() const { return m_paddr; } paddr_t start() const { return m_paddr; }
paddr_t end() const { return m_paddr + m_size; } paddr_t end() const { return m_paddr + m_size; }
bool contains(paddr_t addr) const { return m_paddr <= addr && addr < m_paddr + m_size; } bool contains(paddr_t addr) const { return m_paddr <= addr && addr < m_paddr + m_size; }
size_t usable_memory() const { return m_reservable_pages * PAGE_SIZE; } size_t usable_memory() const { return m_data_pages * PAGE_SIZE; }
size_t used_pages() const { return m_used_pages; } size_t used_pages() const { return m_data_pages - m_free_pages; }
size_t free_pages() const { return m_free_pages; } size_t free_pages() const { return m_free_pages; }
private: private:
struct node unsigned long long* ull_bitmap_ptr() { return (unsigned long long*)m_vaddr; }
{ const unsigned long long* ull_bitmap_ptr() const { return (const unsigned long long*)m_vaddr; }
node* next;
node* prev;
};
paddr_t page_address(const node*) const; paddr_t paddr_for_bit(unsigned long long) const;
node* node_address(paddr_t) const; unsigned long long bit_for_paddr(paddr_t paddr) const;
unsigned long long contiguous_bits_set(unsigned long long start, unsigned long long count) const;
private: private:
paddr_t m_paddr { 0 }; const paddr_t m_paddr { 0 };
const size_t m_size { 0 };
vaddr_t m_vaddr { 0 }; vaddr_t m_vaddr { 0 };
size_t m_size { 0 };
uint64_t m_total_pages { 0 }; const size_t m_bitmap_pages { 0 };
uint64_t m_reservable_pages { 0 }; const size_t m_data_pages { 0 };
uint64_t m_list_pages { 0 };
size_t m_used_pages { 0 };
size_t m_free_pages { 0 }; size_t m_free_pages { 0 };
node* m_free_list { nullptr };
node* m_used_list { nullptr };
}; };
} }

View File

@ -3,6 +3,9 @@
#include <BAN/UniqPtr.h> #include <BAN/UniqPtr.h>
#include <BAN/Vector.h> #include <BAN/Vector.h>
#include <kernel/Memory/Types.h> #include <kernel/Memory/Types.h>
#include <kernel/Storage/StorageController.h>
#include <sys/types.h>
namespace Kernel::PCI namespace Kernel::PCI
{ {

View File

@ -1,48 +1,46 @@
#pragma once #pragma once
#include <BAN/Errors.h> #include <BAN/RefPtr.h>
#include <BAN/Vector.h>
#include <kernel/InterruptController.h> #include <kernel/InterruptController.h>
#include <kernel/SpinLock.h> #include <kernel/SpinLock.h>
#include <kernel/Storage/ATAController.h>
namespace Kernel namespace Kernel
{ {
class ATADevice; class ATADevice;
class ATABus : public Interruptable class ATABus : public BAN::RefCounted<ATABus>, public Interruptable
{ {
public: public:
enum class DeviceType enum class DeviceType
{ {
None,
ATA, ATA,
ATAPI, ATAPI,
}; };
public: public:
static ATABus* create(ATAController&, uint16_t base, uint16_t ctrl, uint8_t irq); static BAN::ErrorOr<BAN::RefPtr<ATABus>> create(uint16_t base, uint16_t ctrl, uint8_t irq);
BAN::ErrorOr<void> read(ATADevice&, uint64_t, uint8_t, uint8_t*); BAN::ErrorOr<void> read(ATADevice&, uint64_t, uint8_t, uint8_t*);
BAN::ErrorOr<void> write(ATADevice&, uint64_t, uint8_t, const uint8_t*); BAN::ErrorOr<void> write(ATADevice&, uint64_t, uint8_t, const uint8_t*);
ATAController& controller() { return m_controller; }
virtual void handle_irq() override; virtual void handle_irq() override;
void initialize_devfs();
private: private:
ATABus(ATAController& controller, uint16_t base, uint16_t ctrl) ATABus(uint16_t base, uint16_t ctrl)
: m_controller(controller) : m_base(base)
, m_base(base)
, m_ctrl(ctrl) , m_ctrl(ctrl)
{} {}
void initialize(uint8_t irq); BAN::ErrorOr<void> initialize();
void select_device(const ATADevice&); void select_device(bool secondary);
DeviceType identify(const ATADevice&, uint16_t*); BAN::ErrorOr<DeviceType> identify(bool secondary, BAN::Span<uint16_t> buffer);
void block_until_irq(); void block_until_irq();
uint8_t device_index(const ATADevice&) const; //uint8_t device_index(const ATADevice&) const;
uint8_t io_read(uint16_t); uint8_t io_read(uint16_t);
void io_write(uint16_t, uint8_t); void io_write(uint16_t, uint8_t);
@ -52,14 +50,14 @@ namespace Kernel
BAN::Error error(); BAN::Error error();
private: private:
ATAController& m_controller;
const uint16_t m_base; const uint16_t m_base;
const uint16_t m_ctrl; const uint16_t m_ctrl;
SpinLock m_lock; SpinLock m_lock;
bool m_has_got_irq { false }; bool m_has_got_irq { false };
BAN::RefPtr<ATADevice> m_devices[2] {}; // Non-owning pointers
BAN::Vector<ATADevice*> m_devices;
friend class ATAController; friend class ATAController;
}; };

View File

@ -0,0 +1,27 @@
#pragma once
#include <BAN/UniqPtr.h>
#include <kernel/PCI.h>
#include <kernel/Storage/StorageController.h>
#include <kernel/Storage/ATA/ATABus.h>
#include <kernel/Storage/ATA/ATADevice.h>
namespace Kernel
{
class ATAController : public StorageController
{
public:
static BAN::ErrorOr<BAN::UniqPtr<StorageController>> create(PCI::Device&);
virtual BAN::ErrorOr<void> initialize() override;
private:
ATAController(PCI::Device& pci_device)
: m_pci_device(pci_device)
{ }
private:
PCI::Device& m_pci_device;
};
}

View File

@ -1,5 +1,8 @@
#pragma once #pragma once
#define ATA_PROGIF_PRIMARY_NATIVE (1 << 0)
#define ATA_PROGIF_SECONDARY_NATIVE (1 << 2)
#define ATA_PORT_DATA 0x00 #define ATA_PORT_DATA 0x00
#define ATA_PORT_ERROR 0x00 #define ATA_PORT_ERROR 0x00
#define ATA_PORT_SECTOR_COUNT 0x02 #define ATA_PORT_SECTOR_COUNT 0x02

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <kernel/Storage/ATABus.h> #include <kernel/Storage/ATA/ATABus.h>
#include <kernel/Storage/StorageDevice.h> #include <kernel/Storage/StorageDevice.h>
namespace Kernel namespace Kernel
@ -9,23 +9,31 @@ namespace Kernel
class ATADevice final : public StorageDevice class ATADevice final : public StorageDevice
{ {
public: public:
ATADevice(ATABus&); static BAN::ErrorOr<BAN::RefPtr<ATADevice>> create(BAN::RefPtr<ATABus>, ATABus::DeviceType, bool is_secondary, BAN::Span<const uint16_t> identify_data);
BAN::ErrorOr<void> initialize(ATABus::DeviceType, const uint16_t*);
virtual uint32_t sector_size() const override { return m_sector_words * 2; } virtual uint32_t sector_size() const override { return m_sector_words * 2; }
virtual uint64_t total_size() const override { return m_lba_count * sector_size(); } virtual uint64_t total_size() const override { return m_lba_count * sector_size(); }
bool is_secondary() const { return m_is_secondary; }
uint32_t words_per_sector() const { return m_sector_words; }
uint64_t sector_count() const { return m_lba_count; }
BAN::StringView model() const { return m_model; } BAN::StringView model() const { return m_model; }
BAN::StringView name() const;
protected: protected:
virtual BAN::ErrorOr<void> read_sectors_impl(uint64_t, uint8_t, uint8_t*) override; virtual BAN::ErrorOr<void> read_sectors_impl(uint64_t, uint8_t, uint8_t*) override;
virtual BAN::ErrorOr<void> write_sectors_impl(uint64_t, uint8_t, const uint8_t*) override; virtual BAN::ErrorOr<void> write_sectors_impl(uint64_t, uint8_t, const uint8_t*) override;
private: private:
ATABus& m_bus; ATADevice(BAN::RefPtr<ATABus>, ATABus::DeviceType, bool is_secodary);
uint8_t m_index; BAN::ErrorOr<void> initialize(BAN::Span<const uint16_t> identify_data);
private:
BAN::RefPtr<ATABus> m_bus;
const ATABus::DeviceType m_type;
const bool m_is_secondary;
ATABus::DeviceType m_type;
uint16_t m_signature; uint16_t m_signature;
uint16_t m_capabilities; uint16_t m_capabilities;
uint32_t m_command_set; uint32_t m_command_set;
@ -33,8 +41,6 @@ namespace Kernel
uint64_t m_lba_count; uint64_t m_lba_count;
char m_model[41]; char m_model[41];
friend class ATABus;
public: public:
virtual Mode mode() const override { return { Mode::IFBLK | Mode::IRUSR | Mode::IRGRP }; } virtual Mode mode() const override { return { Mode::IFBLK | Mode::IRUSR | Mode::IRGRP }; }
virtual uid_t uid() const override { return 0; } virtual uid_t uid() const override { return 0; }

View File

@ -1,38 +0,0 @@
#pragma once
#include <kernel/PCI.h>
#include <kernel/Storage/StorageController.h>
namespace Kernel
{
class ATABus;
class ATAController final : public StorageController
{
public:
static BAN::ErrorOr<BAN::RefPtr<ATAController>> create(const PCI::Device&);
virtual BAN::Vector<BAN::RefPtr<StorageDevice>> devices() override;
private:
ATAController();
BAN::ErrorOr<void> initialize(const PCI::Device& device);
private:
ATABus* m_buses[2] { nullptr, nullptr };
friend class ATABus;
public:
virtual Mode mode() const override { return { Mode::IFCHR }; }
virtual uid_t uid() const override { return 0; }
virtual gid_t gid() const override { return 0; }
virtual dev_t rdev() const override { return m_rdev; }
virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
private:
const dev_t m_rdev;
};
}

View File

@ -1,17 +1,13 @@
#pragma once #pragma once
#include <kernel/Storage/StorageDevice.h>
namespace Kernel namespace Kernel
{ {
class StorageController : public CharacterDevice class StorageController
{ {
public: public:
StorageController() virtual ~StorageController() {}
: CharacterDevice(0660, 0, 0) virtual BAN::ErrorOr<void> initialize() = 0;
{ }
virtual BAN::Vector<BAN::RefPtr<StorageDevice>> devices() = 0;
}; };
} }

View File

@ -20,7 +20,7 @@ namespace Kernel
class Partition final : public BlockDevice class Partition final : public BlockDevice
{ {
public: public:
Partition(StorageDevice&, const GUID&, const GUID&, uint64_t, uint64_t, uint64_t, const char*, uint32_t); static BAN::ErrorOr<BAN::RefPtr<Partition>> create(StorageDevice&, const GUID& type, const GUID& guid, uint64_t start, uint64_t end, uint64_t attr, const char* label, uint32_t index);
const GUID& partition_type() const { return m_type; } const GUID& partition_type() const { return m_type; }
const GUID& partition_guid() const { return m_guid; } const GUID& partition_guid() const { return m_guid; }
@ -33,6 +33,11 @@ namespace Kernel
BAN::ErrorOr<void> read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer); BAN::ErrorOr<void> read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer);
BAN::ErrorOr<void> write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer); BAN::ErrorOr<void> write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer);
virtual BAN::StringView name() const override { return m_name; }
private:
Partition(StorageDevice&, const GUID&, const GUID&, uint64_t, uint64_t, uint64_t, const char*, uint32_t);
private: private:
StorageDevice& m_device; StorageDevice& m_device;
const GUID m_type; const GUID m_type;
@ -41,6 +46,7 @@ namespace Kernel
const uint64_t m_lba_end; const uint64_t m_lba_end;
const uint64_t m_attributes; const uint64_t m_attributes;
char m_label[36 * 4 + 1]; char m_label[36 * 4 + 1];
const BAN::String m_name;
public: public:
virtual bool is_partition() const override { return true; } virtual bool is_partition() const override { return true; }
@ -73,8 +79,8 @@ namespace Kernel
virtual uint32_t sector_size() const = 0; virtual uint32_t sector_size() const = 0;
virtual uint64_t total_size() const = 0; virtual uint64_t total_size() const = 0;
BAN::Vector<Partition*>& partitions() { return m_partitions; } BAN::Vector<BAN::RefPtr<Partition>>& partitions() { return m_partitions; }
const BAN::Vector<Partition*>& partitions() const { return m_partitions; } const BAN::Vector<BAN::RefPtr<Partition>>& partitions() const { return m_partitions; }
BAN::ErrorOr<void> sync_disk_cache(); BAN::ErrorOr<void> sync_disk_cache();
virtual bool is_storage_device() const override { return true; } virtual bool is_storage_device() const override { return true; }
@ -85,9 +91,9 @@ namespace Kernel
void add_disk_cache(); void add_disk_cache();
private: private:
SpinLock m_lock; SpinLock m_lock;
BAN::Optional<DiskCache> m_disk_cache; BAN::Optional<DiskCache> m_disk_cache;
BAN::Vector<Partition*> m_partitions; BAN::Vector<BAN::RefPtr<Partition>> m_partitions;
friend class DiskCache; friend class DiskCache;
}; };

View File

@ -50,8 +50,6 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, void*, size_t) override; virtual BAN::ErrorOr<size_t> read_impl(off_t, void*, size_t) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, const void*, size_t) override; virtual BAN::ErrorOr<size_t> write_impl(off_t, const void*, size_t) override;
virtual BAN::StringView name() const = 0;
private: private:
void do_backspace(); void do_backspace();

View File

@ -22,8 +22,8 @@ namespace Kernel
auto root_inode = MUST(RamDirectoryInode::create(*s_instance, 0, 0755, 0, 0)); auto root_inode = MUST(RamDirectoryInode::create(*s_instance, 0, 0755, 0, 0));
MUST(s_instance->set_root_inode(root_inode)); MUST(s_instance->set_root_inode(root_inode));
s_instance->add_device("null", MUST(NullDevice::create(0666, 0, 0))); s_instance->add_device(MUST(NullDevice::create(0666, 0, 0)));
s_instance->add_device("zero", MUST(ZeroDevice::create(0666, 0, 0))); s_instance->add_device(MUST(ZeroDevice::create(0666, 0, 0)));
} }
DevFileSystem& DevFileSystem::get() DevFileSystem& DevFileSystem::get()
@ -117,10 +117,16 @@ namespace Kernel
m_sync_done.block(); m_sync_done.block();
} }
void DevFileSystem::add_device(BAN::StringView path, BAN::RefPtr<RamInode> device) void DevFileSystem::add_device(BAN::RefPtr<Device> device)
{
ASSERT(!device->name().contains('/'));
MUST(reinterpret_cast<RamDirectoryInode*>(root_inode().ptr())->add_inode(device->name(), device));
}
void DevFileSystem::add_inode(BAN::StringView path, BAN::RefPtr<RamInode> inode)
{ {
ASSERT(!path.contains('/')); ASSERT(!path.contains('/'));
MUST(reinterpret_cast<RamDirectoryInode*>(root_inode().ptr())->add_inode(path, device)); MUST(reinterpret_cast<RamDirectoryInode*>(root_inode().ptr())->add_inode(path, inode));
} }
void DevFileSystem::for_each_device(const BAN::Function<BAN::Iteration(Device*)>& callback) void DevFileSystem::for_each_device(const BAN::Function<BAN::Iteration(Device*)>& callback)
@ -136,11 +142,18 @@ namespace Kernel
); );
} }
dev_t DevFileSystem::get_next_dev() dev_t DevFileSystem::get_next_dev() const
{ {
LockGuard _(m_device_lock); LockGuard _(m_device_lock);
static dev_t next_dev = 1; static dev_t next_dev = 1;
return next_dev++; return next_dev++;
} }
int DevFileSystem::get_next_input_device() const
{
LockGuard _(m_device_lock);
static dev_t next_dev = 0;
return next_dev++;
}
} }

View File

@ -68,6 +68,11 @@ namespace Kernel::Input
static PS2Controller* s_instance = nullptr; static PS2Controller* s_instance = nullptr;
PS2Device::PS2Device()
: CharacterDevice(0440, 0, 0)
, m_name(BAN::String::formatted("input{}", DevFileSystem::get().get_next_input_device()))
{ }
BAN::ErrorOr<void> PS2Controller::initialize() BAN::ErrorOr<void> PS2Controller::initialize()
{ {
ASSERT(s_instance == nullptr); ASSERT(s_instance == nullptr);
@ -175,14 +180,14 @@ namespace Kernel::Input
m_devices[0]->set_irq(PS2::IRQ::DEVICE0); m_devices[0]->set_irq(PS2::IRQ::DEVICE0);
m_devices[0]->enable_interrupt(); m_devices[0]->enable_interrupt();
config |= PS2::Config::INTERRUPT_FIRST_PORT; config |= PS2::Config::INTERRUPT_FIRST_PORT;
DevFileSystem::get().add_device("input0", m_devices[0]); DevFileSystem::get().add_device(m_devices[0]);
} }
if (m_devices[1]) if (m_devices[1])
{ {
m_devices[1]->set_irq(PS2::IRQ::DEVICE1); m_devices[1]->set_irq(PS2::IRQ::DEVICE1);
m_devices[1]->enable_interrupt(); m_devices[1]->enable_interrupt();
config |= PS2::Config::INTERRUPT_SECOND_PORT; config |= PS2::Config::INTERRUPT_SECOND_PORT;
DevFileSystem::get().add_device("input1", m_devices[1]); DevFileSystem::get().add_device(m_devices[1]);
} }
controller_send_command(PS2::Command::WRITE_CONFIG, config); controller_send_command(PS2::Command::WRITE_CONFIG, config);

View File

@ -0,0 +1,46 @@
#include <BAN/ScopeGuard.h>
#include <kernel/Memory/DMARegion.h>
#include <kernel/Memory/Heap.h>
namespace Kernel
{
BAN::ErrorOr<BAN::UniqPtr<DMARegion>> DMARegion::create(size_t size)
{
size_t needed_pages = BAN::Math::div_round_up<size_t>(size, PAGE_SIZE);
vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
if (vaddr == 0)
return BAN::Error::from_errno(ENOMEM);
BAN::ScopeGuard vaddr_guard([vaddr, size] { PageTable::kernel().unmap_range(vaddr, size); });
paddr_t paddr = Heap::get().take_free_contiguous_pages(needed_pages);
if (paddr == 0)
return BAN::Error::from_errno(ENOMEM);
BAN::ScopeGuard paddr_guard([paddr, needed_pages] { Heap::get().release_contiguous_pages(paddr, needed_pages); });
auto* region_ptr = new DMARegion(size, vaddr, paddr);
if (region_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
vaddr_guard.disable();
paddr_guard.disable();
PageTable::kernel().map_range_at(paddr, vaddr, size, PageTable::Flags::CacheDisable | PageTable::Flags::ReadWrite | PageTable::Flags::Reserved);
return BAN::UniqPtr<DMARegion>::adopt(region_ptr);
}
DMARegion::DMARegion(size_t size, vaddr_t vaddr, paddr_t paddr)
: m_size(size)
, m_vaddr(vaddr)
, m_paddr(paddr)
{ }
DMARegion::~DMARegion()
{
PageTable::kernel().unmap_range(m_vaddr, m_size);
Heap::get().release_contiguous_pages(m_vaddr, BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE));
}
}

View File

@ -3,6 +3,8 @@
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <kernel/multiboot.h> #include <kernel/multiboot.h>
extern uint8_t g_kernel_end[];
namespace Kernel namespace Kernel
{ {
@ -30,14 +32,22 @@ namespace Kernel
for (size_t i = 0; i < g_multiboot_info->mmap_length;) for (size_t i = 0; i < g_multiboot_info->mmap_length;)
{ {
multiboot_memory_map_t* mmmt = (multiboot_memory_map_t*)P2V(g_multiboot_info->mmap_addr + i); multiboot_memory_map_t* mmmt = (multiboot_memory_map_t*)P2V(g_multiboot_info->mmap_addr + i);
if (mmmt->type == 1) if (mmmt->type == 1)
{ {
PhysicalRange range(mmmt->base_addr, mmmt->length); paddr_t start = mmmt->base_addr;
if (range.usable_memory() > 0) if (start < V2P(g_kernel_end))
MUST(m_physical_ranges.push_back(range)); start = V2P(g_kernel_end);
} if (auto rem = start % PAGE_SIZE)
start += PAGE_SIZE - rem;
paddr_t end = mmmt->base_addr + mmmt->length;
if (auto rem = end % PAGE_SIZE)
end -= rem;
// Physical pages needs atleast 2 pages
if (end > start + PAGE_SIZE)
MUST(m_physical_ranges.emplace_back(start, end - start));
}
i += mmmt->size + sizeof(uint32_t); i += mmmt->size + sizeof(uint32_t);
} }
@ -55,22 +65,36 @@ namespace Kernel
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
for (auto& range : m_physical_ranges) for (auto& range : m_physical_ranges)
if (paddr_t page = range.reserve_page()) if (range.free_pages() >= 1)
return page; return range.reserve_page();
return 0; return 0;
} }
void Heap::release_page(paddr_t addr) void Heap::release_page(paddr_t paddr)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
for (auto& range : m_physical_ranges) for (auto& range : m_physical_ranges)
{ if (range.contains(paddr))
if (range.contains(addr)) return range.release_page(paddr);
{ ASSERT_NOT_REACHED();
range.release_page(addr); }
return;
} paddr_t Heap::take_free_contiguous_pages(size_t pages)
} {
LockGuard _(m_lock);
for (auto& range : m_physical_ranges)
if (range.free_pages() >= pages)
if (paddr_t paddr = range.reserve_contiguous_pages(pages))
return paddr;
return 0;
}
void Heap::release_contiguous_pages(paddr_t paddr, size_t pages)
{
LockGuard _(m_lock);
for (auto& range : m_physical_ranges)
if (range.contains(paddr))
return range.release_contiguous_pages(paddr, pages);
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }

View File

@ -3,123 +3,150 @@
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <kernel/Memory/PhysicalRange.h> #include <kernel/Memory/PhysicalRange.h>
extern uint8_t g_kernel_end[];
namespace Kernel namespace Kernel
{ {
PhysicalRange::PhysicalRange(paddr_t start, size_t size) using ull = unsigned long long;
static constexpr ull ull_bits = sizeof(ull) * 8;
PhysicalRange::PhysicalRange(paddr_t paddr, size_t size)
: m_paddr(paddr)
, m_size(size)
, m_bitmap_pages(BAN::Math::div_round_up<size_t>(size / PAGE_SIZE, 8))
, m_data_pages((size / PAGE_SIZE) - m_bitmap_pages)
, m_free_pages(m_data_pages)
{ {
// We can't use the memory ovelapping with kernel ASSERT(paddr % PAGE_SIZE == 0);
if (start + size <= V2P(g_kernel_end)) ASSERT(size % PAGE_SIZE == 0);
return; ASSERT(m_bitmap_pages < size / PAGE_SIZE);
// Align start to page boundary and after the kernel memory m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(m_bitmap_pages, KERNEL_OFFSET);
m_paddr = BAN::Math::max(start, V2P(g_kernel_end));
if (auto rem = m_paddr % PAGE_SIZE)
m_paddr += PAGE_SIZE - rem;
if (size <= m_paddr - start)
return;
// Align size to page boundary
m_size = size - (m_paddr - start);
if (auto rem = m_size % PAGE_SIZE)
m_size -= rem;
// We need atleast 2 pages
m_total_pages = m_size / PAGE_SIZE;
if (m_total_pages <= 1)
return;
// FIXME: if total pages is just over multiple of (PAGE_SIZE / sizeof(node)) we might make
// couple of pages unallocatable
m_list_pages = BAN::Math::div_round_up<uint64_t>(m_total_pages * sizeof(node), PAGE_SIZE);
m_reservable_pages = m_total_pages - m_list_pages;
m_used_pages = 0;
m_free_pages = m_reservable_pages;
m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(m_list_pages, KERNEL_OFFSET);
ASSERT(m_vaddr); ASSERT(m_vaddr);
PageTable::kernel().map_range_at(m_paddr, m_vaddr, size, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
PageTable::kernel().map_range_at(m_paddr, m_vaddr, m_list_pages * PAGE_SIZE, PageTable::Flags::ReadWrite | PageTable::Flags::Present); memset((void*)m_vaddr, 0x00, m_bitmap_pages * PAGE_SIZE);
memset((void*)m_vaddr, 0xFF, m_data_pages / 8);
for (ull i = 0; i < m_data_pages % 8; i++)
((uint8_t*)m_vaddr)[m_data_pages / 8] |= 1 << i;
// Initialize page list so that every page points to the next one dprintln("physical range needs {} pages for bitmap", m_bitmap_pages);
node* page_list = (node*)m_vaddr; }
for (uint64_t i = 0; i < m_reservable_pages; i++) paddr_t PhysicalRange::paddr_for_bit(ull bit) const
page_list[i] = { page_list + i - 1, page_list + i + 1 }; {
page_list[ 0 ].next = nullptr; return m_paddr + (m_bitmap_pages + bit) * PAGE_SIZE;
page_list[m_reservable_pages - 1].prev = nullptr; }
m_free_list = page_list; ull PhysicalRange::bit_for_paddr(paddr_t paddr) const
m_used_list = nullptr; {
return (paddr - m_paddr) / PAGE_SIZE - m_bitmap_pages;
}
ull PhysicalRange::contiguous_bits_set(ull start, ull count) const
{
for (ull i = 0; i < count; i++)
{
ull off = (start + i) / ull_bits;
ull bit = (start + i) % ull_bits;
if (!(ull_bitmap_ptr()[off] & (1ull << bit)))
return i;
}
return count;
} }
paddr_t PhysicalRange::reserve_page() paddr_t PhysicalRange::reserve_page()
{ {
if (m_free_list == nullptr) ASSERT(free_pages() > 0);
return 0;
node* page = m_free_list; ull ull_count = BAN::Math::div_round_up<ull>(m_data_pages, ull_bits);
ASSERT(page->next == nullptr);
// Detatch page from top of the free list for (ull i = 0; i < ull_count; i++)
m_free_list = m_free_list->prev; {
if (m_free_list) if (ull_bitmap_ptr()[i] == 0)
m_free_list->next = nullptr; continue;
// Add page to used list int lsb = __builtin_ctzll(ull_bitmap_ptr()[i]);
if (m_used_list)
m_used_list->next = page;
page->prev = m_used_list;
m_used_list = page;
m_used_pages++; ull_bitmap_ptr()[i] &= ~(1ull << lsb);
m_free_pages--; m_free_pages--;
return paddr_for_bit(i * ull_bits + lsb);
}
return page_address(page); ASSERT_NOT_REACHED();
} }
void PhysicalRange::release_page(paddr_t page_address) void PhysicalRange::release_page(paddr_t paddr)
{ {
ASSERT(m_used_list); ASSERT(paddr % PAGE_SIZE == 0);
ASSERT(paddr - m_paddr <= m_size);
node* page = node_address(page_address); ull full_bit = bit_for_paddr(paddr);
ull off = full_bit / ull_bits;
ull bit = full_bit % ull_bits;
ull mask = 1ull << bit;
// Detach page from used list ASSERT(!(ull_bitmap_ptr()[off] & mask));
if (page->prev) ull_bitmap_ptr()[off] |= mask;
page->prev->next = page->next;
if (page->next)
page->next->prev = page->prev;
if (m_used_list == page)
m_used_list = page->prev;
// Add page to the top of free list
page->prev = m_free_list;
page->next = nullptr;
if (m_free_list)
m_free_list->next = page;
m_free_list = page;
m_used_pages--;
m_free_pages++; m_free_pages++;
} }
paddr_t PhysicalRange::page_address(const node* page) const paddr_t PhysicalRange::reserve_contiguous_pages(size_t pages)
{ {
ASSERT((vaddr_t)page <= m_vaddr + m_reservable_pages * sizeof(node)); ASSERT(pages > 0);
uint64_t page_index = page - (node*)m_vaddr; ASSERT(free_pages() > 0);
return m_paddr + (page_index + m_list_pages) * PAGE_SIZE;
if (pages == 1)
return reserve_page();
ull ull_count = BAN::Math::div_round_up<ull>(m_data_pages, ull_bits);
// NOTE: This feels kinda slow, but I don't want to be
// doing premature optimization. This will be only
// used when creating DMA regions.
for (ull i = 0; i < ull_count; i++)
{
if (ull_bitmap_ptr()[i] == 0)
continue;
for (ull bit = 0; bit < ull_bits;)
{
ull start = i * ull_bits + bit;
ull set_cnt = contiguous_bits_set(start, pages);
if (set_cnt == pages)
{
for (ull j = 0; j < pages; j++)
ull_bitmap_ptr()[(start + j) / ull_bits] &= ~(1ull << ((start + j) % ull_bits));
m_free_pages -= pages;
return paddr_for_bit(start);
}
bit += set_cnt + 1;
}
}
ASSERT_NOT_REACHED();
} }
PhysicalRange::node* PhysicalRange::node_address(paddr_t page_address) const void PhysicalRange::release_contiguous_pages(paddr_t paddr, size_t pages)
{ {
ASSERT(page_address % PAGE_SIZE == 0); ASSERT(paddr % PAGE_SIZE == 0);
ASSERT(m_paddr + m_list_pages * PAGE_SIZE <= page_address && page_address < m_paddr + m_size); ASSERT(paddr - m_paddr <= m_size);
uint64_t page_offset = page_address - (m_paddr + m_list_pages * PAGE_SIZE); ASSERT(pages > 0);
return (node*)m_vaddr + page_offset / PAGE_SIZE;
ull start_bit = bit_for_paddr(paddr);
for (size_t i = 0; i < pages; i++)
{
ull off = (start_bit + i) / ull_bits;
ull bit = (start_bit + i) % ull_bits;
ull mask = 1ull << bit;
ASSERT(!(ull_bitmap_ptr()[off] & mask));
ull_bitmap_ptr()[off] |= mask;
}
m_free_pages += pages;
} }
} }

View File

@ -3,7 +3,8 @@
#include <kernel/MMIO.h> #include <kernel/MMIO.h>
#include <kernel/Networking/E1000.h> #include <kernel/Networking/E1000.h>
#include <kernel/PCI.h> #include <kernel/PCI.h>
#include <kernel/Storage/ATAController.h> #include <kernel/Storage/ATA/AHCI/Controller.h>
#include <kernel/Storage/ATA/ATAController.h>
#define INVALID_VENDOR 0xFFFF #define INVALID_VENDOR 0xFFFF
#define MULTI_FUNCTION 0x80 #define MULTI_FUNCTION 0x80
@ -143,6 +144,8 @@ namespace Kernel::PCI
switch (pci_device.subclass()) switch (pci_device.subclass())
{ {
case 0x01: case 0x01:
case 0x05:
case 0x06:
if (auto res = ATAController::create(pci_device); res.is_error()) if (auto res = ATAController::create(pci_device); res.is_error())
dprintln("ATA: {}", res.error()); dprintln("ATA: {}", res.error());
break; break;
@ -181,12 +184,12 @@ namespace Kernel::PCI
// disable io/mem space while reading bar // disable io/mem space while reading bar
device.write_dword(0x04, command_status & ~3); device.write_dword(0x04, command_status & ~3);
uint8_t offset = 0x10 + bar_num * 8; uint8_t offset = 0x10 + bar_num * 4;
uint64_t addr = device.read_dword(offset); uint64_t addr = device.read_dword(offset);
device.write_dword(offset, 0xFFFFFFFF); device.write_dword(offset, 0xFFFFFFFF);
uint32_t size = device.read_dword(0x10 + bar_num * 8); uint32_t size = device.read_dword(offset);
size = ~size + 1; size = ~size + 1;
device.write_dword(offset, addr); device.write_dword(offset, addr);
@ -206,7 +209,7 @@ namespace Kernel::PCI
{ {
type = BarType::MEM; type = BarType::MEM;
addr &= 0xFFFFFFF0; addr &= 0xFFFFFFF0;
addr |= (uint64_t)device.read_dword(offset + 8) << 32; addr |= (uint64_t)device.read_dword(offset + 4) << 32;
} }
if (type == BarType::INVALID) if (type == BarType::INVALID)

View File

@ -1,27 +1,31 @@
#include <BAN/ScopeGuard.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/IDT.h> #include <kernel/IDT.h>
#include <kernel/InterruptController.h> #include <kernel/InterruptController.h>
#include <kernel/IO.h> #include <kernel/IO.h>
#include <kernel/LockGuard.h> #include <kernel/LockGuard.h>
#include <kernel/Storage/ATADevice.h> #include <kernel/Storage/ATA/ATABus.h>
#include <kernel/Storage/ATABus.h> #include <kernel/Storage/ATA/ATADefinitions.h>
#include <kernel/Storage/ATADefinitions.h> #include <kernel/Storage/ATA/ATADevice.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
namespace Kernel namespace Kernel
{ {
ATABus* ATABus::create(ATAController& controller, uint16_t base, uint16_t ctrl, uint8_t irq) BAN::ErrorOr<BAN::RefPtr<ATABus>> ATABus::create(uint16_t base, uint16_t ctrl, uint8_t irq)
{ {
ATABus* bus = new ATABus(controller, base, ctrl); auto* bus_ptr = new ATABus(base, ctrl);
ASSERT(bus); if (bus_ptr == nullptr)
bus->initialize(irq); return BAN::Error::from_errno(ENOMEM);
auto bus = BAN::RefPtr<ATABus>::adopt(bus_ptr);
bus->set_irq(irq);
TRY(bus->initialize());
if (bus->m_devices.empty())
return BAN::Error::from_errno(ENODEV);
return bus; return bus;
} }
void ATABus::initialize(uint8_t irq) BAN::ErrorOr<void> ATABus::initialize()
{ {
set_irq(irq);
enable_interrupt(); enable_interrupt();
BAN::Vector<uint16_t> identify_buffer; BAN::Vector<uint16_t> identify_buffer;
@ -29,49 +33,57 @@ namespace Kernel
for (uint8_t i = 0; i < 2; i++) for (uint8_t i = 0; i < 2; i++)
{ {
{ bool is_secondary = (i == 1);
auto* temp_ptr = new ATADevice(*this);
ASSERT(temp_ptr);
m_devices[i] = BAN::RefPtr<ATADevice>::adopt(temp_ptr);
}
ATADevice& device = *m_devices[i];
BAN::ScopeGuard guard([this, i] { m_devices[i] = nullptr; }); DeviceType device_type;
if (auto res = identify(is_secondary, identify_buffer.span()); res.is_error())
auto type = identify(device, identify_buffer.data());
if (type == DeviceType::None)
continue; continue;
else
device_type = res.value();
auto res = device.initialize(type, identify_buffer.data()); auto device_or_error = ATADevice::create(this, device_type, is_secondary, identify_buffer.span());
if (res.is_error())
if (device_or_error.is_error())
{ {
dprintln("{}", res.error()); dprintln("{}", device_or_error.error());
continue; continue;
} }
guard.disable(); auto device = device_or_error.release_value();
device->ref();
TRY(m_devices.push_back(device.ptr()));
} }
// Enable disk interrupts // Enable disk interrupts
for (int i = 0; i < 2; i++) for (auto& device : m_devices)
{ {
if (!m_devices[i]) select_device(device->is_secondary());
continue;
select_device(*m_devices[i]);
io_write(ATA_PORT_CONTROL, 0); io_write(ATA_PORT_CONTROL, 0);
} }
return {};
}
void ATABus::initialize_devfs()
{
for (auto& device : m_devices)
{
DevFileSystem::get().add_device(device);
if (auto res = device->initialize_partitions(); res.is_error())
dprintln("{}", res.error());
device->unref();
}
} }
void ATABus::select_device(const ATADevice& device) void ATABus::select_device(bool secondary)
{ {
uint8_t device_index = this->device_index(device); io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | ((uint8_t)secondary << 4));
io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | (device_index << 4));
SystemTimer::get().sleep(1); SystemTimer::get().sleep(1);
} }
ATABus::DeviceType ATABus::identify(const ATADevice& device, uint16_t* buffer) BAN::ErrorOr<ATABus::DeviceType> ATABus::identify(bool secondary, BAN::Span<uint16_t> buffer)
{ {
select_device(device); select_device(secondary);
// Disable interrupts // Disable interrupts
io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN); io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN);
@ -81,7 +93,7 @@ namespace Kernel
// No device on port // No device on port
if (io_read(ATA_PORT_STATUS) == 0) if (io_read(ATA_PORT_STATUS) == 0)
return DeviceType::None; return BAN::Error::from_errno(EINVAL);
DeviceType type = DeviceType::ATA; DeviceType type = DeviceType::ATA;
@ -97,7 +109,7 @@ namespace Kernel
else else
{ {
dprintln("Unsupported device type"); dprintln("Unsupported device type");
return DeviceType::None; return BAN::Error::from_errno(EINVAL);
} }
io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET); io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET);
@ -106,11 +118,12 @@ namespace Kernel
if (auto res = wait(true); res.is_error()) if (auto res = wait(true); res.is_error())
{ {
dprintln("Fatal error: {}", res.error()); dprintln("Fatal error: {}", res.error());
return DeviceType::None; return BAN::Error::from_errno(EINVAL);
} }
} }
read_buffer(ATA_PORT_DATA, buffer, 256); ASSERT(buffer.size() >= 256);
read_buffer(ATA_PORT_DATA, buffer.data(), 256);
return type; return type;
} }
@ -212,18 +225,9 @@ namespace Kernel
return BAN::Error::from_error_code(ErrorCode::None); return BAN::Error::from_error_code(ErrorCode::None);
} }
uint8_t ATABus::device_index(const ATADevice& device) const
{
if (m_devices[0] && m_devices[0].ptr() == &device)
return 0;
if (m_devices[1] && m_devices[1].ptr() == &device)
return 1;
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<void> ATABus::read(ATADevice& device, uint64_t lba, uint8_t sector_count, uint8_t* buffer) BAN::ErrorOr<void> ATABus::read(ATADevice& device, uint64_t lba, uint8_t sector_count, uint8_t* buffer)
{ {
if (lba + sector_count > device.m_lba_count) if (lba + sector_count > device.sector_count())
return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries); return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries);
LockGuard _(m_lock); LockGuard _(m_lock);
@ -231,7 +235,7 @@ namespace Kernel
if (lba < (1 << 28)) if (lba < (1 << 28))
{ {
// LBA28 // LBA28
io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | (device_index(device) << 4) | ((lba >> 24) & 0x0F)); io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | ((uint8_t)device.is_secondary() << 4) | ((lba >> 24) & 0x0F));
io_write(ATA_PORT_SECTOR_COUNT, sector_count); io_write(ATA_PORT_SECTOR_COUNT, sector_count);
io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0)); io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8)); io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
@ -241,7 +245,7 @@ namespace Kernel
for (uint32_t sector = 0; sector < sector_count; sector++) for (uint32_t sector = 0; sector < sector_count; sector++)
{ {
block_until_irq(); block_until_irq();
read_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device.m_sector_words, device.m_sector_words); read_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device.words_per_sector(), device.words_per_sector());
} }
} }
else else
@ -255,7 +259,7 @@ namespace Kernel
BAN::ErrorOr<void> ATABus::write(ATADevice& device, uint64_t lba, uint8_t sector_count, const uint8_t* buffer) BAN::ErrorOr<void> ATABus::write(ATADevice& device, uint64_t lba, uint8_t sector_count, const uint8_t* buffer)
{ {
if (lba + sector_count > device.m_lba_count) if (lba + sector_count > device.sector_count())
return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries); return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries);
LockGuard _(m_lock); LockGuard _(m_lock);
@ -263,7 +267,7 @@ namespace Kernel
if (lba < (1 << 28)) if (lba < (1 << 28))
{ {
// LBA28 // LBA28
io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | (device_index(device) << 4) | ((lba >> 24) & 0x0F)); io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | ((uint8_t)device.is_secondary() << 4) | ((lba >> 24) & 0x0F));
io_write(ATA_PORT_SECTOR_COUNT, sector_count); io_write(ATA_PORT_SECTOR_COUNT, sector_count);
io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0)); io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8)); io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
@ -274,7 +278,7 @@ namespace Kernel
for (uint32_t sector = 0; sector < sector_count; sector++) for (uint32_t sector = 0; sector < sector_count; sector++)
{ {
write_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device.m_sector_words, device.m_sector_words); write_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device.words_per_sector(), device.words_per_sector());
block_until_irq(); block_until_irq();
} }
} }

View File

@ -0,0 +1,76 @@
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Storage/ATA/ATABus.h>
#include <kernel/Storage/ATA/ATAController.h>
#include <kernel/Storage/ATA/ATADefinitions.h>
#include <kernel/Storage/ATA/ATADevice.h>
namespace Kernel
{
BAN::ErrorOr<BAN::UniqPtr<StorageController>> ATAController::create(PCI::Device& pci_device)
{
StorageController* controller_ptr = nullptr;
switch (pci_device.subclass())
{
case 0x01:
controller_ptr = new ATAController(pci_device);
break;
case 0x05:
dwarnln("unsupported DMA ATA Controller");
return BAN::Error::from_errno(ENOTSUP);
case 0x06:
dwarnln("unsupported SATA Controller");
return BAN::Error::from_errno(ENOTSUP);
default:
ASSERT_NOT_REACHED();
}
if (controller_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto controller = BAN::UniqPtr<StorageController>::adopt(controller_ptr);
TRY(controller->initialize());
return controller;
}
BAN::ErrorOr<void> ATAController::initialize()
{
BAN::Vector<BAN::RefPtr<ATABus>> buses;
uint8_t prog_if = m_pci_device.read_byte(0x09);
if (!(prog_if & ATA_PROGIF_PRIMARY_NATIVE))
{
auto bus_or_error = ATABus::create(0x1F0, 0x3F6, 14);
if (bus_or_error.is_error())
dprintln("IDE ATABus: {}", bus_or_error.error());
else
TRY(buses.push_back(bus_or_error.release_value()));
}
else
{
dprintln("unsupported IDE ATABus in native mode");
}
// BUS 2
if (!(prog_if & ATA_PROGIF_SECONDARY_NATIVE))
{
auto bus_or_error = ATABus::create(0x170, 0x376, 15);
if (bus_or_error.is_error())
dprintln("IDE ATABus: {}", bus_or_error.error());
else
TRY(buses.push_back(bus_or_error.release_value()));
}
else
{
dprintln("unsupported IDE ATABus in native mode");
}
for (auto& bus : buses)
bus->initialize_devfs();
return {};
}
}

View File

@ -0,0 +1,117 @@
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/IO.h>
#include <kernel/Storage/ATA/ATABus.h>
#include <kernel/Storage/ATA/ATADefinitions.h>
#include <kernel/Storage/ATA/ATADevice.h>
#include <sys/sysmacros.h>
namespace Kernel
{
static dev_t get_ata_dev_major()
{
static dev_t major = DevFileSystem::get().get_next_dev();
return major;
}
static dev_t get_ata_dev_minor()
{
static dev_t minor = 0;
return minor++;
}
BAN::ErrorOr<BAN::RefPtr<ATADevice>> ATADevice::create(BAN::RefPtr<ATABus> bus, ATABus::DeviceType type, bool is_secondary, BAN::Span<const uint16_t> identify_data)
{
auto* device_ptr = new ATADevice(bus, type, is_secondary);
if (device_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto device = BAN::RefPtr<ATADevice>::adopt(device_ptr);
TRY(device->initialize(identify_data));
return device;
}
ATADevice::ATADevice(BAN::RefPtr<ATABus> bus, ATABus::DeviceType type, bool is_secondary)
: m_bus(bus)
, m_type(type)
, m_is_secondary(is_secondary)
, m_rdev(makedev(get_ata_dev_major(), get_ata_dev_minor()))
{ }
BAN::ErrorOr<void> ATADevice::initialize(BAN::Span<const uint16_t> identify_data)
{
ASSERT(identify_data.size() >= 256);
m_signature = identify_data[ATA_IDENTIFY_SIGNATURE];
m_capabilities = identify_data[ATA_IDENTIFY_CAPABILITIES];
m_command_set = 0;
m_command_set |= (uint32_t)(identify_data[ATA_IDENTIFY_COMMAND_SET + 0] << 0);
m_command_set |= (uint32_t)(identify_data[ATA_IDENTIFY_COMMAND_SET + 1] << 16);
if (!(m_capabilities & ATA_CAPABILITIES_LBA))
return BAN::Error::from_error_code(ErrorCode::ATA_NoLBA);
if ((identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 &&
(identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 &&
(identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0)
{
m_sector_words = *(uint32_t*)(identify_data.data() + ATA_IDENTIFY_SECTOR_WORDS);
}
else
{
m_sector_words = 256;
}
m_lba_count = 0;
if (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED)
m_lba_count = *(uint64_t*)(identify_data.data() + ATA_IDENTIFY_LBA_COUNT_EXT);
if (m_lba_count < (1 << 28))
m_lba_count = *(uint32_t*)(identify_data.data() + ATA_IDENTIFY_LBA_COUNT);
for (int i = 0; i < 20; i++)
{
uint16_t word = identify_data[ATA_IDENTIFY_MODEL + i];
m_model[2 * i + 0] = word >> 8;
m_model[2 * i + 1] = word & 0xFF;
}
m_model[40] = 0;
dprintln("ATA disk {} MB", total_size() / 1024 / 1024);
add_disk_cache();
return {};
}
BAN::ErrorOr<void> ATADevice::read_sectors_impl(uint64_t lba, uint8_t sector_count, uint8_t* buffer)
{
TRY(m_bus->read(*this, lba, sector_count, buffer));
return {};
}
BAN::ErrorOr<void> ATADevice::write_sectors_impl(uint64_t lba, uint8_t sector_count, const uint8_t* buffer)
{
TRY(m_bus->write(*this, lba, sector_count, buffer));
return {};
}
BAN::ErrorOr<size_t> ATADevice::read_impl(off_t offset, void* buffer, size_t bytes)
{
ASSERT(offset >= 0);
if (offset % sector_size() || bytes % sector_size())
return BAN::Error::from_errno(EINVAL);
if ((size_t)offset == total_size())
return 0;
TRY(read_sectors(offset / sector_size(), bytes / sector_size(), (uint8_t*)buffer));
return bytes;
}
BAN::StringView ATADevice::name() const
{
static char device_name[] = "sda";
device_name[2] += minor(m_rdev);
return device_name;
}
}

View File

@ -1,102 +0,0 @@
#include <BAN/ScopeGuard.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/LockGuard.h>
#include <kernel/Storage/ATABus.h>
#include <kernel/Storage/ATAController.h>
#include <kernel/Storage/ATADefinitions.h>
#include <kernel/Storage/ATADevice.h>
#include <sys/sysmacros.h>
namespace Kernel
{
BAN::ErrorOr<BAN::RefPtr<ATAController>> ATAController::create(const PCI::Device& device)
{
ATAController* controller = new ATAController();
if (controller == nullptr)
return BAN::Error::from_errno(ENOMEM);
BAN::ScopeGuard guard([controller] { controller->unref(); });
TRY(controller->initialize(device));
guard.disable();
auto ref_ptr = BAN::RefPtr<ATAController>::adopt(controller);
DevFileSystem::get().add_device("hd"sv, ref_ptr);
auto devices = controller->devices();
for (size_t i = 0; i < devices.size(); i++)
{
char device_name[4] { 'h', 'd', (char)('a' + i), '\0' };
DevFileSystem::get().add_device(device_name, devices[i]);
if (auto res = devices[i]->initialize_partitions(); res.is_error())
dprintln("{}", res.error());
else
{
auto& partitions = devices[i]->partitions();
for (size_t j = 0; j < partitions.size(); j++)
{
char partition_name[5] { 'h', 'd', (char)('a' + i), (char)('1' + j), '\0' };
DevFileSystem::get().add_device(partition_name, partitions[j]);
}
}
}
return ref_ptr;
}
ATAController::ATAController()
: m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0))
{ }
BAN::ErrorOr<void> ATAController::initialize(const PCI::Device& pci_device)
{
struct Bus
{
uint16_t base;
uint16_t ctrl;
};
Bus buses[2];
buses[0].base = 0x1F0;
buses[0].ctrl = 0x3F6;
buses[1].base = 0x170;
buses[1].ctrl = 0x376;
uint8_t prog_if = pci_device.read_byte(0x09);
if (prog_if & 0x01)
{
buses[0].base = pci_device.read_dword(0x10) & 0xFFFFFFFC;
buses[0].ctrl = pci_device.read_dword(0x14) & 0xFFFFFFFC;
return BAN::Error::from_error_code(ErrorCode::ATA_UnsupportedDevice);
}
if (prog_if & 0x04)
{
buses[1].base = pci_device.read_dword(0x18) & 0xFFFFFFFC;
buses[1].ctrl = pci_device.read_dword(0x1C) & 0xFFFFFFFC;
return BAN::Error::from_error_code(ErrorCode::ATA_UnsupportedDevice);
}
m_buses[0] = ATABus::create(*this, buses[0].base, buses[0].ctrl, 14);
m_buses[1] = ATABus::create(*this, buses[1].base, buses[1].ctrl, 15);
return {};
}
BAN::Vector<BAN::RefPtr<StorageDevice>> ATAController::devices()
{
BAN::Vector<BAN::RefPtr<StorageDevice>> devices;
if (m_buses[0]->m_devices[0])
MUST(devices.push_back(m_buses[0]->m_devices[0]));
if (m_buses[0]->m_devices[1])
MUST(devices.push_back(m_buses[0]->m_devices[1]));
if (m_buses[1]->m_devices[0])
MUST(devices.push_back(m_buses[1]->m_devices[0]));
if (m_buses[1]->m_devices[1])
MUST(devices.push_back(m_buses[1]->m_devices[1]));
return devices;
}
}

View File

@ -1,86 +0,0 @@
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/IO.h>
#include <kernel/Storage/ATABus.h>
#include <kernel/Storage/ATADefinitions.h>
#include <kernel/Storage/ATADevice.h>
#include <sys/sysmacros.h>
namespace Kernel
{
ATADevice::ATADevice(ATABus& bus)
: m_bus(bus)
, m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0))
{ }
BAN::ErrorOr<void> ATADevice::initialize(ATABus::DeviceType type, const uint16_t* identify_buffer)
{
m_type = type;
m_signature = identify_buffer[ATA_IDENTIFY_SIGNATURE];
m_capabilities = identify_buffer[ATA_IDENTIFY_CAPABILITIES];
m_command_set = 0;
m_command_set |= (uint32_t)(identify_buffer[ATA_IDENTIFY_COMMAND_SET + 0] << 0);
m_command_set |= (uint32_t)(identify_buffer[ATA_IDENTIFY_COMMAND_SET + 1] << 16);
if (!(m_capabilities & ATA_CAPABILITIES_LBA))
return BAN::Error::from_error_code(ErrorCode::ATA_NoLBA);
if ((identify_buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 &&
(identify_buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 &&
(identify_buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0)
{
m_sector_words = *(uint32_t*)(identify_buffer + ATA_IDENTIFY_SECTOR_WORDS);
}
else
{
m_sector_words = 256;
}
m_lba_count = 0;
if (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED)
m_lba_count = *(uint64_t*)(identify_buffer + ATA_IDENTIFY_LBA_COUNT_EXT);
if (m_lba_count < (1 << 28))
m_lba_count = *(uint32_t*)(identify_buffer + ATA_IDENTIFY_LBA_COUNT);
for (int i = 0; i < 20; i++)
{
uint16_t word = identify_buffer[ATA_IDENTIFY_MODEL + i];
m_model[2 * i + 0] = word >> 8;
m_model[2 * i + 1] = word & 0xFF;
}
m_model[40] = 0;
dprintln("ATA disk {} MB", total_size() / 1024 / 1024);
add_disk_cache();
return {};
}
BAN::ErrorOr<void> ATADevice::read_sectors_impl(uint64_t lba, uint8_t sector_count, uint8_t* buffer)
{
TRY(m_bus.read(*this, lba, sector_count, buffer));
return {};
}
BAN::ErrorOr<void> ATADevice::write_sectors_impl(uint64_t lba, uint8_t sector_count, const uint8_t* buffer)
{
TRY(m_bus.write(*this, lba, sector_count, buffer));
return {};
}
BAN::ErrorOr<size_t> ATADevice::read_impl(off_t offset, void* buffer, size_t bytes)
{
ASSERT(offset >= 0);
if (offset % sector_size() || bytes % sector_size())
return BAN::Error::from_errno(EINVAL);
if ((size_t)offset == total_size())
return 0;
TRY(read_sectors(offset / sector_size(), bytes / sector_size(), (uint8_t*)buffer));
return bytes;
}
}

View File

@ -2,6 +2,7 @@
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
#include <BAN/StringView.h> #include <BAN/StringView.h>
#include <BAN/UTF8.h> #include <BAN/UTF8.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/LockGuard.h> #include <kernel/LockGuard.h>
#include <kernel/PCI.h> #include <kernel/PCI.h>
@ -184,7 +185,7 @@ namespace Kernel
char utf8_name[36 * 4 + 1]; char utf8_name[36 * 4 + 1];
BAN::UTF8::from_codepoints(entry.partition_name, 36, utf8_name); BAN::UTF8::from_codepoints(entry.partition_name, 36, utf8_name);
Partition* partition = new Partition( auto partition = TRY(Partition::create(
*this, *this,
entry.partition_type_guid, entry.partition_type_guid,
entry.unique_partition_guid, entry.unique_partition_guid,
@ -193,14 +194,24 @@ namespace Kernel
entry.attributes, entry.attributes,
utf8_name, utf8_name,
i + 1 i + 1
); ));
ASSERT(partition != nullptr); TRY(m_partitions.push_back(BAN::move(partition)));
MUST(m_partitions.push_back(partition));
} }
for (auto partition : m_partitions)
DevFileSystem::get().add_device(partition);
return {}; return {};
} }
BAN::ErrorOr<BAN::RefPtr<Partition>> Partition::create(StorageDevice& device, const GUID& type, const GUID& guid, uint64_t start, uint64_t end, uint64_t attr, const char* label, uint32_t index)
{
auto partition_ptr = new Partition(device, type, guid, start, end, attr, label, index);
if (partition_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<Partition>::adopt(partition_ptr);
}
Partition::Partition(StorageDevice& device, const GUID& type, const GUID& guid, uint64_t start, uint64_t end, uint64_t attr, const char* label, uint32_t index) Partition::Partition(StorageDevice& device, const GUID& type, const GUID& guid, uint64_t start, uint64_t end, uint64_t attr, const char* label, uint32_t index)
: BlockDevice(0660, 0, 0) : BlockDevice(0660, 0, 0)
, m_device(device) , m_device(device)
@ -209,6 +220,7 @@ namespace Kernel
, m_lba_start(start) , m_lba_start(start)
, m_lba_end(end) , m_lba_end(end)
, m_attributes(attr) , m_attributes(attr)
, m_name(BAN::String::formatted("{}{}", device.name(), index))
, m_rdev(makedev(major(device.rdev()), index)) , m_rdev(makedev(major(device.rdev()), index))
{ {
memcpy(m_label, label, sizeof(m_label)); memcpy(m_label, label, sizeof(m_label));

View File

@ -202,7 +202,7 @@ namespace Kernel
} }
auto ref_ptr = BAN::RefPtr<SerialTTY>::adopt(tty); auto ref_ptr = BAN::RefPtr<SerialTTY>::adopt(tty);
DevFileSystem::get().add_device(ref_ptr->name(), ref_ptr); DevFileSystem::get().add_device(ref_ptr);
if (serial.port() == COM1_PORT) if (serial.port() == COM1_PORT)
s_com1 = ref_ptr; s_com1 = ref_ptr;
if (serial.port() == COM2_PORT) if (serial.port() == COM2_PORT)

View File

@ -28,11 +28,11 @@ namespace Kernel
{ {
s_tty = this; s_tty = this;
auto inode_or_error = DevFileSystem::get().root_inode()->find_inode("tty"); auto inode_or_error = DevFileSystem::get().root_inode()->find_inode("tty"sv);
if (inode_or_error.is_error()) if (inode_or_error.is_error())
{ {
if (inode_or_error.error().get_error_code() == ENOENT) if (inode_or_error.error().get_error_code() == ENOENT)
DevFileSystem::get().add_device("tty"sv, MUST(RamSymlinkInode::create(DevFileSystem::get(), s_tty->name(), 0666, 0, 0))); DevFileSystem::get().add_inode("tty"sv, MUST(RamSymlinkInode::create(DevFileSystem::get(), s_tty->name(), 0666, 0, 0)));
else else
dwarnln("{}", inode_or_error.error()); dwarnln("{}", inode_or_error.error());
return; return;

View File

@ -33,12 +33,12 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> VirtualTTY::create(TerminalDriver* driver) BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> VirtualTTY::create(TerminalDriver* driver)
{ {
auto* tty = new VirtualTTY(driver); auto* tty_ptr = new VirtualTTY(driver);
ASSERT(tty); ASSERT(tty_ptr);
auto ref_ptr = BAN::RefPtr<VirtualTTY>::adopt(tty); auto tty = BAN::RefPtr<VirtualTTY>::adopt(tty_ptr);
DevFileSystem::get().add_device(ref_ptr->name(), ref_ptr); DevFileSystem::get().add_device(tty);
return ref_ptr; return tty;
} }
VirtualTTY::VirtualTTY(TerminalDriver* driver) VirtualTTY::VirtualTTY(TerminalDriver* driver)

View File

@ -177,6 +177,7 @@ static void init2(void*)
dprintln("PCI initialized"); dprintln("PCI initialized");
VirtualFileSystem::initialize(cmdline.root); VirtualFileSystem::initialize(cmdline.root);
dprintln("VFS initialized");
if (auto res = PS2Controller::initialize(); res.is_error()) if (auto res = PS2Controller::initialize(); res.is_error())
dprintln("{}", res.error()); dprintln("{}", res.error());