Skip to content

Commit

Permalink
Kernel: Beginnings of networking stuff!
Browse files Browse the repository at this point in the history
  • Loading branch information
byteduck committed Mar 12, 2024
1 parent 11e0dd7 commit 6537543
Show file tree
Hide file tree
Showing 16 changed files with 1,014 additions and 2 deletions.
5 changes: 4 additions & 1 deletion kernel/CMakeLists.txt
Expand Up @@ -171,7 +171,10 @@ SET(KERNEL_SRCS
syscall/uname.cpp
VMWare.cpp
Processor.cpp
StackWalker.cpp)
StackWalker.cpp
net/NetworkAdapter.cpp
net/E1000Adapter.cpp
net/NetworkManager.cpp)

add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated/duckos_version.h"
Expand Down
29 changes: 28 additions & 1 deletion kernel/IO.cpp
Expand Up @@ -18,6 +18,8 @@
*/

#include "IO.h"
#include "kstd/kstdio.h"
#include "memory/MemoryManager.h"

void IO::wait() {
asm volatile ( "jmp 1f\n\t"
Expand Down Expand Up @@ -53,4 +55,29 @@ uint32_t IO::inl(uint16_t port){
uint32_t ret;
asm volatile ("inl %1, %0" : "=a" (ret) : "dN" (port));
return ret;
}
}

IO::Window::Window(PCI::Address addr, uint8_t bar) {
auto bar_val = PCI::read_dword(addr, bar);
if (!(bar_val & 0x1u)) {
// Memory IO
auto type = (bar_val >> 1) & 0x3u;
m_prefetchable = bar_val & 0x8u;
switch (type) {
case 0:
m_type = Mem32;
m_addr = bar_val & ~0xFu;
break;
default:
ASSERT(false);
}

PCI::write_dword(addr, bar, 0xFFFFFFFF);
m_size = ~(PCI::read_dword(addr, bar) & (~0xfull)) + 1;
PCI::write_dword(addr, bar, bar_val);
m_vm_region = MM.alloc_mapped_region(m_addr, m_size);
} else {
m_type = IOSpace;
m_addr = bar_val & ~0x3u;
}
}
60 changes: 60 additions & 0 deletions kernel/IO.h
Expand Up @@ -20,6 +20,9 @@
#pragma once

#include <kernel/kstd/unix_types.h>
#include "pci/PCI.h"
#include "kstd/Arc.h"
#include "memory/VMRegion.h"

namespace IO {
void wait();
Expand All @@ -33,6 +36,63 @@ namespace IO {
while(us--)
inb(0x80);
}

class Window {
public:
enum Type {
Invalid, Mem16, Mem32, Mem64, IOSpace
};

Window() = default;
Window(PCI::Address addr, uint8_t bar);

template<typename T>
T in(size_t offset) {
ASSERT(m_type != Invalid);
if (m_type == Type::IOSpace) {
if constexpr(sizeof(T) == 1)
return inb(m_addr + offset);
else if constexpr(sizeof(T) == 2)
return inw(m_addr + offset);
else if constexpr(sizeof(T) == 4)
return inl(m_addr + offset);
static_assert(sizeof(T) <= 4 && sizeof(T) != 3);
} else {
return *((T*) (m_vm_region->start() + offset));
}
}

uint8_t in8(size_t offset) { return in<uint8_t>(offset); }
uint16_t in16(size_t offset) { return in<uint16_t>(offset); }
uint32_t in32(size_t offset) { return in<uint32_t>(offset); }

template<typename T>
void out(size_t offset, T& data) {
ASSERT(m_type != Invalid);
if (m_type == Type::IOSpace) {
if constexpr(sizeof(T) == 1)
outb(m_addr + offset, data);
else if constexpr(sizeof(T) == 2)
outw(m_addr + offset, data);
else if constexpr(sizeof(T) == 4)
outl(m_addr + offset, data);
static_assert(sizeof(T) <= 4 && sizeof(T) != 3);
} else {
*((T*) (m_vm_region->start() + offset)) = data;
}
}

void out8(size_t offset, uint8_t val) { return out<uint8_t>(offset, val); }
void out16(size_t offset, uint16_t val) { return out<uint16_t>(offset, val); }
void out32(size_t offset, uint32_t val) { return out<uint32_t>(offset, val); }

private:
Type m_type = Invalid;
size_t m_size = 0;
size_t m_addr = 0;
kstd::Arc<VMRegion> m_vm_region;
bool m_prefetchable = false;
};
};


84 changes: 84 additions & 0 deletions kernel/api/endian.h
@@ -0,0 +1,84 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright © 2016-2024 Byteduck */

#pragma once

#include "stdint.h"

#ifdef __cplusplus

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
constexpr static bool __little_endian = true;
#else
constexpr static bool __little_endian = false;
#endif

template<typename T>
inline constexpr T swap_endianness(T val) {
if constexpr(sizeof(T) == 1)
return val;
else if constexpr (sizeof(T) == 2)
return static_cast<T>(__builtin_bswap16(static_cast<uint16_t>(val)));
else if constexpr (sizeof(T) == 4)
return static_cast<T>(__builtin_bswap32(static_cast<uint32_t>(val)));
else if constexpr (sizeof(T) == 8)
return static_cast<T>(__builtin_bswap64(static_cast<uint64_t>(val)));
else
static_assert("Cannot swap endianness of anything larger than 8 bytes");
}

template<typename T>
inline constexpr T as_little_endian(T val) {
if constexpr(__little_endian)
return val;
else
return swap_endianness(val);
}

template<typename T>
inline constexpr T as_big_endian(T val) {
if constexpr(!__little_endian)
return val;
else
return swap_endianness(val);
}

template<typename T>
inline constexpr T from_little_endian(T val) {
if constexpr(__little_endian)
return val;
else
return swap_endianness(val);
}

template<typename T>
inline constexpr T from_big_endian(T val) {
if constexpr(!__little_endian)
return val;
else
return swap_endianness(val);
}

template<typename T>
class LittleEndian {
public:
constexpr LittleEndian() = default;
constexpr LittleEndian(T val): m_val(as_little_endian(val)) {}
constexpr operator T() const { return from_little_endian(m_val); }
constexpr T val() const { return operator T(); }
private:
T m_val;
} __attribute__((packed));

template<typename T>
class BigEndian {
public:
constexpr BigEndian() = default;
constexpr BigEndian(T val): m_val(as_big_endian(val)) {}
constexpr operator T() const { return from_big_endian(m_val); }
constexpr T val() const { return operator T(); }
private:
T m_val;
} __attribute__((packed));

#endif
56 changes: 56 additions & 0 deletions kernel/api/ipv4.h
@@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright © 2016-2024 Byteduck */

#pragma once

#include "types.h"
#include "endian.h"

#ifdef __cplusplus
class __attribute__((packed)) IPv4Address {
public:
constexpr IPv4Address() = default;

constexpr IPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
m_data[0] = a;
m_data[1] = b;
m_data[2] = c;
m_data[3] = d;
}

inline constexpr uint8_t operator[](int idx) const {
return m_data[idx];
}

private:
uint8_t m_data[4];
};

#define IPV4_ARGS(addr) (addr)[0], (addr)[1], (addr)[2], (addr)[3]

struct __attribute__((packed)) IPv4Packet {
uint8_t version_ihl = 0;
uint8_t dscp_ecn = 0;
BigEndian<uint16_t> length;
BigEndian<uint16_t> identification;
BigEndian<uint16_t> flags_fragment_offset;
uint8_t ttl = 0;
uint8_t proto;
BigEndian<uint16_t> checksum;
IPv4Address source_addr;
IPv4Address dest_addr;
uint8_t payload[];
};

static_assert(sizeof(IPv4Packet) == 20);

enum IPv4Proto {
ICMP = 0x1,
TCP = 0x06,
UDP = 0x11
};

#endif

__DECL_BEGIN
__DECL_END
33 changes: 33 additions & 0 deletions kernel/api/net.h
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright © 2016-2024 Byteduck */

#pragma once

#include "ipv4.h"

#define IFNAMESIZ 16

#ifdef __cplusplus

class __attribute__((packed)) MACAddress {
public:
MACAddress() = default;
MACAddress(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f) {
m_data[0] = a;
m_data[1] = b;
m_data[2] = c;
m_data[3] = d;
m_data[4] = e;
m_data[5] = f;
}

uint8_t operator[](size_t index) {
return m_data[index];
}
private:
uint8_t m_data[6] = {0};
};

#define MAC_ARGS(addr) (addr)[0], (addr)[1], (addr)[2], (addr)[3], (addr)[4], (addr)[5]

#endif
4 changes: 4 additions & 0 deletions kernel/kmain.cpp
Expand Up @@ -48,6 +48,7 @@
#include <kernel/tests/KernelTest.h>
#include "bootlogo.h"
#include "Processor.h"
#include "net/NetworkAdapter.h"

uint8_t boot_disk;

Expand Down Expand Up @@ -225,6 +226,9 @@ void kmain_late(){
//Try initializing the sound card
auto dev = AC97Device::detect();

//Try initializing network
NetworkAdapter::setup();

//If we're running tests, do so
if(CommandLine::inst().get_option_value("kernel-tests") == "true") {
KernelTestRegistry::inst().run_tests();
Expand Down
36 changes: 36 additions & 0 deletions kernel/net/ARP.h
@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright © 2016-2024 Byteduck */

#pragma once

#include "../api/endian.h"
#include "../api/net.h"

enum ARPHWType {
Ethernet = 1
};

enum ARPOp {
Req = 1,
Resp = 2
};

enum EtherProto {
IPv4 = 0x0800,
ARP = 0x0806,
IPv6 = 0x86DD
};

struct ARPPacket {
BigEndian<uint16_t> hardware_type {ARPHWType::Ethernet};
BigEndian<uint16_t> protocol_type { EtherProto::IPv4 };
BigEndian<uint8_t> hwaddr_len { sizeof(MACAddress) };
BigEndian<uint8_t> protoaddr_len { sizeof(IPv4Address) };
BigEndian<uint16_t> operation;
MACAddress sender_hwaddr;
IPv4Address sender_protoaddr;
MACAddress target_hwaddr;
IPv4Address target_protoaddr;
} __attribute__((packed));

static_assert(sizeof(ARPPacket) == 28);

0 comments on commit 6537543

Please sign in to comment.