From ddb7641b056ba71bfcdc649d668f54c4efacc324 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Mon, 29 Jun 2026 00:26:10 +0300 Subject: [PATCH] Kernel: Support hardware checksum offload on E1000 receive --- .../kernel/Networking/E1000/Definitions.h | 30 +++++++++++++ kernel/kernel/Networking/E1000/E1000.cpp | 44 +++++++++++++++---- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/kernel/include/kernel/Networking/E1000/Definitions.h b/kernel/include/kernel/Networking/E1000/Definitions.h index 68dfc2d6..5c3bbfec 100644 --- a/kernel/include/kernel/Networking/E1000/Definitions.h +++ b/kernel/include/kernel/Networking/E1000/Definitions.h @@ -29,6 +29,7 @@ namespace Kernel REG_TDLEN = 0x3808, REG_TDH = 0x3810, REG_TDT = 0x3818, + REG_RXCSUM = 0x5000, REG_MTA = 0x5200, }; @@ -167,6 +168,15 @@ namespace Kernel RCTL_BSIZE_16384 = (0b01 << 16) | RCTL_BSEX, }; + enum E1000_RXCSUM : uint32_t + { + RXSUM_IPOFLD = 1 << 8, + RXSUM_TUOFLD = 1 << 9, + RXSUM_CRCOFLD = 1 << 11, + RXSUM_IPPCE = 1 << 12, + RXSUM_PCSD = 1 << 13, + }; + enum E1000_CMD : uint8_t { CMD_EOP = 1 << 0, @@ -178,6 +188,26 @@ namespace Kernel CMD_IDE = 1 << 7, }; + enum E1000_RX_STS : uint8_t + { + RX_STS_IPCS = 1 << 6, + RX_STS_TCPCS = 1 << 5, + RX_STS_UDPCS = 1 << 5, + RX_STS_EOP = 1 << 1, + RX_STS_DD = 1 << 0, + }; + + enum E1000_RX_ERR : uint8_t + { + RX_ERR_RXE = 1 << 7, + RX_ERR_IPE = 1 << 6, + RX_ERR_TCPE = 1 << 5, + RX_ERR_CXE = 1 << 4, + RX_ERR_SEQ = 1 << 2, + RX_ERR_SE = 1 << 1, + RX_ERR_CE = 1 << 0, + }; + struct e1000_rx_desc { uint64_t addr; diff --git a/kernel/kernel/Networking/E1000/E1000.cpp b/kernel/kernel/Networking/E1000/E1000.cpp index 636387ed..479e8838 100644 --- a/kernel/kernel/Networking/E1000/E1000.cpp +++ b/kernel/kernel/Networking/E1000/E1000.cpp @@ -202,6 +202,8 @@ namespace Kernel rctrl |= RCTL_BSIZE_8192; write32(REG_RCTL, rctrl); + write32(REG_RXCSUM, RXSUM_IPOFLD | RXSUM_TUOFLD); + return {}; } @@ -330,20 +332,44 @@ namespace Kernel for (;;) { auto& descriptor = reinterpret_cast(m_rx_descriptor_region->vaddr())[rx_current]; - if (!(descriptor.status & 1)) + + const auto status = descriptor.status; + if (!(status & RX_STS_DD)) break; - ASSERT(descriptor.length <= E1000_RX_BUFFER_SIZE); - dprintln_if(DEBUG_E1000, "got {} bytes", (uint16_t)descriptor.length); + const auto errors = descriptor.errors; + if (!(status & RX_STS_EOP)) + dwarnln("multi descriptor packet??"); + else if (errors & (RX_ERR_CE | RX_ERR_SE | RX_ERR_RXE)) + dwarnln("descriptor error {2h}", errors); + else if ((status & RX_STS_IPCS) && (errors & RX_ERR_IPE)) + dwarnln("IPv4 checksum error"); + else if ((status & RX_STS_TCPCS) && (errors & RX_ERR_TCPE)) + dwarnln("TCP checkum error"); + else if ((status & RX_STS_UDPCS) && (errors & RX_ERR_TCPE)) + dwarnln("UDP checksum error"); + else + { + m_rx_lock.unlock(InterruptState::Enabled); - m_rx_lock.unlock(InterruptState::Enabled); + const uint32_t packet_length = descriptor.length; + ASSERT(packet_length <= E1000_RX_BUFFER_SIZE); - NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { - reinterpret_cast(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE), - descriptor.length - }, 0); + dprintln_if(DEBUG_E1000, "got {} bytes", packet_length); - m_rx_lock.lock(); + uint32_t validated_cksums = 0; + if ((status & RX_STS_IPCS) && !(errors & RX_ERR_IPE)) + validated_cksums |= CKSUM_IPV4; + if ((status & RX_STS_TCPCS) && !(errors & RX_ERR_TCPE)) + validated_cksums |= CKSUM_TCP; + if ((status & RX_STS_UDPCS) && !(errors & RX_ERR_TCPE)) + validated_cksums |= CKSUM_UDP; + + const uint8_t* packet_data = reinterpret_cast(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE); + NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { packet_data, packet_length }, validated_cksums); + + m_rx_lock.lock(); + } descriptor.status = 0;