diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index c91ed769..f66bd685 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -49,7 +49,9 @@ set(KERNEL_SOURCES kernel/Memory/MemoryRegion.cpp kernel/Memory/PhysicalRange.cpp kernel/Memory/VirtualRange.cpp - kernel/Networking/E1000.cpp + kernel/Networking/E1000/E1000.cpp + kernel/Networking/E1000/E1000E.cpp + kernel/Networking/NetworkInterface.cpp kernel/OpenFileDescriptorSet.cpp kernel/Panic.cpp kernel/PCI.cpp diff --git a/kernel/include/kernel/Networking/E1000.h b/kernel/include/kernel/Networking/E1000.h deleted file mode 100644 index d74a1bdd..00000000 --- a/kernel/include/kernel/Networking/E1000.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#define E1000_NUM_RX_DESC 32 -#define E1000_NUM_TX_DESC 8 - -namespace Kernel -{ - - class E1000 final : public NetworkDriver, public Interruptable - { - public: - static bool probe(PCI::Device&); - static BAN::ErrorOr> create(PCI::Device&); - ~E1000(); - - virtual uint8_t* get_mac_address() override { return m_mac_address; } - virtual BAN::ErrorOr send_packet(const void* data, uint16_t len) override; - - virtual bool link_up() override { return m_link_up; } - virtual int link_speed() override; - - virtual void handle_irq() override { ASSERT_NOT_REACHED(); } - - private: - E1000(PCI::Device& pci_device) : m_pci_device(pci_device) {} - BAN::ErrorOr initialize(); - - static void interrupt_handler(); - - uint32_t read32(uint16_t reg); - void write32(uint16_t reg, uint32_t value); - - void detect_eeprom(); - uint32_t eeprom_read(uint8_t addr); - BAN::ErrorOr read_mac_address(); - - void initialize_rx(); - void initialize_tx(); - - void enable_link(); - BAN::ErrorOr enable_interrupts(); - - void handle_receive(); - - private: - PCI::Device& m_pci_device; - BAN::UniqPtr m_bar_region; - bool m_has_eerprom { false }; - uint8_t m_mac_address[6] {}; - uint16_t m_rx_current {}; - uint16_t m_tx_current {}; - struct e1000_rx_desc* m_rx_descs[E1000_NUM_RX_DESC] {}; - struct e1000_tx_desc* m_tx_descs[E1000_NUM_TX_DESC] {}; - bool m_link_up { false }; - }; - -} diff --git a/kernel/include/kernel/Networking/E1000/Definitions.h b/kernel/include/kernel/Networking/E1000/Definitions.h new file mode 100644 index 00000000..68dfc2d6 --- /dev/null +++ b/kernel/include/kernel/Networking/E1000/Definitions.h @@ -0,0 +1,202 @@ +#pragma once + +#include + +namespace Kernel +{ + + enum E1000_REG : uint32_t + { + REG_CTRL = 0x0000, + REG_STATUS = 0x0008, + REG_EERD = 0x0014, + REG_ICR = 0x00C0, + REG_ITR = 0x00C4, + REG_IMS = 0x00D0, + REG_IMC = 0x00D8, + REG_IVAR = 0x00E4, + REG_EITR = 0x00E8, + REG_RCTL = 0x0100, + REG_TCTL = 0x0400, + REG_TIPG = 0x0410, + REG_RDBAL0 = 0x2800, + REG_RDBAH0 = 0x2804, + REG_RDLEN0 = 0x2808, + REG_RDH0 = 0x2810, + REG_RDT0 = 0x2818, + REG_TDBAL = 0x3800, + REG_TDBAH = 0x3804, + REG_TDLEN = 0x3808, + REG_TDH = 0x3810, + REG_TDT = 0x3818, + REG_MTA = 0x5200, + }; + + enum E1000_CTRL : uint32_t + { + CTRL_FD = 1u << 0, + CTRL_GIOMD = 1u << 2, + CTRL_ASDE = 1u << 5, + CTRL_SLU = 1u << 6, + CTRL_FRCSPD = 1u << 11, + CTRL_FCRDBLX = 1u << 12, + CTRL_ADVD3WUC = 1u << 20, + CTRL_RST = 1u << 26, + CTRL_RFCE = 1u << 27, + CTRL_TFCE = 1u << 28, + CTRL_VME = 1u << 30, + CTRL_PHY_RST = 1u << 31, + + CTRL_SPEED_10MB = 0b00 << 8, + CTRL_SPEED_100MB = 0b01 << 8, + CTRL_SPEED_1000MB1 = 0b10 << 8, + CTRL_SPEED_1000MB2 = 0b11 << 8, + }; + + enum E1000_STATUS : uint32_t + { + STATUS_LU = 1 << 1, + + STATUS_SPEED_MASK = 0b11 << 6, + STATUS_SPEED_10MB = 0b00 << 6, + STATUS_SPEED_100MB = 0b01 << 6, + STATUS_SPEED_1000MB1 = 0b10 << 6, + STATUS_SPEED_1000MB2 = 0b11 << 6, + }; + + enum E1000_ICR : uint32_t + { + ICR_TXDW = 1 << 0, + ICR_TXQE = 1 << 1, + ICR_LSC = 1 << 2, + ICR_RXDMT0 = 1 << 4, + ICR_RXO = 1 << 6, + ICR_RXT0 = 1 << 7, + ICR_MDAC = 1 << 9, + ICR_TXD_LOW = 1 << 15, + ICR_SRPD = 1 << 16, + ICR_ACK = 1 << 17, + ICR_MNG = 1 << 18, + ICR_RxQ0 = 1 << 20, + ICR_RxQ1 = 1 << 21, + ICR_TxQ0 = 1 << 22, + ICR_TxQ1 = 1 << 23, + ICR_Other = 1 << 24, + }; + + enum E1000_IMS : uint32_t + { + IMS_TXDW = 1 << 0, + IMS_TXQE = 1 << 1, + IMS_LSC = 1 << 2, + IMS_RXDMT0 = 1 << 4, + IMS_RXO = 1 << 6, + IMS_RXT0 = 1 << 7, + IMS_MDAC = 1 << 9, + IMS_TXD_LOW = 1 << 15, + IMS_SRPD = 1 << 16, + IMS_ACK = 1 << 17, + IMS_MNG = 1 << 18, + IMS_RxQ0 = 1 << 20, + IMS_RxQ1 = 1 << 21, + IMS_TxQ0 = 1 << 22, + IMS_TxQ1 = 1 << 23, + IMS_Other = 1 << 24, + }; + + enum E1000_IMC : uint32_t + { + IMC_TXDW = 1 << 0, + IMC_TXQE = 1 << 1, + IMC_LSC = 1 << 2, + IMC_RXDMT0 = 1 << 4, + IMC_RXO = 1 << 6, + IMC_RXT0 = 1 << 7, + IMC_MDAC = 1 << 9, + IMC_TXD_LOW = 1 << 15, + IMC_SRPD = 1 << 16, + IMC_ACK = 1 << 17, + IMC_MNG = 1 << 18, + IMC_RxQ0 = 1 << 20, + IMC_RxQ1 = 1 << 21, + IMC_TxQ0 = 1 << 22, + IMC_TxQ1 = 1 << 23, + IMC_Other = 1 << 24, + }; + + enum E1000_TCTL : uint32_t + { + TCTL_EN = 1 << 1, + TCTL_PSP = 1 << 3, + TCTL_CT_IEEE = 15 << 4, + TCTL_SWXOFF = 1 << 22, + TCTL_PBE = 1 << 23, + TCTL_RCTL = 1 << 24, + TCTL_UNORTX = 1 << 25, + TCTL_MULR = 1 << 28, + }; + + enum E1000_RCTL : uint32_t + { + RCTL_EN = 1 << 1, + RCTL_SBP = 1 << 2, + RCTL_UPE = 1 << 3, + RCTL_MPE = 1 << 4, + RCTL_BAM = 1 << 15, + RCTL_VFE = 1 << 18, + RCTL_CFIEN = 1 << 19, + RCTL_CFI = 1 << 20, + RCTL_DPF = 1 << 22, + RCTL_PMCF = 1 << 23, + RCTL_BSEX = 1 << 25, + RCTL_SECRC = 1 << 26, + + RCTL_RDMTS_1_2 = 0b00 << 8, + RCTL_RDMTS_1_4 = 0b01 << 8, + RCTL_RDMTS_1_8 = 0b10 << 8, + + RCTL_LBM_NORMAL = 0b00 << 6, + RCTL_LBM_MAC = 0b01 << 6, + + RCTL_BSIZE_256 = (0b11 << 16), + RCTL_BSIZE_512 = (0b10 << 16), + RCTL_BSIZE_1024 = (0b01 << 16), + RCTL_BSIZE_2048 = (0b00 << 16), + RCTL_BSIZE_4096 = (0b11 << 16) | RCTL_BSEX, + RCTL_BSIZE_8192 = (0b10 << 16) | RCTL_BSEX, + RCTL_BSIZE_16384 = (0b01 << 16) | RCTL_BSEX, + }; + + enum E1000_CMD : uint8_t + { + CMD_EOP = 1 << 0, + CMD_IFCS = 1 << 1, + CMD_IC = 1 << 2, + CMD_RS = 1 << 3, + CMD_DEXT = 1 << 5, + CMD_VLE = 1 << 6, + CMD_IDE = 1 << 7, + }; + + struct e1000_rx_desc + { + uint64_t addr; + uint16_t length; + uint16_t checksum; + uint8_t status; + uint8_t errors; + uint16_t special; + } __attribute__((packed)); + + struct e1000_tx_desc + { + uint64_t addr; + uint16_t length; + uint8_t cso; + uint8_t cmd; + uint8_t status; + uint8_t css; + uint16_t special; + } __attribute__((packed)); + +} diff --git a/kernel/include/kernel/Networking/E1000/E1000.h b/kernel/include/kernel/Networking/E1000/E1000.h new file mode 100644 index 00000000..dad13f52 --- /dev/null +++ b/kernel/include/kernel/Networking/E1000/E1000.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#define E1000_RX_DESCRIPTOR_COUNT 256 +#define E1000_TX_DESCRIPTOR_COUNT 256 + +#define E1000_RX_BUFFER_SIZE 8192 +#define E1000_TX_BUFFER_SIZE 8192 + +namespace Kernel +{ + + class E1000 : public NetworkInterface, public Interruptable + { + public: + static bool probe(PCI::Device&); + static BAN::ErrorOr> create(PCI::Device&); + ~E1000(); + + virtual uint8_t* get_mac_address() override { return m_mac_address; } + + virtual bool link_up() override { return m_link_up; } + virtual int link_speed() override; + + virtual void handle_irq() final override; + + protected: + E1000(PCI::Device& pci_device) + : m_pci_device(pci_device) + { } + BAN::ErrorOr initialize(); + + virtual void detect_eeprom(); + virtual uint32_t eeprom_read(uint8_t addr); + + uint32_t read32(uint16_t reg); + void write32(uint16_t reg, uint32_t value); + + virtual BAN::ErrorOr send_raw_bytes(BAN::ConstByteSpan) override; + + private: + BAN::ErrorOr read_mac_address(); + + BAN::ErrorOr initialize_rx(); + BAN::ErrorOr initialize_tx(); + + void enable_link(); + BAN::ErrorOr enable_interrupt(); + + void handle_receive(); + + protected: + PCI::Device& m_pci_device; + BAN::UniqPtr m_bar_region; + bool m_has_eerprom { false }; + + private: + BAN::UniqPtr m_rx_buffer_region; + BAN::UniqPtr m_tx_buffer_region; + BAN::UniqPtr m_rx_descriptor_region; + BAN::UniqPtr m_tx_descriptor_region; + + uint8_t m_mac_address[6] {}; + uint16_t m_rx_current {}; + uint16_t m_tx_current {}; + void* m_rx_buffers[E1000_RX_DESCRIPTOR_COUNT] {}; + void* m_tx_buffers[E1000_TX_DESCRIPTOR_COUNT] {}; + bool m_link_up { false }; + + friend class BAN::RefPtr; + }; + +} diff --git a/kernel/include/kernel/Networking/E1000/E1000E.h b/kernel/include/kernel/Networking/E1000/E1000E.h new file mode 100644 index 00000000..20dea114 --- /dev/null +++ b/kernel/include/kernel/Networking/E1000/E1000E.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace Kernel +{ + + class E1000E final : public E1000 + { + public: + static bool probe(PCI::Device&); + static BAN::ErrorOr> create(PCI::Device&); + + protected: + virtual void detect_eeprom() override; + virtual uint32_t eeprom_read(uint8_t addr) override; + + private: + E1000E(PCI::Device& pci_device) + : E1000(pci_device) + { } + + private: + friend class BAN::RefPtr; + }; + +} diff --git a/kernel/include/kernel/Networking/NetworkDriver.h b/kernel/include/kernel/Networking/NetworkDriver.h deleted file mode 100644 index 96c9b6fd..00000000 --- a/kernel/include/kernel/Networking/NetworkDriver.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -namespace Kernel -{ - - class NetworkDriver - { - public: - virtual ~NetworkDriver() {} - - virtual uint8_t* get_mac_address() = 0; - virtual BAN::ErrorOr send_packet(const void* data, uint16_t len) = 0; - - virtual bool link_up() = 0; - virtual int link_speed() = 0; - }; - -} diff --git a/kernel/include/kernel/Networking/NetworkInterface.h b/kernel/include/kernel/Networking/NetworkInterface.h new file mode 100644 index 00000000..4888615b --- /dev/null +++ b/kernel/include/kernel/Networking/NetworkInterface.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +namespace Kernel +{ + + class NetworkInterface : public CharacterDevice + { + public: + enum class Type + { + Ethernet, + }; + + public: + NetworkInterface(); + virtual ~NetworkInterface() {} + + virtual uint8_t* get_mac_address() = 0; + + virtual bool link_up() = 0; + virtual int link_speed() = 0; + + virtual dev_t rdev() const override { return m_rdev; } + virtual BAN::StringView name() const override { return m_name; } + + protected: + virtual BAN::ErrorOr send_raw_bytes(BAN::ConstByteSpan) = 0; + + private: + const Type m_type; + + const dev_t m_rdev; + char m_name[10]; + }; + +} diff --git a/kernel/kernel/Networking/E1000.cpp b/kernel/kernel/Networking/E1000.cpp deleted file mode 100644 index 666e5408..00000000 --- a/kernel/kernel/Networking/E1000.cpp +++ /dev/null @@ -1,374 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define DEBUG_E1000 1 - -#define E1000_REG_CTRL 0x0000 -#define E1000_REG_STATUS 0x0008 -#define E1000_REG_EEPROM 0x0014 -#define E1000_REG_INT_CAUSE_READ 0x00C0 -#define E1000_REG_INT_RATE 0x00C4 -#define E1000_REG_INT_MASK_SET 0x00D0 -#define E1000_REG_INT_MASK_CLEAR 0x00D8 -#define E1000_REG_RCTRL 0x0100 -#define E1000_REG_RXDESCLO 0x2800 -#define E1000_REG_RXDESCHI 0x2804 -#define E1000_REG_RXDESCLEN 0x2808 -#define E1000_REG_RXDESCHEAD 0x2810 -#define E1000_REG_RXDESCTAIL 0x2818 -#define E1000_REG_TXDESCLO 0x3800 -#define E1000_REG_TXDESCHI 0x3804 -#define E1000_REG_TXDESCLEN 0x3808 -#define E1000_REG_TXDESCHEAD 0x3810 -#define E1000_REG_TXDESCTAIL 0x3818 -#define E1000_REG_TCTRL 0x0400 -#define E1000_REG_TIPG 0x0410 - -#define E1000_STATUS_LINK_UP 0x02 -#define E1000_STATUS_SPEED_MASK 0xC0 -#define E1000_STATUS_SPEED_10MB 0x00 -#define E1000_STATUS_SPEED_100MB 0x40 -#define E1000_STATUS_SPEED_1000MB1 0x80 -#define E1000_STATUS_SPEED_1000MB2 0xC0 - -#define E1000_CTRL_SET_LINK_UP 0x40 - -#define E1000_INT_TXDW (1 << 0) -#define E1000_INT_TXQE (1 << 1) -#define E1000_INT_LSC (1 << 2) -#define E1000_INT_RXSEQ (1 << 3) -#define E1000_INT_RXDMT0 (1 << 4) -#define E1000_INT_RXO (1 << 6) -#define E1000_INT_RXT0 (1 << 7) -#define E1000_INT_MDAC (1 << 9) -#define E1000_INT_RXCFG (1 << 10) -#define E1000_INT_PHYINT (1 << 12) -#define E1000_INT_TXD_LOW (1 << 15) -#define E1000_INT_SRPD (1 << 16) - - -#define E1000_TCTL_EN (1 << 1) -#define E1000_TCTL_PSP (1 << 3) -#define E1000_TCTL_CT_SHIFT 4 -#define E1000_TCTL_COLD_SHIFT 12 -#define E1000_TCTL_SWXOFF (1 << 22) -#define E1000_TCTL_RTLC (1 << 24) - -#define E1000_RCTL_EN (1 << 1) -#define E1000_RCTL_SBP (1 << 2) -#define E1000_RCTL_UPE (1 << 3) -#define E1000_RCTL_MPE (1 << 4) -#define E1000_RCTL_LPE (1 << 5) -#define E1000_RCTL_LBM_NONE (0 << 6) -#define E1000_RCTL_LBM_PHY (3 << 6) -#define E1000_RTCL_RDMTS_HALF (0 << 8) -#define E1000_RTCL_RDMTS_QUARTER (1 << 8) -#define E1000_RTCL_RDMTS_EIGHTH (2 << 8) -#define E1000_RCTL_MO_36 (0 << 12) -#define E1000_RCTL_MO_35 (1 << 12) -#define E1000_RCTL_MO_34 (2 << 12) -#define E1000_RCTL_MO_32 (3 << 12) -#define E1000_RCTL_BAM (1 << 15) -#define E1000_RCTL_VFE (1 << 18) -#define E1000_RCTL_CFIEN (1 << 19) -#define E1000_RCTL_CFI (1 << 20) -#define E1000_RCTL_DPF (1 << 22) -#define E1000_RCTL_PMCF (1 << 23) -#define E1000_RCTL_SECRC (1 << 26) - -#define E1000_RCTL_BSIZE_256 (3 << 16) -#define E1000_RCTL_BSIZE_512 (2 << 16) -#define E1000_RCTL_BSIZE_1024 (1 << 16) -#define E1000_RCTL_BSIZE_2048 (0 << 16) -#define E1000_RCTL_BSIZE_4096 ((3 << 16) | (1 << 25)) -#define E1000_RCTL_BSIZE_8192 ((2 << 16) | (1 << 25)) -#define E1000_RCTL_BSIZE_16384 ((1 << 16) | (1 << 25)) - -namespace Kernel -{ - - struct e1000_rx_desc - { - volatile uint64_t addr; - volatile uint16_t length; - volatile uint16_t checksum; - volatile uint8_t status; - volatile uint8_t errors; - volatile uint16_t special; - } __attribute__((packed)); - - struct e1000_tx_desc - { - volatile uint64_t addr; - volatile uint16_t length; - volatile uint8_t cso; - volatile uint8_t cmd; - volatile uint8_t status; - volatile uint8_t css; - volatile uint16_t special; - } __attribute__((packed)); - - // https://www.intel.com/content/dam/doc/manual/pci-pci-x-family-gbe-controllers-software-dev-manual.pdf (section 5.2) - bool E1000::probe(PCI::Device& pci_device) - { - // Intel device - if (pci_device.vendor_id() != 0x8086) - return false; - - switch (pci_device.device_id()) - { - case 0x1019: - case 0x101A: - case 0x1010: - case 0x1012: - case 0x101D: - case 0x1079: - case 0x107A: - case 0x107B: - case 0x100F: - case 0x1011: - case 0x1026: - case 0x1027: - case 0x1028: - case 0x1107: - case 0x1112: - case 0x1013: - case 0x1018: - case 0x1076: - case 0x1077: - case 0x1078: - case 0x1017: - case 0x1016: - case 0x100e: - case 0x1015: - return true; - default: - return false; - } - } - - BAN::ErrorOr> E1000::create(PCI::Device& pci_device) - { - E1000* e1000 = new E1000(); - ASSERT(e1000); - if (auto ret = e1000->initialize(pci_device); ret.is_error()) - { - delete e1000; - return ret.release_error(); - } - return BAN::UniqPtr::adopt(e1000); - } - - E1000::~E1000() - { - } - - BAN::ErrorOr E1000::initialize(PCI::Device& pci_device) - { - m_bar_region = TRY(pci_device.allocate_bar_region(0)); - pci_device.enable_bus_mastering(); - - detect_eeprom(); - - TRY(read_mac_address()); - - - 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], - m_mac_address[2], - m_mac_address[3], - m_mac_address[4], - m_mac_address[5] - ); - 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) - { - m_bar_region->write32(reg, value); - } - - uint32_t E1000::read32(uint16_t reg) - { - return m_bar_region->read32(reg); - } - - void E1000::detect_eeprom() - { - m_has_eerprom = false; - write32(E1000_REG_EEPROM, 0x01); - for (int i = 0; i < 1000 && !m_has_eerprom; i++) - if (read32(E1000_REG_EEPROM) & 0x10) - m_has_eerprom = true; - } - - uint32_t E1000::eeprom_read(uint8_t address) - { - uint32_t tmp = 0; - if (m_has_eerprom) - { - write32(E1000_REG_EEPROM, ((uint32_t)address << 8) | 1); - while (!((tmp = read32(E1000_REG_EEPROM)) & (1 << 4))) - continue; - } - else - { - write32(E1000_REG_EEPROM, ((uint32_t)address << 2) | 1); - while (!((tmp = read32(E1000_REG_EEPROM)) & (1 << 1))) - continue; - } - return (tmp >> 16) & 0xFFFF; - } - - BAN::ErrorOr E1000::read_mac_address() - { - if (m_has_eerprom) - { - uint32_t temp = eeprom_read(0); - m_mac_address[0] = temp; - m_mac_address[1] = temp >> 8; - - temp = eeprom_read(1); - m_mac_address[2] = temp; - m_mac_address[3] = temp >> 8; - - temp = eeprom_read(2); - m_mac_address[4] = temp; - m_mac_address[5] = temp >> 8; - - return {}; - } - - if (read32(0x5400) == 0) - { - dwarnln("no mac address"); - return BAN::Error::from_errno(EINVAL); - } - - for (int i = 0; i < 6; i++) - m_mac_address[i] = (uint8_t)read32(0x5400 + i * 8); - - return {}; - } - - void E1000::initialize_rx() - { - uint8_t* ptr = (uint8_t*)kmalloc(sizeof(e1000_rx_desc) * E1000_NUM_RX_DESC + 16, 16, true); - ASSERT(ptr); - - e1000_rx_desc* descs = (e1000_rx_desc*)ptr; - for (int i = 0; i < E1000_NUM_RX_DESC; i++) - { - // FIXME - m_rx_descs[i] = &descs[i]; - m_rx_descs[i]->addr = 0; - m_rx_descs[i]->status = 0; - } - - write32(E1000_REG_RXDESCLO, (uintptr_t)ptr >> 32); - write32(E1000_REG_RXDESCHI, (uintptr_t)ptr & 0xFFFFFFFF); - write32(E1000_REG_RXDESCLEN, E1000_NUM_RX_DESC * sizeof(e1000_rx_desc)); - write32(E1000_REG_RXDESCHEAD, 0); - write32(E1000_REG_RXDESCTAIL, E1000_NUM_RX_DESC - 1); - - m_rx_current = 0; - - uint32_t rctrl = 0; - rctrl |= E1000_RCTL_EN; - rctrl |= E1000_RCTL_SBP; - rctrl |= E1000_RCTL_UPE; - rctrl |= E1000_RCTL_MPE; - rctrl |= E1000_RCTL_LBM_NONE; - rctrl |= E1000_RTCL_RDMTS_HALF; - rctrl |= E1000_RCTL_BAM; - rctrl |= E1000_RCTL_SECRC; - rctrl |= E1000_RCTL_BSIZE_8192; - - write32(E1000_REG_RCTRL, rctrl); - } - - void E1000::initialize_tx() - { - auto* ptr = (uint8_t*)kmalloc(sizeof(e1000_tx_desc) * E1000_NUM_TX_DESC + 16, 16, true); - ASSERT(ptr); - - auto* descs = (e1000_tx_desc*)ptr; - for(int i = 0; i < E1000_NUM_TX_DESC; i++) - { - // FIXME - m_tx_descs[i] = &descs[i]; - m_tx_descs[i]->addr = 0; - m_tx_descs[i]->cmd = 0; - } - - write32(E1000_REG_TXDESCHI, (uintptr_t)ptr >> 32); - write32(E1000_REG_TXDESCLO, (uintptr_t)ptr & 0xFFFFFFFF); - write32(E1000_REG_TXDESCLEN, E1000_NUM_TX_DESC * sizeof(e1000_tx_desc)); - write32(E1000_REG_TXDESCHEAD, 0); - write32(E1000_REG_TXDESCTAIL, 0); - - m_tx_current = 0; - - write32(E1000_REG_TCTRL, read32(E1000_REG_TCTRL) | E1000_TCTL_EN | E1000_TCTL_PSP); - write32(E1000_REG_TIPG, 0x0060200A); - } - - void E1000::enable_link() - { - write32(E1000_REG_CTRL, read32(E1000_REG_CTRL) | E1000_CTRL_SET_LINK_UP); - m_link_up = !!(read32(E1000_REG_STATUS) & E1000_STATUS_LINK_UP); - } - - int E1000::link_speed() - { - if (!link_up()) - return 0; - uint32_t speed = read32(E1000_REG_STATUS) & E1000_STATUS_SPEED_MASK; - if (speed == E1000_STATUS_SPEED_10MB) - return 10; - if (speed == E1000_STATUS_SPEED_100MB) - return 100; - if (speed == E1000_STATUS_SPEED_1000MB1) - return 1000; - if (speed == E1000_STATUS_SPEED_1000MB2) - return 1000; - return 0; - } - - void E1000::enable_interrupts() - { - write32(E1000_REG_INT_RATE, 6000); - write32(E1000_REG_INT_MASK_SET, E1000_INT_LSC | E1000_INT_RXT0 | E1000_INT_RXO); - read32(E1000_REG_INT_CAUSE_READ); - - // FIXME: implement PCI interrupt allocation - //IDT::register_irq_handler(irq, E1000::interrupt_handler); - //InterruptController::enable_irq(irq); - } - - BAN::ErrorOr E1000::send_packet(const void* data, uint16_t len) - { - (void)data; - (void)len; - return BAN::Error::from_errno(ENOTSUP); - } - -} diff --git a/kernel/kernel/Networking/E1000/E1000.cpp b/kernel/kernel/Networking/E1000/E1000.cpp new file mode 100644 index 00000000..56239948 --- /dev/null +++ b/kernel/kernel/Networking/E1000/E1000.cpp @@ -0,0 +1,314 @@ +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_E1000 1 + +namespace Kernel +{ + + // https://www.intel.com/content/dam/doc/manual/pci-pci-x-family-gbe-controllers-software-dev-manual.pdf (section 5.2) + bool E1000::probe(PCI::Device& pci_device) + { + // Intel device + if (pci_device.vendor_id() != 0x8086) + return false; + + switch (pci_device.device_id()) + { + case 0x1019: + case 0x101A: + case 0x1010: + case 0x1012: + case 0x101D: + case 0x1079: + case 0x107A: + case 0x107B: + case 0x100F: + case 0x1011: + case 0x1026: + case 0x1027: + case 0x1028: + case 0x1107: + case 0x1112: + case 0x1013: + case 0x1018: + case 0x1076: + case 0x1077: + case 0x1078: + case 0x1017: + case 0x1016: + case 0x100e: + case 0x1015: + return true; + default: + return false; + } + } + + BAN::ErrorOr> E1000::create(PCI::Device& pci_device) + { + auto e1000 = TRY(BAN::RefPtr::create(pci_device)); + TRY(e1000->initialize()); + return e1000; + } + + E1000::~E1000() + { + } + + BAN::ErrorOr E1000::initialize() + { + m_bar_region = TRY(m_pci_device.allocate_bar_region(0)); + m_pci_device.enable_bus_mastering(); + + detect_eeprom(); + TRY(read_mac_address()); +#if DEBUG_E1000 + dprintln("E1000 at PCI {}:{}.{}", m_pci_device.bus(), m_pci_device.dev(), m_pci_device.func()); + dprintln(" MAC: {2H}:{2H}:{2H}:{2H}:{2H}:{2H}", + m_mac_address[0], + m_mac_address[1], + m_mac_address[2], + m_mac_address[3], + m_mac_address[4], + m_mac_address[5] + ); +#endif + + TRY(initialize_rx()); + TRY(initialize_tx()); + + enable_link(); + TRY(enable_interrupt()); + + m_link_up = !!(read32(REG_STATUS) & STATUS_LU); + +#if DEBUG_E1000 + dprintln(" link up: {}", link_up()); + if (link_up()) + { + int speed = link_speed(); + dprintln(" link speed: {} Mbps", speed); + } +#endif + + DevFileSystem::get().add_device(this); + + return {}; + } + + void E1000::write32(uint16_t reg, uint32_t value) + { + m_bar_region->write32(reg, value); + } + + uint32_t E1000::read32(uint16_t reg) + { + return m_bar_region->read32(reg); + } + + void E1000::detect_eeprom() + { + m_has_eerprom = false; + write32(REG_EERD, 0x01); + for (int i = 0; i < 1000 && !m_has_eerprom; i++) + if (read32(REG_EERD) & 0x10) + m_has_eerprom = true; + } + + uint32_t E1000::eeprom_read(uint8_t address) + { + uint32_t tmp = 0; + if (m_has_eerprom) + { + write32(REG_EERD, ((uint32_t)address << 8) | 1); + while (!((tmp = read32(REG_EERD)) & (1 << 4))) + continue; + } + else + { + write32(REG_EERD, ((uint32_t)address << 2) | 1); + while (!((tmp = read32(REG_EERD)) & (1 << 1))) + continue; + } + return (tmp >> 16) & 0xFFFF; + } + + BAN::ErrorOr E1000::read_mac_address() + { + if (m_has_eerprom) + { + uint32_t temp = eeprom_read(0); + m_mac_address[0] = temp; + m_mac_address[1] = temp >> 8; + + temp = eeprom_read(1); + m_mac_address[2] = temp; + m_mac_address[3] = temp >> 8; + + temp = eeprom_read(2); + m_mac_address[4] = temp; + m_mac_address[5] = temp >> 8; + + return {}; + } + + if (read32(0x5400) == 0) + { + dwarnln("no mac address"); + return BAN::Error::from_errno(EINVAL); + } + + for (int i = 0; i < 6; i++) + m_mac_address[i] = (uint8_t)read32(0x5400 + i * 8); + + return {}; + } + + BAN::ErrorOr E1000::initialize_rx() + { + m_rx_buffer_region = TRY(DMARegion::create(E1000_RX_BUFFER_SIZE * E1000_RX_DESCRIPTOR_COUNT)); + m_rx_descriptor_region = TRY(DMARegion::create(sizeof(e1000_rx_desc) * E1000_RX_DESCRIPTOR_COUNT)); + + auto* rx_descriptors = reinterpret_cast(m_rx_descriptor_region->vaddr()); + for (size_t i = 0; i < E1000_RX_DESCRIPTOR_COUNT; i++) + { + m_rx_buffers[i] = reinterpret_cast(m_rx_buffer_region->vaddr() + E1000_RX_BUFFER_SIZE * i); + rx_descriptors[i].addr = m_rx_buffer_region->paddr() + E1000_RX_BUFFER_SIZE * i; + rx_descriptors[i].status = 0; + } + + write32(REG_RDBAL0, m_rx_descriptor_region->paddr() & 0xFFFFFFFF); + write32(REG_RDBAH0, m_rx_descriptor_region->paddr() >> 32); + write32(REG_RDLEN0, E1000_RX_DESCRIPTOR_COUNT * sizeof(e1000_rx_desc)); + write32(REG_RDH0, 0); + write32(REG_RDT0, E1000_RX_DESCRIPTOR_COUNT - 1); + + uint32_t rctrl = 0; + rctrl |= RCTL_EN; + rctrl |= RCTL_SBP; + rctrl |= RCTL_UPE; + rctrl |= RCTL_MPE; + rctrl |= RCTL_LBM_NORMAL; + rctrl |= RCTL_RDMTS_1_2; + rctrl |= RCTL_BAM; + rctrl |= RCTL_SECRC; + rctrl |= RCTL_BSIZE_8192; + write32(REG_RCTL, rctrl); + + return {}; + } + + BAN::ErrorOr E1000::initialize_tx() + { + m_tx_buffer_region = TRY(DMARegion::create(E1000_TX_BUFFER_SIZE * E1000_TX_DESCRIPTOR_COUNT)); + m_tx_descriptor_region = TRY(DMARegion::create(sizeof(e1000_tx_desc) * E1000_TX_DESCRIPTOR_COUNT)); + + auto* tx_descriptors = reinterpret_cast(m_tx_descriptor_region->vaddr()); + for (size_t i = 0; i < E1000_TX_DESCRIPTOR_COUNT; i++) + { + m_tx_buffers[i] = reinterpret_cast(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * i); + tx_descriptors[i].addr = m_tx_buffer_region->paddr() + E1000_TX_BUFFER_SIZE * i; + tx_descriptors[i].cmd = 0; + } + + write32(REG_TDBAL, m_tx_descriptor_region->paddr() & 0xFFFFFFFF); + write32(REG_TDBAH, m_tx_descriptor_region->paddr() >> 32); + write32(REG_TDLEN, E1000_TX_DESCRIPTOR_COUNT * sizeof(e1000_tx_desc)); + write32(REG_TDH, 0); + write32(REG_TDT, 0); + + write32(REG_TCTL, TCTL_EN | TCTL_PSP); + write32(REG_TIPG, 0x0060200A); + + return {}; + } + + void E1000::enable_link() + { + write32(REG_CTRL, read32(REG_CTRL) | CTRL_SLU); + } + + int E1000::link_speed() + { + if (!link_up()) + return 0; + uint32_t speed = read32(REG_STATUS) & STATUS_SPEED_MASK; + if (speed == STATUS_SPEED_10MB) + return 10; + if (speed == STATUS_SPEED_100MB) + return 100; + if (speed == STATUS_SPEED_1000MB1) + return 1000; + if (speed == STATUS_SPEED_1000MB2) + return 1000; + return 0; + } + + BAN::ErrorOr E1000::enable_interrupt() + { + write32(REG_ITR, 0x1000); + + write32(REG_IVAR, 1 << 3); + write32(REG_EITR, 0x1000); + + write32(REG_IMS, IMC_RxQ0); + read32(REG_ICR); + + TRY(m_pci_device.reserve_irqs(1)); + set_irq(m_pci_device.get_irq(0)); + Interruptable::enable_interrupt(); + + return {}; + } + + BAN::ErrorOr E1000::send_raw_bytes(BAN::ConstByteSpan buffer) + { + ASSERT_LTE(buffer.size(), E1000_TX_BUFFER_SIZE); + + CriticalScope _; + + size_t tx_current = read32(REG_TDT) % E1000_TX_DESCRIPTOR_COUNT; + + auto* tx_buffer = reinterpret_cast(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * tx_current); + memcpy(tx_buffer, buffer.data(), buffer.size()); + + auto& descriptor = reinterpret_cast(m_tx_descriptor_region->vaddr())[tx_current]; + descriptor.length = buffer.size(); + descriptor.status = 0; + descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS; + + write32(REG_TDT, (tx_current + 1) % E1000_TX_DESCRIPTOR_COUNT); + while (descriptor.status == 0) + continue; + + return {}; + } + + void E1000::handle_irq() + { + if (read32(REG_ICR) & ICR_RxQ0) + return; + + for (;;) { + uint32_t rx_current = (read32(REG_RDT0) + 1) % E1000_RX_DESCRIPTOR_COUNT; + + auto& descriptor = reinterpret_cast(m_rx_descriptor_region->vaddr())[rx_current]; + if (!(descriptor.status & 1)) + break; + ASSERT_LTE((uint16_t)descriptor.length, E1000_RX_BUFFER_SIZE); + + // FIXME: do something with the packet :) + dprintln("got {} byte packet", (uint16_t)descriptor.length); + + descriptor.status = 0; + write32(REG_RDT0, rx_current); + } + } + +} diff --git a/kernel/kernel/Networking/E1000/E1000E.cpp b/kernel/kernel/Networking/E1000/E1000E.cpp new file mode 100644 index 00000000..0b3876a9 --- /dev/null +++ b/kernel/kernel/Networking/E1000/E1000E.cpp @@ -0,0 +1,43 @@ +#include +#include + +#define E1000E_VENDOR_INTEL 0x8086 +#define E1000E_DEVICE_82574 0x10D3 + +namespace Kernel +{ + + bool E1000E::probe(PCI::Device& pci_device) + { + if (pci_device.vendor_id() != E1000E_VENDOR_INTEL) + return false; + switch (pci_device.device_id()) + { + case E1000E_DEVICE_82574: + return true; + } + return false; + } + + BAN::ErrorOr> E1000E::create(PCI::Device& pci_device) + { + auto e1000e = TRY(BAN::RefPtr::create(pci_device)); + TRY(e1000e->initialize()); + return e1000e; + } + + void E1000E::detect_eeprom() + { + m_has_eerprom = true; + } + + uint32_t E1000E::eeprom_read(uint8_t addr) + { + uint32_t tmp; + write32(REG_EERD, ((uint32_t)addr << 2) | 1); + while (!((tmp = read32(REG_EERD)) & (1 << 1))) + continue; + return tmp >> 16; + } + +} diff --git a/kernel/kernel/Networking/NetworkInterface.cpp b/kernel/kernel/Networking/NetworkInterface.cpp new file mode 100644 index 00000000..f9a60715 --- /dev/null +++ b/kernel/kernel/Networking/NetworkInterface.cpp @@ -0,0 +1,34 @@ +#include +#include + +#include +#include + +namespace Kernel +{ + + static dev_t get_network_rdev_major() + { + static dev_t major = DevFileSystem::get().get_next_dev(); + return major; + } + + static dev_t get_network_rdev_minor() + { + static dev_t minor = 0; + return minor++; + } + + NetworkInterface::NetworkInterface() + : CharacterDevice(0400, 0, 0) + , m_type(Type::Ethernet) + , m_rdev(makedev(get_network_rdev_major(), get_network_rdev_minor())) + { + ASSERT(minor(m_rdev) < 10); + ASSERT(m_type == Type::Ethernet); + + strcpy(m_name, "ethx"); + m_name[3] = minor(m_rdev) + '0'; + } + +} diff --git a/kernel/kernel/PCI.cpp b/kernel/kernel/PCI.cpp index 4a0c3b59..f80a3ef1 100644 --- a/kernel/kernel/PCI.cpp +++ b/kernel/kernel/PCI.cpp @@ -2,7 +2,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -187,11 +188,22 @@ namespace Kernel::PCI { case 0x00: if (E1000::probe(pci_device)) + { if (auto res = E1000::create(pci_device); res.is_error()) dprintln("E1000: {}", res.error()); - break; + break; + } + if (E1000E::probe(pci_device)) + { + if (auto res = E1000E::create(pci_device); res.is_error()) + dprintln("E1000E: {}", res.error()); + break; + } + // fall through default: - dprintln("unsupported ethernet device (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if()); + dprintln("unsupported network controller (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if()); + dprintln(" vendor id: {4H}", pci_device.vendor_id()); + dprintln(" device id: {4H}", pci_device.device_id()); break; } break;