forked from Bananymous/banan-os
				
			
			update main #1
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -13,7 +13,7 @@ namespace Kernel
 | 
			
		|||
	class E1000 final : public NetworkDriver
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::UniqPtr<E1000>> create(const PCIDevice&);
 | 
			
		||||
		static BAN::ErrorOr<BAN::UniqPtr<E1000>> create(PCI::Device&);
 | 
			
		||||
		~E1000();
 | 
			
		||||
 | 
			
		||||
		virtual uint8_t* get_mac_address() override { return m_mac_address; }
 | 
			
		||||
| 
						 | 
				
			
			@ -24,12 +24,12 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
	private:
 | 
			
		||||
		E1000() = default;
 | 
			
		||||
		BAN::ErrorOr<void> initialize(const PCIDevice&);
 | 
			
		||||
		BAN::ErrorOr<void> initialize(PCI::Device&);
 | 
			
		||||
 | 
			
		||||
		static void interrupt_handler();
 | 
			
		||||
 | 
			
		||||
		void write32(uint16_t reg, uint32_t value);
 | 
			
		||||
		uint32_t read32(uint16_t reg);
 | 
			
		||||
		void write32(uint16_t reg, uint32_t value);
 | 
			
		||||
 | 
			
		||||
		void detect_eeprom();
 | 
			
		||||
		uint32_t eeprom_read(uint8_t addr);
 | 
			
		||||
| 
						 | 
				
			
			@ -44,8 +44,7 @@ namespace Kernel
 | 
			
		|||
		void handle_receive();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		PCIDevice::BarType		m_bar_type {};
 | 
			
		||||
		uint64_t				m_bar_addr {};
 | 
			
		||||
		BAN::UniqPtr<PCI::BarRegion> m_bar_region;
 | 
			
		||||
		bool					m_has_eerprom { false };
 | 
			
		||||
		uint8_t					m_mac_address[6] {};
 | 
			
		||||
		uint16_t				m_rx_current {};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,28 +1,63 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <BAN/UniqPtr.h>
 | 
			
		||||
#include <BAN/Vector.h>
 | 
			
		||||
#include <kernel/Memory/Types.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
namespace Kernel::PCI
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class PCIDevice
 | 
			
		||||
	enum class BarType
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		enum class BarType
 | 
			
		||||
		{
 | 
			
		||||
			INVAL,
 | 
			
		||||
			MEM,
 | 
			
		||||
			IO,
 | 
			
		||||
		};
 | 
			
		||||
		INVALID,
 | 
			
		||||
		MEM,
 | 
			
		||||
		IO,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class Device;
 | 
			
		||||
 | 
			
		||||
	class BarRegion
 | 
			
		||||
	{
 | 
			
		||||
		BAN_NON_COPYABLE(BarRegion);
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		PCIDevice(uint8_t, uint8_t, uint8_t);
 | 
			
		||||
		static BAN::ErrorOr<BAN::UniqPtr<BarRegion>> create(PCI::Device&, uint8_t bar_num);
 | 
			
		||||
		~BarRegion();
 | 
			
		||||
 | 
			
		||||
		BarType type() const { return m_type; }
 | 
			
		||||
		vaddr_t vaddr() const { return m_vaddr; }
 | 
			
		||||
		paddr_t paddr() const { return m_paddr; }
 | 
			
		||||
		size_t size() const { return m_size; }
 | 
			
		||||
 | 
			
		||||
		void write8(off_t, uint8_t);
 | 
			
		||||
		void write16(off_t, uint16_t);
 | 
			
		||||
		void write32(off_t, uint32_t);
 | 
			
		||||
 | 
			
		||||
		uint8_t read8(off_t);
 | 
			
		||||
		uint16_t read16(off_t);
 | 
			
		||||
		uint32_t read32(off_t);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		BarRegion(BarType, paddr_t, size_t);
 | 
			
		||||
		BAN::ErrorOr<void> initialize();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		const BarType	m_type	{};
 | 
			
		||||
		const paddr_t	m_paddr	{};
 | 
			
		||||
		const size_t	m_size	{};
 | 
			
		||||
		vaddr_t			m_vaddr	{};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class Device
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Device(uint8_t, uint8_t, uint8_t);
 | 
			
		||||
 | 
			
		||||
		uint32_t read_dword(uint8_t) const;
 | 
			
		||||
		uint16_t read_word(uint8_t) const;
 | 
			
		||||
		uint8_t  read_byte(uint8_t) const;
 | 
			
		||||
 | 
			
		||||
		void write_dword(uint8_t, uint32_t) const;
 | 
			
		||||
		void write_dword(uint8_t, uint32_t);
 | 
			
		||||
 | 
			
		||||
		uint8_t bus() const { return m_bus; }
 | 
			
		||||
		uint8_t dev() const { return m_dev; }
 | 
			
		||||
| 
						 | 
				
			
			@ -32,17 +67,24 @@ namespace Kernel
 | 
			
		|||
		uint8_t subclass() const { return m_subclass; }
 | 
			
		||||
		uint8_t prog_if() const { return m_prog_if; }
 | 
			
		||||
 | 
			
		||||
		BarType read_bar_type(uint8_t) const;
 | 
			
		||||
		uint64_t read_bar_address(uint8_t) const;
 | 
			
		||||
		uint8_t header_type() const { return m_header_type; }
 | 
			
		||||
 | 
			
		||||
		void enable_bus_mastering() const;
 | 
			
		||||
		void disable_bus_mastering() const;
 | 
			
		||||
		BAN::ErrorOr<BAN::UniqPtr<BarRegion>> allocate_bar_region(uint8_t bar_num);
 | 
			
		||||
 | 
			
		||||
		void enable_memory_space() const;
 | 
			
		||||
		void disable_memory_space() const;
 | 
			
		||||
		void enable_bus_mastering();
 | 
			
		||||
		void disable_bus_mastering();
 | 
			
		||||
 | 
			
		||||
		void enable_pin_interrupts() const;
 | 
			
		||||
		void disable_pin_interrupts() const;
 | 
			
		||||
		void enable_memory_space();
 | 
			
		||||
		void disable_memory_space();
 | 
			
		||||
 | 
			
		||||
		void enable_io_space();
 | 
			
		||||
		void disable_io_space();
 | 
			
		||||
 | 
			
		||||
		void enable_pin_interrupts();
 | 
			
		||||
		void disable_pin_interrupts();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void enumerate_capabilites();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		uint8_t m_bus;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,19 +98,19 @@ namespace Kernel
 | 
			
		|||
		uint8_t m_header_type;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class PCI
 | 
			
		||||
	class PCIManager
 | 
			
		||||
	{
 | 
			
		||||
		BAN_NON_COPYABLE(PCI);
 | 
			
		||||
		BAN_NON_MOVABLE(PCI);
 | 
			
		||||
		BAN_NON_COPYABLE(PCIManager);
 | 
			
		||||
		BAN_NON_MOVABLE(PCIManager);
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		static void initialize();
 | 
			
		||||
		static PCI& get();
 | 
			
		||||
		static PCIManager& get();
 | 
			
		||||
		
 | 
			
		||||
		const BAN::Vector<PCIDevice>& devices() const { return m_devices; }
 | 
			
		||||
		const BAN::Vector<PCI::Device>& devices() const { return m_devices; }
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		PCI() = default;
 | 
			
		||||
		PCIManager() = default;
 | 
			
		||||
		void check_function(uint8_t bus, uint8_t dev, uint8_t func);
 | 
			
		||||
		void check_device(uint8_t bus, uint8_t dev);
 | 
			
		||||
		void check_bus(uint8_t bus);
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +118,7 @@ namespace Kernel
 | 
			
		|||
		void initialize_devices();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		BAN::Vector<PCIDevice> m_devices;
 | 
			
		||||
		BAN::Vector<PCI::Device> m_devices;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -11,13 +11,13 @@ namespace Kernel
 | 
			
		|||
	class ATAController final : public StorageController
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::RefPtr<ATAController>> create(const PCIDevice&);
 | 
			
		||||
		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 PCIDevice& device);
 | 
			
		||||
		BAN::ErrorOr<void> initialize(const PCI::Device& device);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		ATABus* m_buses[2] { nullptr, nullptr };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
#include <kernel/MMIO.h>
 | 
			
		||||
#include <kernel/Networking/E1000.h>
 | 
			
		||||
 | 
			
		||||
#define E1000_GENERAL_MEM_SIZE		(128 * 1024)
 | 
			
		||||
#define DEBUG_E1000 1
 | 
			
		||||
 | 
			
		||||
#define E1000_REG_CTRL				0x0000
 | 
			
		||||
#define E1000_REG_STATUS			0x0008
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +112,7 @@ namespace Kernel
 | 
			
		|||
		volatile uint16_t special;
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<E1000>> E1000::create(const PCIDevice& pci_device)
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<E1000>> E1000::create(PCI::Device& pci_device)
 | 
			
		||||
	{
 | 
			
		||||
		E1000* e1000 = new E1000();
 | 
			
		||||
		ASSERT(e1000);
 | 
			
		||||
| 
						 | 
				
			
			@ -126,42 +126,26 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
	E1000::~E1000()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_bar_type == PCIDevice::BarType::MEM && m_bar_addr)
 | 
			
		||||
			PageTable::kernel().unmap_range(m_bar_addr & PAGE_ADDR_MASK, E1000_GENERAL_MEM_SIZE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> E1000::initialize(const PCIDevice& pci_device)
 | 
			
		||||
	BAN::ErrorOr<void> E1000::initialize(PCI::Device& pci_device)
 | 
			
		||||
	{
 | 
			
		||||
		m_bar_type = pci_device.read_bar_type(0);
 | 
			
		||||
		if (m_bar_type == PCIDevice::BarType::INVAL)
 | 
			
		||||
		{
 | 
			
		||||
			dwarnln("invalid bar0 type");
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (m_bar_type == PCIDevice::BarType::MEM)
 | 
			
		||||
		{
 | 
			
		||||
			uint64_t bar_addr = pci_device.read_bar_address(0);
 | 
			
		||||
 | 
			
		||||
			vaddr_t page_vaddr = PageTable::kernel().reserve_free_contiguous_pages(E1000_GENERAL_MEM_SIZE / PAGE_SIZE, KERNEL_OFFSET);
 | 
			
		||||
			paddr_t page_paddr = bar_addr & PAGE_ADDR_MASK;
 | 
			
		||||
			PageTable::kernel().map_range_at(page_paddr, page_vaddr, E1000_GENERAL_MEM_SIZE, PageTable::Flags::CacheDisable | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
 | 
			
		||||
 | 
			
		||||
			m_bar_addr = page_vaddr + (bar_addr % PAGE_SIZE);
 | 
			
		||||
		}
 | 
			
		||||
		else if (m_bar_type == PCIDevice::BarType::IO)
 | 
			
		||||
		{
 | 
			
		||||
			m_bar_addr = pci_device.read_bar_address(0);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		m_bar_region = TRY(pci_device.allocate_bar_region(0));
 | 
			
		||||
		pci_device.enable_bus_mastering();
 | 
			
		||||
 | 
			
		||||
		detect_eeprom();
 | 
			
		||||
 | 
			
		||||
		TRY(read_mac_address());
 | 
			
		||||
		
 | 
			
		||||
		dprintln("E1000 at PCI {}:{}.{}", pci_device.bus(), pci_device.dev(), pci_device.func());
 | 
			
		||||
 | 
			
		||||
		initialize_rx();
 | 
			
		||||
		initialize_tx();
 | 
			
		||||
 | 
			
		||||
		enable_link();
 | 
			
		||||
		enable_interrupts();
 | 
			
		||||
		
 | 
			
		||||
#if DEBUG_E1000
 | 
			
		||||
		dprintln("E1000 at PCI {}:{}.{}", pci_device.bus(), pci_device.dev(), pci_device.func());
 | 
			
		||||
		dprintln("  MAC: {2H}:{2H}:{2H}:{2H}:{2H}:{2H}",
 | 
			
		||||
			m_mac_address[0],
 | 
			
		||||
			m_mac_address[1],
 | 
			
		||||
| 
						 | 
				
			
			@ -170,52 +154,22 @@ namespace Kernel
 | 
			
		|||
			m_mac_address[4],
 | 
			
		||||
			m_mac_address[5]
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		initialize_rx();
 | 
			
		||||
		initialize_tx();
 | 
			
		||||
 | 
			
		||||
		enable_link();
 | 
			
		||||
		enable_interrupts();
 | 
			
		||||
		
 | 
			
		||||
		dprintln("  link up: {}", link_up());
 | 
			
		||||
		if (link_up())
 | 
			
		||||
			dprintln("  link speed: {} Mbps", link_speed());
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void E1000::write32(uint16_t reg, uint32_t value)
 | 
			
		||||
	{
 | 
			
		||||
		switch (m_bar_type)
 | 
			
		||||
		{
 | 
			
		||||
			case PCIDevice::BarType::MEM:
 | 
			
		||||
				MMIO::write32(m_bar_addr + reg, value);
 | 
			
		||||
				break;
 | 
			
		||||
			case PCIDevice::BarType::IO:
 | 
			
		||||
				IO::outl(m_bar_addr, reg);
 | 
			
		||||
				IO::outl(m_bar_addr + 4, value);
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				ASSERT_NOT_REACHED();
 | 
			
		||||
		}
 | 
			
		||||
		m_bar_region->write32(reg, value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t E1000::read32(uint16_t reg)
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t result = 0;
 | 
			
		||||
		switch (m_bar_type)
 | 
			
		||||
		{
 | 
			
		||||
			case PCIDevice::BarType::MEM:
 | 
			
		||||
				result = MMIO::read32(m_bar_addr + reg);
 | 
			
		||||
				break;
 | 
			
		||||
			case PCIDevice::BarType::IO:
 | 
			
		||||
				IO::outl(m_bar_addr, reg);
 | 
			
		||||
				result = IO::inl(m_bar_addr + 4);
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				ASSERT_NOT_REACHED();
 | 
			
		||||
		}
 | 
			
		||||
		return result;
 | 
			
		||||
		return m_bar_region->read32(reg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void E1000::detect_eeprom()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,33 +1,22 @@
 | 
			
		|||
#include <kernel/IO.h>
 | 
			
		||||
#include <kernel/Memory/PageTable.h>
 | 
			
		||||
#include <kernel/MMIO.h>
 | 
			
		||||
#include <kernel/Networking/E1000.h>
 | 
			
		||||
#include <kernel/PCI.h>
 | 
			
		||||
#include <kernel/Storage/ATAController.h>
 | 
			
		||||
 | 
			
		||||
#define INVALID 0xFFFF
 | 
			
		||||
#define INVALID_VENDOR 0xFFFF
 | 
			
		||||
#define MULTI_FUNCTION 0x80
 | 
			
		||||
 | 
			
		||||
#define CONFIG_ADDRESS 0xCF8
 | 
			
		||||
#define CONFIG_DATA 0xCFC
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
#define DEBUG_PCI 1
 | 
			
		||||
 | 
			
		||||
namespace Kernel::PCI
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	static PCI* s_instance = nullptr;
 | 
			
		||||
 | 
			
		||||
	void PCI::initialize()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(s_instance == nullptr);
 | 
			
		||||
		s_instance = new PCI();
 | 
			
		||||
		ASSERT(s_instance);
 | 
			
		||||
		s_instance->check_all_buses();
 | 
			
		||||
		s_instance->initialize_devices();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	PCI& PCI::get()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(s_instance);
 | 
			
		||||
		return *s_instance;
 | 
			
		||||
	}
 | 
			
		||||
	static PCIManager* s_instance = nullptr;
 | 
			
		||||
 | 
			
		||||
	static uint32_t read_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +44,22 @@ namespace Kernel
 | 
			
		|||
		return (dword >> 16) & 0xFF;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCI::check_function(uint8_t bus, uint8_t dev, uint8_t func)
 | 
			
		||||
	void PCIManager::initialize()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(s_instance == nullptr);
 | 
			
		||||
		s_instance = new PCIManager();
 | 
			
		||||
		ASSERT(s_instance);
 | 
			
		||||
		s_instance->check_all_buses();
 | 
			
		||||
		s_instance->initialize_devices();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	PCIManager& PCIManager::get()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(s_instance);
 | 
			
		||||
		return *s_instance;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCIManager::check_function(uint8_t bus, uint8_t dev, uint8_t func)
 | 
			
		||||
	{
 | 
			
		||||
		MUST(m_devices.emplace_back(bus, dev, func));
 | 
			
		||||
		auto& device = m_devices.back();
 | 
			
		||||
| 
						 | 
				
			
			@ -63,29 +67,29 @@ namespace Kernel
 | 
			
		|||
			check_bus(device.read_byte(0x19));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCI::check_device(uint8_t bus, uint8_t dev)
 | 
			
		||||
	void PCIManager::check_device(uint8_t bus, uint8_t dev)
 | 
			
		||||
	{
 | 
			
		||||
		if (get_vendor_id(bus, dev, 0) == INVALID)
 | 
			
		||||
		if (get_vendor_id(bus, dev, 0) == INVALID_VENDOR)
 | 
			
		||||
			return;
 | 
			
		||||
		
 | 
			
		||||
		check_function(bus, dev, 0);
 | 
			
		||||
		if (get_header_type(bus, dev, 0) & MULTI_FUNCTION)
 | 
			
		||||
			for (uint8_t func = 1; func < 8; func++)
 | 
			
		||||
				if (get_vendor_id(bus, dev, func) != INVALID)
 | 
			
		||||
				if (get_vendor_id(bus, dev, func) != INVALID_VENDOR)
 | 
			
		||||
					check_function(bus, dev, func);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCI::check_bus(uint8_t bus)
 | 
			
		||||
	void PCIManager::check_bus(uint8_t bus)
 | 
			
		||||
	{
 | 
			
		||||
		for (uint8_t dev = 0; dev < 32; dev++)
 | 
			
		||||
			check_device(bus, dev);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCI::check_all_buses()
 | 
			
		||||
	void PCIManager::check_all_buses()
 | 
			
		||||
	{
 | 
			
		||||
		if (get_header_type(0, 0, 0) & MULTI_FUNCTION)
 | 
			
		||||
		{
 | 
			
		||||
			for (int func = 0; func < 8 && get_vendor_id(0, 0, func) != INVALID; func++)
 | 
			
		||||
			for (int func = 0; func < 8 && get_vendor_id(0, 0, func) != INVALID_VENDOR; func++)
 | 
			
		||||
				check_bus(func);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
| 
						 | 
				
			
			@ -94,9 +98,9 @@ namespace Kernel
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCI::initialize_devices()
 | 
			
		||||
	void PCIManager::initialize_devices()
 | 
			
		||||
	{
 | 
			
		||||
		for (const auto& pci_device : PCI::get().devices())
 | 
			
		||||
		for (auto& pci_device : m_devices)
 | 
			
		||||
		{
 | 
			
		||||
			switch (pci_device.class_code())
 | 
			
		||||
			{
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +138,144 @@ namespace Kernel
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	PCIDevice::PCIDevice(uint8_t bus, uint8_t dev, uint8_t func)
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<BarRegion>> BarRegion::create(PCI::Device& device, uint8_t bar_num)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(device.header_type() == 0x00);
 | 
			
		||||
 | 
			
		||||
		uint32_t command_status = device.read_dword(0x04);
 | 
			
		||||
 | 
			
		||||
		// disable io/mem space while reading bar
 | 
			
		||||
		device.write_dword(0x04, command_status & ~3);
 | 
			
		||||
 | 
			
		||||
		uint8_t offset = 0x10 + bar_num * 8;
 | 
			
		||||
 | 
			
		||||
		uint64_t addr = device.read_dword(offset);
 | 
			
		||||
 | 
			
		||||
		device.write_dword(offset, 0xFFFFFFFF);
 | 
			
		||||
		uint32_t size = device.read_dword(0x10 + bar_num * 8);
 | 
			
		||||
		size = ~size + 1;
 | 
			
		||||
		device.write_dword(offset, addr);
 | 
			
		||||
 | 
			
		||||
		// determine bar type
 | 
			
		||||
		BarType type = BarType::INVALID;
 | 
			
		||||
		if (addr & 1)
 | 
			
		||||
		{
 | 
			
		||||
			type = BarType::IO;
 | 
			
		||||
			addr &= 0xFFFFFFFC;
 | 
			
		||||
		}
 | 
			
		||||
		else if ((addr & 0b110) == 0b000)
 | 
			
		||||
		{
 | 
			
		||||
			type = BarType::MEM;
 | 
			
		||||
			addr &= 0xFFFFFFF0;
 | 
			
		||||
		}
 | 
			
		||||
		else if ((addr & 0b110) == 0b100)
 | 
			
		||||
		{
 | 
			
		||||
			type = BarType::MEM;
 | 
			
		||||
			addr &= 0xFFFFFFF0;
 | 
			
		||||
			addr |= (uint64_t)device.read_dword(offset + 8) << 32;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (type == BarType::INVALID)
 | 
			
		||||
		{
 | 
			
		||||
			dwarnln("invalid pci device bar");
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto* region_ptr = new BarRegion(type, addr, size);
 | 
			
		||||
		ASSERT(region_ptr);
 | 
			
		||||
 | 
			
		||||
		auto region = BAN::UniqPtr<BarRegion>::adopt(region_ptr);
 | 
			
		||||
		TRY(region->initialize());
 | 
			
		||||
 | 
			
		||||
		// restore old command register and enable correct IO/MEM
 | 
			
		||||
		command_status |= (type == BarType::IO) ? 1 : 2;
 | 
			
		||||
		device.write_dword(0x04, command_status);
 | 
			
		||||
 | 
			
		||||
#if DEBUG_PCI
 | 
			
		||||
		dprintln("created BAR region for PCI {}:{}.{}",
 | 
			
		||||
			device.bus(),
 | 
			
		||||
			device.dev(),
 | 
			
		||||
			device.func()
 | 
			
		||||
		);
 | 
			
		||||
		dprintln("  type: {}", region->type() == BarType::IO ? "IO" : "MEM");
 | 
			
		||||
		dprintln("  paddr {}", (void*)region->paddr());
 | 
			
		||||
		dprintln("  vaddr {}", (void*)region->vaddr());
 | 
			
		||||
		dprintln("  size  {}", region->size());
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		return region;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BarRegion::BarRegion(BarType type, paddr_t paddr, size_t size)
 | 
			
		||||
		: m_type(type)
 | 
			
		||||
		, m_paddr(paddr)
 | 
			
		||||
		, m_size(size)
 | 
			
		||||
	{ }
 | 
			
		||||
 | 
			
		||||
	BarRegion::~BarRegion()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_type == BarType::MEM && m_vaddr)
 | 
			
		||||
			PageTable::kernel().unmap_range(m_vaddr, m_size);
 | 
			
		||||
		m_vaddr = 0;		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> BarRegion::initialize()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_type == BarType::IO)
 | 
			
		||||
			return {};
 | 
			
		||||
 | 
			
		||||
		size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
 | 
			
		||||
		m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
 | 
			
		||||
		if (m_vaddr == 0)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		PageTable::kernel().map_range_at(m_paddr, m_vaddr, m_size, PageTable::Flags::CacheDisable | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void BarRegion::write8(off_t reg, uint8_t val)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_type == BarType::IO)
 | 
			
		||||
			return IO::outb(m_vaddr + reg, val);
 | 
			
		||||
		MMIO::write8(m_vaddr + reg, val);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void BarRegion::write16(off_t reg, uint16_t val)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_type == BarType::IO)
 | 
			
		||||
			return IO::outw(m_vaddr + reg, val);
 | 
			
		||||
		MMIO::write16(m_vaddr + reg, val);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void BarRegion::write32(off_t reg, uint32_t val)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_type == BarType::IO)
 | 
			
		||||
			return IO::outl(m_vaddr + reg, val);
 | 
			
		||||
		MMIO::write32(m_vaddr + reg, val);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t BarRegion::read8(off_t reg)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_type == BarType::IO)
 | 
			
		||||
			return IO::inb(m_vaddr + reg);
 | 
			
		||||
		return MMIO::read8(m_vaddr + reg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint16_t BarRegion::read16(off_t reg)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_type == BarType::IO)
 | 
			
		||||
			return IO::inw(m_vaddr + reg);
 | 
			
		||||
		return MMIO::read16(m_vaddr + reg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t BarRegion::read32(off_t reg)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_type == BarType::IO)
 | 
			
		||||
			return IO::inl(m_vaddr + reg);
 | 
			
		||||
		return MMIO::read32(m_vaddr + reg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	PCI::Device::Device(uint8_t bus, uint8_t dev, uint8_t func)
 | 
			
		||||
		: m_bus(bus), m_dev(dev), m_func(func)
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t type = read_word(0x0A);
 | 
			
		||||
| 
						 | 
				
			
			@ -142,87 +283,92 @@ namespace Kernel
 | 
			
		|||
		m_subclass    = (uint8_t)(type);
 | 
			
		||||
		m_prog_if     = read_byte(0x09);
 | 
			
		||||
		m_header_type = read_byte(0x0E);
 | 
			
		||||
 | 
			
		||||
		enumerate_capabilites();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t PCIDevice::read_dword(uint8_t offset) const
 | 
			
		||||
	uint32_t PCI::Device::read_dword(uint8_t offset) const
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT((offset & 0x03) == 0);
 | 
			
		||||
		return read_config_dword(m_bus, m_dev, m_func, offset);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint16_t PCIDevice::read_word(uint8_t offset) const
 | 
			
		||||
	uint16_t PCI::Device::read_word(uint8_t offset) const
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT((offset & 0x01) == 0);
 | 
			
		||||
		uint32_t dword = read_config_dword(m_bus, m_dev, m_func, offset & 0xFC);
 | 
			
		||||
		return (uint16_t)(dword >> (8 * (offset & 0x03)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t PCIDevice::read_byte(uint8_t offset) const
 | 
			
		||||
	uint8_t PCI::Device::read_byte(uint8_t offset) const
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t dword = read_config_dword(m_bus, m_dev, m_func, offset & 0xFC);
 | 
			
		||||
		return (uint8_t)(dword >> (8 * (offset & 0x03)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCIDevice::write_dword(uint8_t offset, uint32_t value) const
 | 
			
		||||
	void PCI::Device::write_dword(uint8_t offset, uint32_t value)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT((offset & 0x03) == 0);
 | 
			
		||||
		write_config_dword(m_bus, m_dev, m_func, offset, value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	PCIDevice::BarType PCIDevice::read_bar_type(uint8_t bar) const
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<BarRegion>> PCI::Device::allocate_bar_region(uint8_t bar_num)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(m_header_type == 0x00);
 | 
			
		||||
		ASSERT(bar <= 5);
 | 
			
		||||
 | 
			
		||||
		uint32_t type = read_dword(0x10 + bar * 4) & 0b111;
 | 
			
		||||
		if (type & 1)
 | 
			
		||||
			return BarType::IO;
 | 
			
		||||
		type >>= 1;
 | 
			
		||||
		if (type == 0x0 || type == 0x2)
 | 
			
		||||
			return BarType::MEM;
 | 
			
		||||
		return BarType::INVAL;
 | 
			
		||||
		return BarRegion::create(*this, bar_num);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint64_t PCIDevice::read_bar_address(uint8_t bar) const
 | 
			
		||||
	void PCI::Device::enumerate_capabilites()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(m_header_type == 0x00);
 | 
			
		||||
		ASSERT(bar <= 5);
 | 
			
		||||
		uint16_t status = read_word(0x06);
 | 
			
		||||
		if (!(status & (1 << 4)))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		uint64_t address = read_dword(0x10 + bar * 4);
 | 
			
		||||
		if (address & 1)
 | 
			
		||||
			return address & 0xFFFFFFFC;
 | 
			
		||||
		if ((address & 0b110) == 0b100)
 | 
			
		||||
			address |= (uint64_t)read_dword(0x10 + bar * 4 + 4) << 32;
 | 
			
		||||
		return address & 0xFFFFFFFFFFFFFFF0;
 | 
			
		||||
		uint8_t capabilities = read_byte(0x34) & 0xFC;
 | 
			
		||||
		while (capabilities)
 | 
			
		||||
		{
 | 
			
		||||
			uint16_t next = read_word(capabilities);
 | 
			
		||||
			dprintln("  cap {2H}", next & 0xFF);
 | 
			
		||||
			capabilities = (next >> 8) & 0xFC;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCIDevice::enable_bus_mastering() const
 | 
			
		||||
	void PCI::Device::enable_bus_mastering()
 | 
			
		||||
	{
 | 
			
		||||
		write_dword(0x04, read_dword(0x04) | 1u << 2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCIDevice::disable_bus_mastering() const
 | 
			
		||||
	void PCI::Device::disable_bus_mastering()
 | 
			
		||||
	{
 | 
			
		||||
		write_dword(0x04, read_dword(0x04) & ~(1u << 2));
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCIDevice::enable_memory_space() const
 | 
			
		||||
	void PCI::Device::enable_memory_space()
 | 
			
		||||
	{
 | 
			
		||||
		write_dword(0x04, read_dword(0x04) | 1u << 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCIDevice::disable_memory_space() const
 | 
			
		||||
	void PCI::Device::disable_memory_space()
 | 
			
		||||
	{
 | 
			
		||||
		write_dword(0x04, read_dword(0x04) & ~(1u << 1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCIDevice::enable_pin_interrupts() const
 | 
			
		||||
	void PCI::Device::enable_io_space()
 | 
			
		||||
	{
 | 
			
		||||
		write_dword(0x04, read_dword(0x04) | 1u << 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCI::Device::disable_io_space()
 | 
			
		||||
	{
 | 
			
		||||
		write_dword(0x04, read_dword(0x04) & ~(1u << 0));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCI::Device::enable_pin_interrupts()
 | 
			
		||||
	{
 | 
			
		||||
		write_dword(0x04, read_dword(0x04) | 1u << 10);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PCIDevice::disable_pin_interrupts() const
 | 
			
		||||
	void PCI::Device::disable_pin_interrupts()
 | 
			
		||||
	{
 | 
			
		||||
		write_dword(0x04, read_dword(0x04) & ~(1u << 10));
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<ATAController>> ATAController::create(const PCIDevice& device)
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<ATAController>> ATAController::create(const PCI::Device& device)
 | 
			
		||||
	{
 | 
			
		||||
		ATAController* controller = new ATAController();
 | 
			
		||||
		if (controller == nullptr)
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ namespace Kernel
 | 
			
		|||
		: m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0))
 | 
			
		||||
	{ }
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> ATAController::initialize(const PCIDevice& pci_device)
 | 
			
		||||
	BAN::ErrorOr<void> ATAController::initialize(const PCI::Device& pci_device)
 | 
			
		||||
	{
 | 
			
		||||
		struct Bus
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -167,7 +167,7 @@ static void init2(void*)
 | 
			
		|||
 | 
			
		||||
	DevFileSystem::get().initialize_device_updater();
 | 
			
		||||
 | 
			
		||||
	PCI::initialize();
 | 
			
		||||
	PCI::PCIManager::initialize();
 | 
			
		||||
	dprintln("PCI initialized");
 | 
			
		||||
 | 
			
		||||
	VirtualFileSystem::initialize(cmdline.root);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue