Compare commits
5 Commits
f7e549e412
...
b8622f2b4b
Author | SHA1 | Date |
---|---|---|
Bananymous | b8622f2b4b | |
Bananymous | 7f0c39fe91 | |
Bananymous | a489be0e05 | |
Bananymous | 8e08046519 | |
Bananymous | 999eb53364 |
|
@ -65,6 +65,7 @@ set(KERNEL_SOURCES
|
||||||
kernel/Networking/NetworkLayer.cpp
|
kernel/Networking/NetworkLayer.cpp
|
||||||
kernel/Networking/NetworkManager.cpp
|
kernel/Networking/NetworkManager.cpp
|
||||||
kernel/Networking/NetworkSocket.cpp
|
kernel/Networking/NetworkSocket.cpp
|
||||||
|
kernel/Networking/RTL8169/RTL8169.cpp
|
||||||
kernel/Networking/TCPSocket.cpp
|
kernel/Networking/TCPSocket.cpp
|
||||||
kernel/Networking/UDPSocket.cpp
|
kernel/Networking/UDPSocket.cpp
|
||||||
kernel/Networking/UNIX/Socket.cpp
|
kernel/Networking/UNIX/Socket.cpp
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
enum RTL8169_IO_REGS : uint16_t
|
||||||
|
{
|
||||||
|
RTL8169_IO_IDR0 = 0x00,
|
||||||
|
RTL8169_IO_IDR1 = 0x01,
|
||||||
|
RTL8169_IO_IDR2 = 0x02,
|
||||||
|
RTL8169_IO_IDR3 = 0x03,
|
||||||
|
RTL8169_IO_IDR4 = 0x04,
|
||||||
|
RTL8169_IO_IDR5 = 0x05,
|
||||||
|
|
||||||
|
RTL8169_IO_TNPDS = 0x20,
|
||||||
|
RTL8169_IO_CR = 0x37,
|
||||||
|
RTL8169_IO_TPPoll = 0x38,
|
||||||
|
RTL8169_IO_IMR = 0x3C,
|
||||||
|
RTL8169_IO_ISR = 0x3E,
|
||||||
|
RTL8169_IO_TCR = 0x40,
|
||||||
|
RTL8169_IO_RCR = 0x44,
|
||||||
|
RTL8169_IO_9346CR = 0x50,
|
||||||
|
RTL8169_IO_PHYSts = 0x6C,
|
||||||
|
RTL8169_IO_RMS = 0xDA,
|
||||||
|
RTL8169_IO_RDSAR = 0xE4,
|
||||||
|
RTL8169_IO_MTPS = 0xEC,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169_CR : uint8_t
|
||||||
|
{
|
||||||
|
RTL8169_CR_TE = 1u << 2,
|
||||||
|
RTL8169_CR_RE = 1u << 3,
|
||||||
|
RTL8169_CR_RST = 1u << 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169_TPPoll : uint8_t
|
||||||
|
{
|
||||||
|
RTL8169_TPPoll_FSWInt = 1u << 0,
|
||||||
|
RTL8169_TPPoll_NPQ = 1u << 6,
|
||||||
|
RTL8169_TPPoll_HPQ = 1u << 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169_IR : uint16_t
|
||||||
|
{
|
||||||
|
RTL8169_IR_ROK = 1u << 0,
|
||||||
|
RTL8169_IR_RER = 1u << 1,
|
||||||
|
RTL8169_IR_TOK = 1u << 2,
|
||||||
|
RTL8169_IR_TER = 1u << 3,
|
||||||
|
RTL8169_IR_RDU = 1u << 4,
|
||||||
|
RTL8169_IR_LinkChg = 1u << 5,
|
||||||
|
RTL8169_IR_FVOW = 1u << 6,
|
||||||
|
RTL8169_IR_TDU = 1u << 7,
|
||||||
|
RTL8169_IR_SWInt = 1u << 8,
|
||||||
|
RTL8169_IR_FEmp = 1u << 9,
|
||||||
|
RTL8169_IR_TimeOut = 1u << 14,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169_TCR : uint32_t
|
||||||
|
{
|
||||||
|
RTL8169_TCR_MXDMA_16 = 0b000u << 8,
|
||||||
|
RTL8169_TCR_MXDMA_32 = 0b001u << 8,
|
||||||
|
RTL8169_TCR_MXDMA_64 = 0b010u << 8,
|
||||||
|
RTL8169_TCR_MXDMA_128 = 0b011u << 8,
|
||||||
|
RTL8169_TCR_MXDMA_256 = 0b100u << 8,
|
||||||
|
RTL8169_TCR_MXDMA_512 = 0b101u << 8,
|
||||||
|
RTL8169_TCR_MXDMA_1024 = 0b110u << 8,
|
||||||
|
RTL8169_TCR_MXDMA_UNLIMITED = 0b111u << 8,
|
||||||
|
|
||||||
|
RTL8169_TCR_TX_NOCRC = 1u << 16,
|
||||||
|
|
||||||
|
RTL8169_TCR_LOOPBACK = 0b01u << 17,
|
||||||
|
|
||||||
|
RTL8169_TCR_IFG_0 = (0u << 19) | (0b11 << 24),
|
||||||
|
RTL8169_TCR_IFG_8 = (1u << 19) | (0b01 << 24),
|
||||||
|
RTL8169_TCR_IFG_16 = (1u << 19) | (0b11 << 24),
|
||||||
|
RTL8169_TCR_IFG_24 = (0u << 19) | (0b01 << 24),
|
||||||
|
RTL8169_TCR_IFG_48 = (0u << 19) | (0b10 << 24),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169_RCR : uint32_t
|
||||||
|
{
|
||||||
|
RTL8169_RCR_AAP = 1u << 0, // accept all packets with destination
|
||||||
|
RTL8169_RCR_APM = 1u << 1, // accept physical matches
|
||||||
|
RTL8169_RCR_AM = 1u << 2, // accept multicast
|
||||||
|
RTL8169_RCR_AB = 1u << 3, // accept broadcast
|
||||||
|
RTL8169_RCR_AR = 1u << 4, // accept runt
|
||||||
|
RTL8169_RCR_AER = 1u << 5, // accept error
|
||||||
|
|
||||||
|
RTL8169_RCR_MXDMA_64 = 0b010u << 8,
|
||||||
|
RTL8169_RCR_MXDMA_128 = 0b011u << 8,
|
||||||
|
RTL8169_RCR_MXDMA_256 = 0b100u << 8,
|
||||||
|
RTL8169_RCR_MXDMA_512 = 0b101u << 8,
|
||||||
|
RTL8169_RCR_MXDMA_1024 = 0b110u << 8,
|
||||||
|
RTL8169_RCR_MXDMA_UNLIMITED = 0b111u << 8,
|
||||||
|
|
||||||
|
RTL8169_RCR_RXFTH_64 = 0b010u << 13,
|
||||||
|
RTL8169_RCR_RXFTH_128 = 0b011u << 13,
|
||||||
|
RTL8169_RCR_RXFTH_256 = 0b100u << 13,
|
||||||
|
RTL8169_RCR_RXFTH_512 = 0b101u << 13,
|
||||||
|
RTL8169_RCR_RXFTH_1024 = 0b110u << 13,
|
||||||
|
RTL8169_RCR_RXFTH_NO = 0b111u << 13,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169_9346CR : uint8_t
|
||||||
|
{
|
||||||
|
RTL8169_9346CR_MODE_NORMAL = 0b00 << 6,
|
||||||
|
RTL8169_9346CR_MODE_CONFIG = 0b11 << 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169_PHYSts : uint8_t
|
||||||
|
{
|
||||||
|
RTL8169_PHYSts_FullDup = 1u << 0,
|
||||||
|
RTL8169_PHYSts_LinkSts = 1u << 1,
|
||||||
|
RTL8169_PHYSts_10M = 1u << 2,
|
||||||
|
RTL8169_PHYSts_100M = 1u << 3,
|
||||||
|
RTL8169_PHYSts_1000MF = 1u << 4,
|
||||||
|
RTL8169_PHYSts_RxFlow = 1u << 5,
|
||||||
|
RTL8169_PHYSts_TxFlow = 1u << 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169_RMS : uint16_t
|
||||||
|
{
|
||||||
|
// 8192 - 1
|
||||||
|
RTL8169_RMS_MAX = 0x1FFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169_MTPS : uint8_t
|
||||||
|
{
|
||||||
|
RTL8169_MTPS_MAX = 0x3B,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RTL8169Descriptor
|
||||||
|
{
|
||||||
|
uint32_t command;
|
||||||
|
uint32_t vlan;
|
||||||
|
uint32_t buffer_low;
|
||||||
|
uint32_t buffer_high;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RTL8169DescriptorCommand : uint32_t
|
||||||
|
{
|
||||||
|
RTL8169_DESC_CMD_LGSEN = 1u << 27,
|
||||||
|
RTL8169_DESC_CMD_LS = 1u << 28,
|
||||||
|
RTL8169_DESC_CMD_FS = 1u << 29,
|
||||||
|
RTL8169_DESC_CMD_EOR = 1u << 30,
|
||||||
|
RTL8169_DESC_CMD_OWN = 1u << 31,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <kernel/Interruptable.h>
|
||||||
|
#include <kernel/Memory/DMARegion.h>
|
||||||
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
|
#include <kernel/PCI.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class RTL8169 final : public NetworkInterface, public Interruptable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool probe(PCI::Device&);
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<RTL8169>> create(PCI::Device&);
|
||||||
|
|
||||||
|
virtual BAN::MACAddress get_mac_address() const override { return m_mac_address; }
|
||||||
|
|
||||||
|
virtual bool link_up() override { return m_link_up; }
|
||||||
|
virtual int link_speed() override;
|
||||||
|
|
||||||
|
virtual size_t payload_mtu() const override { return 7436 - sizeof(EthernetHeader); }
|
||||||
|
|
||||||
|
virtual void handle_irq() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RTL8169(PCI::Device& pci_device)
|
||||||
|
: m_pci_device(pci_device)
|
||||||
|
{ }
|
||||||
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override;
|
||||||
|
|
||||||
|
virtual bool can_read_impl() const override { return false; }
|
||||||
|
virtual bool can_write_impl() const override { return false; }
|
||||||
|
virtual bool has_error_impl() const override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::ErrorOr<void> reset();
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> initialize_rx();
|
||||||
|
BAN::ErrorOr<void> initialize_tx();
|
||||||
|
|
||||||
|
void enable_link();
|
||||||
|
BAN::ErrorOr<void> enable_interrupt();
|
||||||
|
|
||||||
|
void handle_receive();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PCI::Device& m_pci_device;
|
||||||
|
BAN::UniqPtr<PCI::BarRegion> m_io_bar_region;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t m_rx_descriptor_count = 256;
|
||||||
|
static constexpr size_t m_tx_descriptor_count = 256;
|
||||||
|
|
||||||
|
BAN::UniqPtr<DMARegion> m_rx_buffer_region;
|
||||||
|
BAN::UniqPtr<DMARegion> m_tx_buffer_region;
|
||||||
|
BAN::UniqPtr<DMARegion> m_rx_descriptor_region;
|
||||||
|
BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
|
||||||
|
|
||||||
|
SpinLock m_lock;
|
||||||
|
ThreadBlocker m_thread_blocker;
|
||||||
|
|
||||||
|
uint32_t m_rx_current { 0 };
|
||||||
|
size_t m_tx_current { 0 };
|
||||||
|
|
||||||
|
BAN::MACAddress m_mac_address {};
|
||||||
|
BAN::Atomic<bool> m_link_up { false };
|
||||||
|
|
||||||
|
friend class BAN::RefPtr<RTL8169>;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -17,7 +17,11 @@ namespace Kernel
|
||||||
static void panic_impl(const char* location, const char* message, Args&&... args)
|
static void panic_impl(const char* location, const char* message, Args&&... args)
|
||||||
{
|
{
|
||||||
asm volatile("cli");
|
asm volatile("cli");
|
||||||
|
|
||||||
|
const bool had_debug_lock = Debug::s_debug_lock.current_processor_has_lock();
|
||||||
derrorln("Kernel panic at {}", location);
|
derrorln("Kernel panic at {}", location);
|
||||||
|
if (had_debug_lock)
|
||||||
|
derrorln(" while having debug lock...");
|
||||||
derrorln(message, BAN::forward<Args>(args)...);
|
derrorln(message, BAN::forward<Args>(args)...);
|
||||||
if (!g_paniced)
|
if (!g_paniced)
|
||||||
{
|
{
|
||||||
|
|
|
@ -92,6 +92,7 @@ namespace Kernel
|
||||||
};
|
};
|
||||||
Buffer m_output;
|
Buffer m_output;
|
||||||
|
|
||||||
|
protected:
|
||||||
RecursiveSpinLock m_write_lock;
|
RecursiveSpinLock m_write_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace Kernel
|
||||||
virtual uint64_t ns_since_boot() const override;
|
virtual uint64_t ns_since_boot() const override;
|
||||||
virtual timespec time_since_boot() const override;
|
virtual timespec time_since_boot() const override;
|
||||||
|
|
||||||
|
virtual bool pre_scheduler_sleep_needs_lock() const override { return false; }
|
||||||
virtual void pre_scheduler_sleep_ns(uint64_t) override;
|
virtual void pre_scheduler_sleep_ns(uint64_t) override;
|
||||||
|
|
||||||
virtual void handle_irq() override;
|
virtual void handle_irq() override;
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace Kernel
|
||||||
virtual uint64_t ns_since_boot() const override;
|
virtual uint64_t ns_since_boot() const override;
|
||||||
virtual timespec time_since_boot() const override;
|
virtual timespec time_since_boot() const override;
|
||||||
|
|
||||||
|
virtual bool pre_scheduler_sleep_needs_lock() const override { return true; }
|
||||||
virtual void pre_scheduler_sleep_ns(uint64_t) override;
|
virtual void pre_scheduler_sleep_ns(uint64_t) override;
|
||||||
|
|
||||||
virtual void handle_irq() override;
|
virtual void handle_irq() override;
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace Kernel
|
||||||
virtual uint64_t ns_since_boot() const = 0;
|
virtual uint64_t ns_since_boot() const = 0;
|
||||||
virtual timespec time_since_boot() const = 0;
|
virtual timespec time_since_boot() const = 0;
|
||||||
|
|
||||||
|
virtual bool pre_scheduler_sleep_needs_lock() const = 0;
|
||||||
virtual void pre_scheduler_sleep_ns(uint64_t) = 0;
|
virtual void pre_scheduler_sleep_ns(uint64_t) = 0;
|
||||||
|
|
||||||
void dont_invoke_scheduler() { m_should_invoke_scheduler = false; }
|
void dont_invoke_scheduler() { m_should_invoke_scheduler = false; }
|
||||||
|
@ -39,6 +40,7 @@ namespace Kernel
|
||||||
virtual uint64_t ns_since_boot() const override;
|
virtual uint64_t ns_since_boot() const override;
|
||||||
virtual timespec time_since_boot() const override;
|
virtual timespec time_since_boot() const override;
|
||||||
|
|
||||||
|
virtual bool pre_scheduler_sleep_needs_lock() const override;
|
||||||
virtual void pre_scheduler_sleep_ns(uint64_t) override;
|
virtual void pre_scheduler_sleep_ns(uint64_t) override;
|
||||||
|
|
||||||
void sleep_ms(uint64_t ms) const { return sleep_ns(ms * 1'000'000); }
|
void sleep_ms(uint64_t ms) const { return sleep_ns(ms * 1'000'000); }
|
||||||
|
|
|
@ -253,11 +253,11 @@ namespace Kernel
|
||||||
const auto send_ipi =
|
const auto send_ipi =
|
||||||
[&](uint8_t processor, uint32_t data, uint64_t ud)
|
[&](uint8_t processor, uint32_t data, uint64_t ud)
|
||||||
{
|
{
|
||||||
|
while ((read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_delivery_status_send_pending) == ICR_LO_delivery_status_send_pending)
|
||||||
|
__builtin_ia32_pause();
|
||||||
write_to_local_apic(LAPIC_ICR_HI_REG, (read_from_local_apic(LAPIC_ICR_HI_REG) & 0x00FFFFFF) | (processor << 24));
|
write_to_local_apic(LAPIC_ICR_HI_REG, (read_from_local_apic(LAPIC_ICR_HI_REG) & 0x00FFFFFF) | (processor << 24));
|
||||||
write_to_local_apic(LAPIC_ICR_LO_REG, data);
|
write_to_local_apic(LAPIC_ICR_LO_REG, data);
|
||||||
udelay(ud);
|
udelay(ud);
|
||||||
while ((read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_delivery_status_send_pending) == ICR_LO_delivery_status_send_pending)
|
|
||||||
__builtin_ia32_pause();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
dprintln("System has {} processors", m_processors.size());
|
dprintln("System has {} processors", m_processors.size());
|
||||||
|
@ -402,10 +402,13 @@ namespace Kernel
|
||||||
|
|
||||||
void APIC::initialize_timer()
|
void APIC::initialize_timer()
|
||||||
{
|
{
|
||||||
{
|
ASSERT(Kernel::Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||||
|
|
||||||
constexpr uint64_t measuring_duration_ms = 100;
|
constexpr uint64_t measuring_duration_ms = 100;
|
||||||
|
|
||||||
SpinLockGuard _(s_timer_init_lock);
|
const bool needs_lock = SystemTimer::get().pre_scheduler_sleep_needs_lock();
|
||||||
|
if (needs_lock)
|
||||||
|
s_timer_init_lock.lock();
|
||||||
|
|
||||||
write_to_local_apic(LAPIC_TIMER_LVT, TimerModeOneShot | TimerMask);
|
write_to_local_apic(LAPIC_TIMER_LVT, TimerModeOneShot | TimerMask);
|
||||||
write_to_local_apic(LAPIC_TIMER_DIVIDE_REG, DivideBy2);
|
write_to_local_apic(LAPIC_TIMER_DIVIDE_REG, DivideBy2);
|
||||||
|
@ -415,8 +418,10 @@ namespace Kernel
|
||||||
const uint32_t counter = read_from_local_apic(LAPIC_TIMER_CURRENT_REG);
|
const uint32_t counter = read_from_local_apic(LAPIC_TIMER_CURRENT_REG);
|
||||||
m_lapic_timer_frequency_hz = static_cast<uint64_t>(0xFFFFFFFF - counter) * 2 * (1000 / measuring_duration_ms);
|
m_lapic_timer_frequency_hz = static_cast<uint64_t>(0xFFFFFFFF - counter) * 2 * (1000 / measuring_duration_ms);
|
||||||
|
|
||||||
|
if (needs_lock)
|
||||||
|
s_timer_init_lock.unlock(InterruptState::Disabled);
|
||||||
|
|
||||||
dprintln("CPU {}: lapic timer frequency: {} Hz", Kernel::Processor::current_id(), m_lapic_timer_frequency_hz);
|
dprintln("CPU {}: lapic timer frequency: {} Hz", Kernel::Processor::current_id(), m_lapic_timer_frequency_hz);
|
||||||
}
|
|
||||||
|
|
||||||
write_to_local_apic(LAPIC_TIMER_LVT, TimerModePeriodic | (IRQ_VECTOR_BASE + IRQ_TIMER));
|
write_to_local_apic(LAPIC_TIMER_LVT, TimerModePeriodic | (IRQ_VECTOR_BASE + IRQ_TIMER));
|
||||||
write_to_local_apic(LAPIC_TIMER_INITIAL_REG, m_lapic_timer_frequency_hz / 2 / 100);
|
write_to_local_apic(LAPIC_TIMER_INITIAL_REG, m_lapic_timer_frequency_hz / 2 / 100);
|
||||||
|
|
|
@ -360,6 +360,8 @@ done:
|
||||||
{
|
{
|
||||||
if (g_paniced)
|
if (g_paniced)
|
||||||
{
|
{
|
||||||
|
while (Debug::s_debug_lock.current_processor_has_lock())
|
||||||
|
Debug::s_debug_lock.unlock(InterruptState::Disabled);
|
||||||
dprintln("Processor {} halted", Processor::current_id());
|
dprintln("Processor {} halted", Processor::current_id());
|
||||||
if (InterruptController::is_initialized())
|
if (InterruptController::is_initialized())
|
||||||
InterruptController::get().broadcast_ipi();
|
InterruptController::get().broadcast_ipi();
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <kernel/Networking/E1000/E1000E.h>
|
#include <kernel/Networking/E1000/E1000E.h>
|
||||||
#include <kernel/Networking/ICMP.h>
|
#include <kernel/Networking/ICMP.h>
|
||||||
#include <kernel/Networking/NetworkManager.h>
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
|
#include <kernel/Networking/RTL8169/RTL8169.h>
|
||||||
#include <kernel/Networking/TCPSocket.h>
|
#include <kernel/Networking/TCPSocket.h>
|
||||||
#include <kernel/Networking/UDPSocket.h>
|
#include <kernel/Networking/UDPSocket.h>
|
||||||
#include <kernel/Networking/UNIX/Socket.h>
|
#include <kernel/Networking/UNIX/Socket.h>
|
||||||
|
@ -48,6 +49,11 @@ namespace Kernel
|
||||||
interface = TRY(E1000E::create(pci_device));
|
interface = TRY(E1000E::create(pci_device));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (RTL8169::probe(pci_device))
|
||||||
|
{
|
||||||
|
interface = TRY(RTL8169::create(pci_device));
|
||||||
|
break;
|
||||||
|
}
|
||||||
// fall through
|
// fall through
|
||||||
default:
|
default:
|
||||||
dprintln("unsupported network controller (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());
|
||||||
|
@ -121,6 +127,8 @@ namespace Kernel
|
||||||
|
|
||||||
void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet)
|
void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet)
|
||||||
{
|
{
|
||||||
|
if (packet.size() < sizeof(EthernetHeader))
|
||||||
|
return;
|
||||||
auto ethernet_header = packet.as<const EthernetHeader>();
|
auto ethernet_header = packet.as<const EthernetHeader>();
|
||||||
|
|
||||||
switch (ethernet_header.ether_type)
|
switch (ethernet_header.ether_type)
|
||||||
|
|
|
@ -0,0 +1,295 @@
|
||||||
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
|
#include <kernel/Networking/RTL8169/Definitions.h>
|
||||||
|
#include <kernel/Networking/RTL8169/RTL8169.h>
|
||||||
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
bool RTL8169::probe(PCI::Device& pci_device)
|
||||||
|
{
|
||||||
|
if (pci_device.vendor_id() != 0x10ec)
|
||||||
|
return false;
|
||||||
|
switch (pci_device.device_id())
|
||||||
|
{
|
||||||
|
case 0x8161:
|
||||||
|
case 0x8168:
|
||||||
|
case 0x8169:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<RTL8169>> RTL8169::create(PCI::Device& pci_device)
|
||||||
|
{
|
||||||
|
auto rtl8169 = TRY(BAN::RefPtr<RTL8169>::create(pci_device));
|
||||||
|
TRY(rtl8169->initialize());
|
||||||
|
return rtl8169;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> RTL8169::initialize()
|
||||||
|
{
|
||||||
|
m_pci_device.enable_bus_mastering();
|
||||||
|
|
||||||
|
m_io_bar_region = TRY(m_pci_device.allocate_bar_region(0));
|
||||||
|
if (m_io_bar_region->type() != PCI::BarType::IO)
|
||||||
|
{
|
||||||
|
dwarnln("RTL8169 BAR0 is not IO space");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintln("Initializing RTL8169");
|
||||||
|
|
||||||
|
TRY(reset());
|
||||||
|
|
||||||
|
dprintln(" reset done");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 6; i++)
|
||||||
|
m_mac_address.address[i] = m_io_bar_region->read8(RTL8169_IO_IDR0 + i);
|
||||||
|
dprintln(" MAC {}", m_mac_address);
|
||||||
|
|
||||||
|
// unlock config registers
|
||||||
|
m_io_bar_region->write8(RTL8169_IO_9346CR, RTL8169_9346CR_MODE_CONFIG);
|
||||||
|
|
||||||
|
TRY(initialize_rx());
|
||||||
|
TRY(initialize_tx());
|
||||||
|
m_io_bar_region->write8(RTL8169_IO_CR, RTL8169_CR_RE | RTL8169_CR_TE);
|
||||||
|
dprintln(" descriptors initialized");
|
||||||
|
|
||||||
|
m_link_up = m_io_bar_region->read8(RTL8169_IO_PHYSts) & RTL8169_PHYSts_LinkSts;
|
||||||
|
if (m_link_up)
|
||||||
|
dprintln(" link speed {}", link_speed());
|
||||||
|
|
||||||
|
TRY(enable_interrupt());
|
||||||
|
dprintln(" interrupts enabled");
|
||||||
|
|
||||||
|
// lock config registers
|
||||||
|
m_io_bar_region->write8(RTL8169_IO_9346CR, RTL8169_9346CR_MODE_NORMAL);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> RTL8169::reset()
|
||||||
|
{
|
||||||
|
m_io_bar_region->write8(RTL8169_IO_CR, RTL8169_CR_RST);
|
||||||
|
|
||||||
|
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 100;
|
||||||
|
while (m_io_bar_region->read8(RTL8169_IO_CR) & RTL8169_CR_RST)
|
||||||
|
if (SystemTimer::get().ms_since_boot() >= timeout_ms)
|
||||||
|
return BAN::Error::from_errno(ETIMEDOUT);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> RTL8169::initialize_rx()
|
||||||
|
{
|
||||||
|
// each buffer is 7440 bytes + padding = 8192
|
||||||
|
constexpr size_t buffer_size = 2 * PAGE_SIZE;
|
||||||
|
|
||||||
|
m_rx_buffer_region = TRY(DMARegion::create(m_rx_descriptor_count * buffer_size));
|
||||||
|
m_rx_descriptor_region = TRY(DMARegion::create(m_rx_descriptor_count * sizeof(RTL8169Descriptor)));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_rx_descriptor_count; i++)
|
||||||
|
{
|
||||||
|
const paddr_t rx_buffer_paddr = m_rx_buffer_region->paddr() + i * buffer_size;
|
||||||
|
|
||||||
|
uint32_t command = 0x1FF8 | RTL8169_DESC_CMD_OWN;
|
||||||
|
if (i == m_rx_descriptor_count - 1)
|
||||||
|
command |= RTL8169_DESC_CMD_EOR;
|
||||||
|
|
||||||
|
auto& rx_descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[i];
|
||||||
|
rx_descriptor.command = command;
|
||||||
|
rx_descriptor.vlan = 0;
|
||||||
|
rx_descriptor.buffer_low = rx_buffer_paddr & 0xFFFFFFFF;
|
||||||
|
rx_descriptor.buffer_high = rx_buffer_paddr >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure rx descriptor addresses
|
||||||
|
m_io_bar_region->write32(RTL8169_IO_RDSAR + 0, m_rx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||||
|
m_io_bar_region->write32(RTL8169_IO_RDSAR + 4, m_rx_descriptor_region->paddr() >> 32);
|
||||||
|
|
||||||
|
// configure receibe control (no fifo threshold, max dma burst 1024, accept physical match, broadcast, multicast)
|
||||||
|
m_io_bar_region->write32(RTL8169_IO_RCR,
|
||||||
|
RTL8169_RCR_RXFTH_NO | RTL8169_RCR_MXDMA_1024 | RTL8169_RCR_AB | RTL8169_RCR_AM | RTL8169_RCR_APM
|
||||||
|
);
|
||||||
|
|
||||||
|
m_io_bar_region->write32(0x44, 0b111111 | (0b111 << 8) | (0b111 << 13));
|
||||||
|
|
||||||
|
// configure max rx packet size
|
||||||
|
m_io_bar_region->write16(RTL8169_IO_RMS, RTL8169_RMS_MAX);
|
||||||
|
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> RTL8169::initialize_tx()
|
||||||
|
{
|
||||||
|
// each buffer is 7440 bytes + padding = 8192
|
||||||
|
constexpr size_t buffer_size = 2 * PAGE_SIZE;
|
||||||
|
|
||||||
|
m_tx_buffer_region = TRY(DMARegion::create(m_tx_descriptor_count * buffer_size));
|
||||||
|
m_tx_descriptor_region = TRY(DMARegion::create(m_tx_descriptor_count * sizeof(RTL8169Descriptor)));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_tx_descriptor_count; i++)
|
||||||
|
{
|
||||||
|
const paddr_t tx_buffer_paddr = m_tx_buffer_region->paddr() + i * buffer_size;
|
||||||
|
|
||||||
|
uint32_t command = 0;
|
||||||
|
if (i == m_tx_descriptor_count - 1)
|
||||||
|
command |= RTL8169_DESC_CMD_EOR;
|
||||||
|
|
||||||
|
auto& tx_descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr())[i];
|
||||||
|
tx_descriptor.command = command;
|
||||||
|
tx_descriptor.vlan = 0;
|
||||||
|
tx_descriptor.buffer_low = tx_buffer_paddr & 0xFFFFFFFF;
|
||||||
|
tx_descriptor.buffer_high = tx_buffer_paddr >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure tx descriptor addresses
|
||||||
|
m_io_bar_region->write32(RTL8169_IO_TNPDS + 0, m_tx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||||
|
m_io_bar_region->write32(RTL8169_IO_TNPDS + 4, m_tx_descriptor_region->paddr() >> 32);
|
||||||
|
|
||||||
|
// configure transmit control (standard ifg, max dma burst 1024)
|
||||||
|
m_io_bar_region->write32(RTL8169_IO_TCR, RTL8169_TCR_IFG_0 | RTL8169_TCR_MXDMA_1024);
|
||||||
|
|
||||||
|
// configure max tx packet size
|
||||||
|
m_io_bar_region->write8(RTL8169_IO_MTPS, RTL8169_MTPS_MAX);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> RTL8169::enable_interrupt()
|
||||||
|
{
|
||||||
|
TRY(m_pci_device.reserve_irqs(1));
|
||||||
|
set_irq(m_pci_device.get_irq(0));
|
||||||
|
Interruptable::enable_interrupt();
|
||||||
|
|
||||||
|
m_io_bar_region->write16(RTL8169_IO_IMR,
|
||||||
|
RTL8169_IR_ROK
|
||||||
|
| RTL8169_IR_RER
|
||||||
|
| RTL8169_IR_TOK
|
||||||
|
| RTL8169_IR_TER
|
||||||
|
| RTL8169_IR_RDU
|
||||||
|
| RTL8169_IR_LinkChg
|
||||||
|
| RTL8169_IR_FVOW
|
||||||
|
| RTL8169_IR_TDU
|
||||||
|
);
|
||||||
|
m_io_bar_region->write16(RTL8169_IO_ISR, 0xFFFF);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int RTL8169::link_speed()
|
||||||
|
{
|
||||||
|
if (!link_up())
|
||||||
|
return 0;
|
||||||
|
const uint8_t phy_status = m_io_bar_region->read8(RTL8169_IO_PHYSts);
|
||||||
|
if (phy_status & RTL8169_PHYSts_1000MF)
|
||||||
|
return 1000;
|
||||||
|
if (phy_status & RTL8169_PHYSts_100M)
|
||||||
|
return 100;
|
||||||
|
if (phy_status & RTL8169_PHYSts_10M)
|
||||||
|
return 10;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> RTL8169::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer)
|
||||||
|
{
|
||||||
|
constexpr size_t buffer_size = 8192;
|
||||||
|
|
||||||
|
const uint16_t packet_size = sizeof(EthernetHeader) + buffer.size();
|
||||||
|
if (packet_size > buffer_size)
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
|
if (!link_up())
|
||||||
|
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||||
|
|
||||||
|
auto state = m_lock.lock();
|
||||||
|
const uint32_t tx_current = m_tx_current;
|
||||||
|
m_tx_current = (m_tx_current + 1) % m_tx_descriptor_count;
|
||||||
|
m_lock.unlock(state);
|
||||||
|
|
||||||
|
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr())[tx_current];
|
||||||
|
while (descriptor.command & RTL8169_DESC_CMD_OWN)
|
||||||
|
m_thread_blocker.block_with_timeout_ms(100);
|
||||||
|
|
||||||
|
auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + tx_current * buffer_size);
|
||||||
|
|
||||||
|
// write packet
|
||||||
|
auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(tx_buffer);
|
||||||
|
ethernet_header.dst_mac = destination;
|
||||||
|
ethernet_header.src_mac = get_mac_address();
|
||||||
|
ethernet_header.ether_type = protocol;
|
||||||
|
memcpy(tx_buffer + sizeof(EthernetHeader), buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
// give packet ownership to NIC
|
||||||
|
uint32_t command = packet_size | RTL8169_DESC_CMD_OWN | RTL8169_DESC_CMD_LS | RTL8169_DESC_CMD_FS;
|
||||||
|
if (tx_current >= m_tx_descriptor_count - 1)
|
||||||
|
command |= RTL8169_DESC_CMD_EOR;
|
||||||
|
descriptor.command = command;
|
||||||
|
|
||||||
|
// notify NIC about new packet
|
||||||
|
m_io_bar_region->write8(RTL8169_IO_TPPoll, RTL8169_TPPoll_NPQ);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTL8169::handle_irq()
|
||||||
|
{
|
||||||
|
const uint16_t interrupt_status = m_io_bar_region->read16(RTL8169_IO_ISR);
|
||||||
|
m_io_bar_region->write16(RTL8169_IO_ISR, interrupt_status);
|
||||||
|
|
||||||
|
if (interrupt_status & RTL8169_IR_LinkChg)
|
||||||
|
{
|
||||||
|
m_link_up = m_io_bar_region->read8(RTL8169_IO_PHYSts) & RTL8169_PHYSts_LinkSts;
|
||||||
|
dprintln("link status -> {}", m_link_up.load());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interrupt_status & RTL8169_IR_TOK)
|
||||||
|
m_thread_blocker.unblock();
|
||||||
|
|
||||||
|
if (interrupt_status & RTL8169_IR_RER)
|
||||||
|
dwarnln("Rx error");
|
||||||
|
if (interrupt_status & RTL8169_IR_TER)
|
||||||
|
dwarnln("Tx error");
|
||||||
|
if (interrupt_status & RTL8169_IR_RDU)
|
||||||
|
dwarnln("Rx descriptor not available");
|
||||||
|
if (interrupt_status & RTL8169_IR_FVOW)
|
||||||
|
dwarnln("Rx FIFO overflow");
|
||||||
|
// dont log TDU is sent after each sent packet
|
||||||
|
|
||||||
|
if (!(interrupt_status & RTL8169_IR_ROK))
|
||||||
|
return;
|
||||||
|
|
||||||
|
constexpr size_t buffer_size = 8192;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[m_rx_current];
|
||||||
|
if (descriptor.command & RTL8169_DESC_CMD_OWN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// packet buffer can only hold single packet, so we should not receive any multi-descriptor packets
|
||||||
|
ASSERT((descriptor.command & RTL8169_DESC_CMD_LS) && (descriptor.command & RTL8169_DESC_CMD_FS));
|
||||||
|
|
||||||
|
const uint16_t packet_length = descriptor.command & 0x3FFF;
|
||||||
|
if (packet_length > buffer_size)
|
||||||
|
dwarnln("Got {} bytes to {} byte buffer", packet_length, buffer_size);
|
||||||
|
else if (descriptor.command & (1u << 21))
|
||||||
|
; // descriptor has an error
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
|
||||||
|
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + m_rx_current * buffer_size),
|
||||||
|
packet_length
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rx_current = (m_rx_current + 1) % m_rx_descriptor_count;
|
||||||
|
|
||||||
|
descriptor.command = descriptor.command | RTL8169_DESC_CMD_OWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -49,6 +49,7 @@ namespace Kernel
|
||||||
|
|
||||||
void VirtualTTY::clear()
|
void VirtualTTY::clear()
|
||||||
{
|
{
|
||||||
|
SpinLockGuard _(m_write_lock);
|
||||||
for (uint32_t i = 0; i < m_width * m_height; i++)
|
for (uint32_t i = 0; i < m_width * m_height; i++)
|
||||||
m_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
|
m_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
|
||||||
m_terminal_driver->clear(m_background);
|
m_terminal_driver->clear(m_background);
|
||||||
|
@ -56,6 +57,8 @@ namespace Kernel
|
||||||
|
|
||||||
void VirtualTTY::set_font(const LibFont::Font& font)
|
void VirtualTTY::set_font(const LibFont::Font& font)
|
||||||
{
|
{
|
||||||
|
SpinLockGuard _(m_write_lock);
|
||||||
|
|
||||||
m_terminal_driver->set_font(font);
|
m_terminal_driver->set_font(font);
|
||||||
|
|
||||||
uint32_t new_width = m_terminal_driver->width();
|
uint32_t new_width = m_terminal_driver->width();
|
||||||
|
@ -86,6 +89,7 @@ namespace Kernel
|
||||||
|
|
||||||
void VirtualTTY::set_cursor_position(uint32_t x, uint32_t y)
|
void VirtualTTY::set_cursor_position(uint32_t x, uint32_t y)
|
||||||
{
|
{
|
||||||
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
static uint32_t last_x = -1;
|
static uint32_t last_x = -1;
|
||||||
static uint32_t last_y = -1;
|
static uint32_t last_y = -1;
|
||||||
if (last_x != uint32_t(-1) && last_y != uint32_t(-1))
|
if (last_x != uint32_t(-1) && last_y != uint32_t(-1))
|
||||||
|
@ -98,6 +102,7 @@ namespace Kernel
|
||||||
|
|
||||||
void VirtualTTY::reset_ansi()
|
void VirtualTTY::reset_ansi()
|
||||||
{
|
{
|
||||||
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
m_ansi_state.index = 0;
|
m_ansi_state.index = 0;
|
||||||
m_ansi_state.nums[0] = -1;
|
m_ansi_state.nums[0] = -1;
|
||||||
m_ansi_state.nums[1] = -1;
|
m_ansi_state.nums[1] = -1;
|
||||||
|
@ -107,6 +112,7 @@ namespace Kernel
|
||||||
|
|
||||||
void VirtualTTY::handle_ansi_csi_color()
|
void VirtualTTY::handle_ansi_csi_color()
|
||||||
{
|
{
|
||||||
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
switch (m_ansi_state.nums[0])
|
switch (m_ansi_state.nums[0])
|
||||||
{
|
{
|
||||||
case -1:
|
case -1:
|
||||||
|
@ -155,6 +161,7 @@ namespace Kernel
|
||||||
|
|
||||||
void VirtualTTY::handle_ansi_csi(uint8_t ch)
|
void VirtualTTY::handle_ansi_csi(uint8_t ch)
|
||||||
{
|
{
|
||||||
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
switch (ch)
|
switch (ch)
|
||||||
{
|
{
|
||||||
case '0': case '1': case '2': case '3': case '4':
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
@ -360,6 +367,7 @@ namespace Kernel
|
||||||
|
|
||||||
void VirtualTTY::render_from_buffer(uint32_t x, uint32_t y)
|
void VirtualTTY::render_from_buffer(uint32_t x, uint32_t y)
|
||||||
{
|
{
|
||||||
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
ASSERT(x < m_width && y < m_height);
|
ASSERT(x < m_width && y < m_height);
|
||||||
const auto& cell = m_buffer[y * m_width + x];
|
const auto& cell = m_buffer[y * m_width + x];
|
||||||
m_terminal_driver->putchar_at(cell.codepoint, x, y, cell.foreground, cell.background);
|
m_terminal_driver->putchar_at(cell.codepoint, x, y, cell.foreground, cell.background);
|
||||||
|
@ -367,6 +375,7 @@ namespace Kernel
|
||||||
|
|
||||||
void VirtualTTY::putchar_at(uint32_t codepoint, uint32_t x, uint32_t y)
|
void VirtualTTY::putchar_at(uint32_t codepoint, uint32_t x, uint32_t y)
|
||||||
{
|
{
|
||||||
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
ASSERT(x < m_width && y < m_height);
|
ASSERT(x < m_width && y < m_height);
|
||||||
auto& cell = m_buffer[y * m_width + x];
|
auto& cell = m_buffer[y * m_width + x];
|
||||||
cell.codepoint = codepoint;
|
cell.codepoint = codepoint;
|
||||||
|
@ -377,6 +386,8 @@ namespace Kernel
|
||||||
|
|
||||||
void VirtualTTY::putchar_impl(uint8_t ch)
|
void VirtualTTY::putchar_impl(uint8_t ch)
|
||||||
{
|
{
|
||||||
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
|
|
||||||
uint32_t codepoint = ch;
|
uint32_t codepoint = ch;
|
||||||
|
|
||||||
switch (m_state)
|
switch (m_state)
|
||||||
|
|
|
@ -69,6 +69,11 @@ namespace Kernel
|
||||||
return m_timer->time_since_boot();
|
return m_timer->time_since_boot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SystemTimer::pre_scheduler_sleep_needs_lock() const
|
||||||
|
{
|
||||||
|
return m_timer->pre_scheduler_sleep_needs_lock();
|
||||||
|
}
|
||||||
|
|
||||||
void SystemTimer::pre_scheduler_sleep_ns(uint64_t ns)
|
void SystemTimer::pre_scheduler_sleep_ns(uint64_t ns)
|
||||||
{
|
{
|
||||||
return m_timer->pre_scheduler_sleep_ns(ns);
|
return m_timer->pre_scheduler_sleep_ns(ns);
|
||||||
|
|
Loading…
Reference in New Issue