diff --git a/Makefile b/Makefile index 55c5b06..9c60bc1 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ run: bin - qemu-system-i386 -drive format=raw,file=target/boot.bin -monitor stdio + qemu-system-i386 -vga std -nodefaults -drive format=raw,file=target/boot.bin -monitor stdio -device e1000,netdev=u1,mac=aa:bb:cc:dd:ee:ff -object filter-dump,id=f1,netdev=u1,file=/tmp/dump.pcap -netdev tap,id=u1,ifname=tap0,script=no,downscript=no run_kernelonly: compile_kernel - qemu-system-i386 -kernel target/kernel/kernel.bin -monitor stdio + qemu-system-i386 -kernel target/kernel/kernel.bin -monitor stdio -vga std -nodefaults -device e1000,netdev=u1,mac=aa:bb:cc:dd:ee:ff -object filter-dump,id=f1,netdev=u1,file=/tmp/dump.dat -netdev tap,id=u1,ifname=tap0,script=no,downscript=no debug_kernel: compile_kernel qemu-system-i386 -s -S -kernel target/kernel/kernel.bin diff --git a/README.md b/README.md index 06b93cc..b5f4dc9 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ If you run `make bin`, it will generate `target/boot.bin`, this is a binary file In case there are errors in the bootloader you can use `make compile_kernel` to only compile the kernel. To run TABS in the qemu simulator run `make run`. +To test the operating system in QEMU, first set up a tap interface with the `create_tap.sh` script, +then run `make run` or `make run_kernelonly`. ## Bootloader @@ -45,5 +47,8 @@ The kernel is based on [the bare bones kernel from the OSDev wiki](https://wiki. - [ ] Running executables from filesystem - [ ] Better memory management - [ ] Better shell +- [X] A driver for E1000-type network cards + - [X] sending packets + - [X] receiving packets As a test, I've implemented day 1 of [advent of code](https://adventofcode.com/) on the [AoC branch](https://github.com/Robbe7730/RoBoot/tree/AoC). diff --git a/create_tap.sh b/create_tap.sh new file mode 100755 index 0000000..4935575 --- /dev/null +++ b/create_tap.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +sudo ip tuntap add dev tap0 mode tap +sudo ip link set up dev tap0 +sudo chown $USER tap0 diff --git a/docs/8254x_GBe_SDM.pdf b/docs/8254x_GBe_SDM.pdf new file mode 100644 index 0000000..5f118a7 Binary files /dev/null and b/docs/8254x_GBe_SDM.pdf differ diff --git a/kernel/drivers/networking/e1000.c b/kernel/drivers/networking/e1000.c new file mode 100644 index 0000000..8e9ec09 --- /dev/null +++ b/kernel/drivers/networking/e1000.c @@ -0,0 +1,334 @@ +#ifndef DRIVERS_NETWORKING_E1000_C +#define DRIVERS_NETWORKING_E1000_C + +#include "../../inline_asm.c" +#include "../pci/pci.c" + +#define E1000_NUM_RX_DESC 32 +#define E1000_NUM_TX_DESC 8 + +static uint32_t e1000_device_pci = 0x00000000; +static uintptr_t mem_base = 0; +static int has_eeprom = 0; +static uint8_t e1000_mac[6]; + +// Aligned alloc +void* valloc(unsigned int size, int i) { + uint32_t addr = (uint32_t) alloc(size + (1 << i)); + addr = (((addr - 1) >> i) + 1 ) << i; + return (void*) addr; +} + +struct 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 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)); + +static uint8_t * rx_virt[E1000_NUM_RX_DESC]; +static uint8_t * tx_virt[E1000_NUM_TX_DESC]; +static struct rx_desc * rx; +static struct tx_desc * tx; +static uintptr_t rx_phys; +static uintptr_t tx_phys; + +#define E1000_REG_CTRL 0x0000 +#define E1000_REG_STATUS 0x0008 +#define E1000_REG_EEPROM 0x0014 +#define E1000_REG_CTRL_EXT 0x0018 + +#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_TCTRL 0x0400 +#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_RXADDR 0x5400 + +#define RCTL_EN (1 << 1) /* Receiver Enable */ +#define RCTL_SBP (1 << 2) /* Store Bad Packets */ +#define RCTL_UPE (1 << 3) /* Unicast Promiscuous Enabled */ +#define RCTL_MPE (1 << 4) /* Multicast Promiscuous Enabled */ +#define RCTL_LPE (1 << 5) /* Long Packet Reception Enable */ +#define RCTL_LBM_NONE (0 << 6) /* No Loopback */ +#define RCTL_LBM_PHY (3 << 6) /* PHY or external SerDesc loopback */ +#define RTCL_RDMTS_HALF (0 << 8) /* Free Buffer Threshold is 1/2 of RDLEN */ +#define RTCL_RDMTS_QUARTER (1 << 8) /* Free Buffer Threshold is 1/4 of RDLEN */ +#define RTCL_RDMTS_EIGHTH (2 << 8) /* Free Buffer Threshold is 1/8 of RDLEN */ +#define RCTL_MO_36 (0 << 12) /* Multicast Offset - bits 47:36 */ +#define RCTL_MO_35 (1 << 12) /* Multicast Offset - bits 46:35 */ +#define RCTL_MO_34 (2 << 12) /* Multicast Offset - bits 45:34 */ +#define RCTL_MO_32 (3 << 12) /* Multicast Offset - bits 43:32 */ +#define RCTL_BAM (1 << 15) /* Broadcast Accept Mode */ +#define RCTL_VFE (1 << 18) /* VLAN Filter Enable */ +#define RCTL_CFIEN (1 << 19) /* Canonical Form Indicator Enable */ +#define RCTL_CFI (1 << 20) /* Canonical Form Indicator Bit Value */ +#define RCTL_DPF (1 << 22) /* Discard Pause Frames */ +#define RCTL_PMCF (1 << 23) /* Pass MAC Control Frames */ +#define RCTL_SECRC (1 << 26) /* Strip Ethernet CRC */ + +#define RCTL_BSIZE_256 (3 << 16) +#define RCTL_BSIZE_512 (2 << 16) +#define RCTL_BSIZE_1024 (1 << 16) +#define RCTL_BSIZE_2048 (0 << 16) +#define RCTL_BSIZE_4096 ((3 << 16) | (1 << 25)) +#define RCTL_BSIZE_8192 ((2 << 16) | (1 << 25)) +#define RCTL_BSIZE_16384 ((1 << 16) | (1 << 25)) + +#define TCTL_EN (1 << 1) /* Transmit Enable */ +#define TCTL_PSP (1 << 3) /* Pad Short Packets */ +#define TCTL_CT_SHIFT 4 /* Collision Threshold */ +#define TCTL_COLD_SHIFT 12 /* Collision Distance */ +#define TCTL_SWXOFF (1 << 22) /* Software XOFF Transmission */ +#define TCTL_RTLC (1 << 24) /* Re-transmit on Late Collision */ + +#define CMD_EOP (1 << 0) /* End of Packet */ +#define CMD_IFCS (1 << 1) /* Insert FCS */ +#define CMD_IC (1 << 2) /* Insert Checksum */ +#define CMD_RS (1 << 3) /* Report Status */ +#define CMD_RPS (1 << 4) /* Report Packet Sent */ +#define CMD_VLE (1 << 6) /* VLAN Packet Enable */ +#define CMD_IDE (1 << 7) /* Interrupt Delay Enable */ + +#define RX_STATUS_DD (1 << 0) /* Descriptor done */ + +#define STATUS_LINK_UP (1 << 1) /* Link Up */ + +static void write_command(uint16_t addr, uint32_t val) { + (*((volatile uint32_t*)(mem_base + addr))) = val; +} + +static uint32_t read_command(uint16_t addr) { + return *((volatile uint32_t*)(mem_base + addr)); +} + +static int eeprom_detect(void) { + + write_command(E1000_REG_EEPROM, 1); + + for (int i = 0; i < 100000 && !has_eeprom; ++i) { + uint32_t val = read_command(E1000_REG_EEPROM); + if (val & 0x10) has_eeprom = 1; + } + + return 0; +} + +static uint16_t eeprom_read(uint8_t addr) { + uint32_t temp = 0; + write_command(E1000_REG_EEPROM, 1 | ((uint32_t)(addr) << 8)); + while (!((temp = read_command(E1000_REG_EEPROM)) & (1 << 4))); + return (uint16_t)((temp >> 16) & 0xFFFF); +} + + +static void find_e1000(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + if ((vendorid == 0x8086) && (deviceid == 0x100e || deviceid == 0x1004 || deviceid == 0x100f || deviceid == 0x10ea)) { + *((uint32_t *)extra) = device; + } +} + +static void write_mac(void) { + + uint32_t low; + uint32_t high; + + memcpy(&low, &e1000_mac[0], 4); + memcpy(&high,&e1000_mac[4], 2); + memset((uint8_t *)&high + 2, 0, 2); + high |= 0x80000000; + + write_command(E1000_REG_RXADDR + 0, low); + write_command(E1000_REG_RXADDR + 4, high); +} + +static void read_mac(void) { + if (has_eeprom) { + for (int i = 0; i < 3; i++) { + uint32_t part = eeprom_read(i); + e1000_mac[2*i] = part & 0xFF; + e1000_mac[2*i + 1] = (part >> 8) & 0xFF; + } + } else { + uint8_t* mac_addr = (uint8_t*)(mem_base + E1000_REG_RXADDR); + for (int i = 0; i < 6; ++i) { + e1000_mac[i] = mac_addr[i]; + } + } +} + + +// Receives a packet, returning the size of the packet or 0 if no packet was received +// User is responsible for freeing the buffer that we will allocate +static size_t receive_packet(uint8_t** payload) { + uint32_t rx_index = read_command(E1000_REG_RXDESCTAIL); + if (rx_index == read_command(E1000_REG_RXDESCHEAD)) { + // head == tail, so the queue is empty + return 0; + } + + rx_index = (rx_index + 1) % E1000_NUM_RX_DESC; + uint32_t packetstatus = rx[rx_index].status; + if (!(packetstatus & (RX_STATUS_DD))) { + // The network card isn't done receiving this packet + return 0; + } + // Normally, we would have to check if this is the end of the packet, but + // since we receive in chunks of 2048, an ethernet frame always fits in one chunk + uint8_t* packet_address = (uint8_t*) rx_virt[rx_index]; + size_t size = (size_t) rx[rx_index].length; + void* user_packet = alloc(size); + memcpy(user_packet, packet_address, size); + + // Set the status to done + rx[rx_index].status = 0; + + // Update the network card's tail + write_command(E1000_REG_RXDESCTAIL, rx_index); + *payload = user_packet; + return size; +} + +static void send_packet(uint8_t* payload, size_t payload_size) { + uint32_t tx_index = read_command(E1000_REG_TXDESCTAIL); + + memcpy(tx_virt[tx_index], payload, payload_size); + tx[tx_index].length = payload_size; + // End Of Packet, let hardware generate checksum + tx[tx_index].cmd = CMD_EOP | CMD_IFCS; + tx[tx_index].status = 0; + + tx_index = (tx_index + 1) % E1000_NUM_TX_DESC; + write_command(E1000_REG_TXDESCTAIL, tx_index); +} + +static void init_rx(void) { + // Set physical address of receive FIFO + write_command(E1000_REG_RXDESCLO, rx_phys); + write_command(E1000_REG_RXDESCHI, 0); + + write_command(E1000_REG_RXDESCLEN, E1000_NUM_RX_DESC * sizeof(struct rx_desc)); + + // Initialize head and tail of receive FIFO + write_command(E1000_REG_RXDESCHEAD, 0); + write_command(E1000_REG_RXDESCTAIL, E1000_NUM_RX_DESC - 1); + + // Enable receiving, receive packets of up to 2048, allow receiving broadcast packets + write_command(E1000_REG_RCTRL, + RCTL_EN | RCTL_BSIZE_2048 | RCTL_BAM | + (read_command(E1000_REG_RCTRL))); + +} + +static void init_tx(void) { + + // Set physical address of transmit FIFO + write_command(E1000_REG_TXDESCLO, tx_phys); + write_command(E1000_REG_TXDESCHI, 0); + + write_command(E1000_REG_TXDESCLEN, E1000_NUM_TX_DESC * sizeof(struct tx_desc)); + + // Initialize head and tail of transmit FIFO + write_command(E1000_REG_TXDESCHEAD, 0); + write_command(E1000_REG_TXDESCTAIL, 0); + + // Enable transmitting, Pad Short Packets + write_command(E1000_REG_TCTRL, + TCTL_EN | + TCTL_PSP | + read_command(E1000_REG_TCTRL)); +} + +static int e1000_init_main(void) { + pci_scan(&find_e1000, -1, &e1000_device_pci); + + if (!e1000_device_pci) { + terminal_writestring("No e1000 device found."); + return 1; + } + + mem_base = pci_read_field(e1000_device_pci, PCI_BAR0, 4) & 0xFFFFFFF0; + + // TODO mark page as cache-disabled + + // TODO shrink network buffer size to RCTL_BSIZE_2048 + // TODO align to paragraph instead of to page + + // We don't do paging, so the virtual address = the physical address + rx = valloc(sizeof(struct rx_desc) * E1000_NUM_RX_DESC + 16, 12); + rx_phys = (uintptr_t) rx; + for (int i = 0; i < E1000_NUM_RX_DESC; i++) { + // Allocate a 2048-sized piece of memory, aligned (so the last 4 bits are 0) + rx_virt[i] = valloc(2048, 4); + rx[i].addr = (uintptr_t) rx_virt[i]; + rx[i].status = 0; + } + + tx = valloc(sizeof(struct tx_desc) * E1000_NUM_TX_DESC + 16, 12); + tx_phys = (uintptr_t) tx; + for (int i = 0; i < E1000_NUM_TX_DESC; i++) { + tx_virt[i] = valloc(2048, 4); + tx[i].addr = (uintptr_t) tx_virt[i]; + tx[i].status = 0; + tx[i].cmd = (1 << 0); + } + + // Enable PCI bus mastering + uint16_t command_reg = pci_read_field(e1000_device_pci, PCI_COMMAND, 2); + command_reg |= (1 << 2); + command_reg |= (1 << 0); + pci_write_field(e1000_device_pci, PCI_COMMAND, 2, command_reg); + + eeprom_detect(); + + terminal_writestring("EEPROM="); + terminal_writeint(has_eeprom, 10); + + read_mac(); + terminal_writestring(" MAC = "); + terminal_writeint(e1000_mac[0], 16); + terminal_writeint(e1000_mac[1], 16); + terminal_writeint(e1000_mac[2], 16); + terminal_writeint(e1000_mac[3], 16); + terminal_writeint(e1000_mac[4], 16); + terminal_writeint(e1000_mac[5], 16); + terminal_writestring("\n"); + write_mac(); + + init_rx(); + init_tx(); + + int networkstatus = read_command(E1000_REG_STATUS); + + terminal_writestring("Network is "); + if (networkstatus) { + terminal_writestring("up!\n"); + } else { + terminal_writestring("down :/ \n"); + } + + return 0; +} + +#endif // DRIVERS_NETWORKING_E1000_C diff --git a/kernel/drivers/networking/network.c b/kernel/drivers/networking/network.c new file mode 100644 index 0000000..4a0fe26 --- /dev/null +++ b/kernel/drivers/networking/network.c @@ -0,0 +1,47 @@ +#ifndef DRIVERS_NETWORKING_NETWORK_C +#define DRIVERS_NETWORKING_NETWORK_C + +#include "e1000.c" +#include "../../memory.c" + +uint8_t* create_packet(uint8_t dest[6], uint8_t src[6], uint8_t type[2], uint8_t* content, int contentlength) { + uint8_t* returnbuffer = alloc(6 + 6 + 2 + contentlength); + memcpy(returnbuffer, dest, 6); + memcpy(returnbuffer + 6, src, 6); + memcpy(returnbuffer + 6 + 6, type, 2); + memcpy(returnbuffer + 6 + 6 + 2, content, contentlength); + return returnbuffer; +} + +void network_init() { + + uint8_t dest[6] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + uint8_t src[6] = {0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f}; + uint8_t type[2] = {0x69, 0x69}; + + e1000_init_main(); + + for (int i = 0; i < 3; i++) { + uint8_t* packet = create_packet(dest, src, type, (uint8_t*) "Zulu Echo Uniform Sierra Whiskey Papa India", 43); + + send_packet(packet, 6 + 6 + 2 + 43); + // TODO free(packet) + } + + uint8_t* received_packet; + while (1) { + size_t s = receive_packet(&received_packet); + if (s) { + terminal_writeint(s, 10); + terminal_writestring(" received packet \n"); + for (size_t i = 0; i < s; i++) { + terminal_putchar(received_packet[i]); + } + // TODO free(*received_packet) + break; + } + } + +} + +#endif // DRIVERS_NETWORKING_NETWORK_C diff --git a/kernel/drivers/pci/pci.c b/kernel/drivers/pci/pci.c new file mode 100644 index 0000000..7735580 --- /dev/null +++ b/kernel/drivers/pci/pci.c @@ -0,0 +1,196 @@ +#ifndef DRIVERS_PCI_PCI_C +#define DRIVERS_PCI_PCI_C + +typedef void (*pci_func_t)(uint32_t device, uint16_t vendor_id, uint16_t device_id, void * extra); +void pci_scan_bus(pci_func_t f, int type, int bus, void * extra); + +#define PCI_VENDOR_ID 0x00 // 2 +#define PCI_DEVICE_ID 0x02 // 2 +#define PCI_COMMAND 0x04 // 2 +#define PCI_STATUS 0x06 // 2 +#define PCI_REVISION_ID 0x08 // 1 + +#define PCI_PROG_IF 0x09 // 1 +#define PCI_SUBCLASS 0x0a // 1 +#define PCI_CLASS 0x0b // 1 +#define PCI_CACHE_LINE_SIZE 0x0c // 1 +#define PCI_LATENCY_TIMER 0x0d // 1 +#define PCI_HEADER_TYPE 0x0e // 1 +#define PCI_BIST 0x0f // 1 +#define PCI_BAR0 0x10 // 4 +#define PCI_BAR1 0x14 // 4 +#define PCI_BAR2 0x18 // 4 +#define PCI_BAR3 0x1C // 4 +#define PCI_BAR4 0x20 // 4 +#define PCI_BAR5 0x24 // 4 + +#define PCI_INTERRUPT_LINE 0x3C // 1 + +#define PCI_SECONDARY_BUS 0x19 // 1 + +#define PCI_HEADER_TYPE_DEVICE 0 +#define PCI_HEADER_TYPE_BRIDGE 1 +#define PCI_HEADER_TYPE_CARDBUS 2 + +#define PCI_TYPE_BRIDGE 0x0604 +#define PCI_TYPE_SATA 0x0106 + +#define PCI_ADDRESS_PORT 0xCF8 +#define PCI_VALUE_PORT 0xCFC + +#define PCI_NONE 0xFFFF + +typedef void (*pci_func_t)(uint32_t device, uint16_t vendor_id, uint16_t device_id, void * extra); + +static inline int pci_extract_bus(uint32_t device) { + return (uint8_t)((device >> 16)); +} +static inline int pci_extract_slot(uint32_t device) { + return (uint8_t)((device >> 8)); +} +static inline int pci_extract_func(uint32_t device) { + return (uint8_t)(device); +} + +static inline uint32_t pci_get_addr(uint32_t device, int field) { + return 0x80000000 | (pci_extract_bus(device) << 16) | (pci_extract_slot(device) << 11) | (pci_extract_func(device) << 8) | ((field) & 0xFC); +} + +static inline uint32_t pci_box_device(int bus, int slot, int func) { + return (uint32_t)((bus << 16) | (slot << 8) | func); +} + + +void pci_write_field(uint32_t device, int field, int size, uint32_t value) { + outl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); + outl(PCI_VALUE_PORT, value); +} + +uint32_t pci_read_field(uint32_t device, int field, int size) { + outl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); + + if (size == 4) { + uint32_t t = inl(PCI_VALUE_PORT); + return t; + } else if (size == 2) { + uint16_t t = inw(PCI_VALUE_PORT + (field & 2)); + return t; + } else if (size == 1) { + uint8_t t = inb(PCI_VALUE_PORT + (field & 3)); + return t; + } + return 0xFFFF; +} + +uint16_t pci_find_type(uint32_t dev) { + return (pci_read_field(dev, PCI_CLASS, 1) << 8) | pci_read_field(dev, PCI_SUBCLASS, 1); +} + + +void pci_scan_hit(pci_func_t f, uint32_t dev, void * extra) { + int dev_vend = (int)pci_read_field(dev, PCI_VENDOR_ID, 2); + int dev_dvid = (int)pci_read_field(dev, PCI_DEVICE_ID, 2); + + f(dev, dev_vend, dev_dvid, extra); +} + +void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, void * extra) { + uint32_t dev = pci_box_device(bus, slot, func); + if (type == -1 || type == pci_find_type(dev)) { + pci_scan_hit(f, dev, extra); + } + if (pci_find_type(dev) == PCI_TYPE_BRIDGE) { + pci_scan_bus(f, type, pci_read_field(dev, PCI_SECONDARY_BUS, 1), extra); + } +} + +void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void * extra) { + uint32_t dev = pci_box_device(bus, slot, 0); + if (pci_read_field(dev, PCI_VENDOR_ID, 2) == PCI_NONE) { + return; + } + pci_scan_func(f, type, bus, slot, 0, extra); + if (!pci_read_field(dev, PCI_HEADER_TYPE, 1)) { + return; + } + for (int func = 1; func < 8; func++) { + uint32_t dev = pci_box_device(bus, slot, func); + if (pci_read_field(dev, PCI_VENDOR_ID, 2) != PCI_NONE) { + pci_scan_func(f, type, bus, slot, func, extra); + } + } +} + +void pci_scan_bus(pci_func_t f, int type, int bus, void * extra) { + for (int slot = 0; slot < 32; ++slot) { + pci_scan_slot(f, type, bus, slot, extra); + } +} + +void pci_scan(pci_func_t f, int type, void * extra) { + + if ((pci_read_field(0, PCI_HEADER_TYPE, 1) & 0x80) == 0) { + pci_scan_bus(f,type,0,extra); + return; + } + + for (int func = 0; func < 8; ++func) { + uint32_t dev = pci_box_device(0, 0, func); + if (pci_read_field(dev, PCI_VENDOR_ID, 2) != PCI_NONE) { + pci_scan_bus(f, type, func, extra); + } else { + break; + } + } +} + +static void find_isa_bridge(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) { + *((uint32_t *)extra) = device; + } +} +static uint32_t pci_isa = 0; +static uint8_t pci_remaps[4] = {0}; +void pci_remap(void) { + pci_scan(&find_isa_bridge, -1, &pci_isa); + if (pci_isa) { + for (int i = 0; i < 4; ++i) { + pci_remaps[i] = pci_read_field(pci_isa, 0x60+i, 1); + if (pci_remaps[i] == 0x80) { + pci_remaps[i] = 10 + (i%1); + } + } + uint32_t out = 0; + memcpy(&out, &pci_remaps, 4); + pci_write_field(pci_isa, 0x60, 4, out); + } +} + +int pci_get_interrupt(uint32_t device) { + + if (pci_isa) { + uint32_t irq_pin = pci_read_field(device, 0x3D, 1); + if (irq_pin == 0) { + return pci_read_field(device, PCI_INTERRUPT_LINE, 1); + } + int pirq = (irq_pin + pci_extract_slot(device) - 2) % 4; + int int_line = pci_read_field(device, PCI_INTERRUPT_LINE, 1); + if (pci_remaps[pirq] >= 0x80) { + if (int_line == 0xFF) { + int_line = 10; + pci_write_field(device, PCI_INTERRUPT_LINE, 1, int_line); + } + pci_remaps[pirq] = int_line; + uint32_t out = 0; + memcpy(&out, &pci_remaps, 4); + pci_write_field(pci_isa, 0x60, 4, out); + return int_line; + } + pci_write_field(device, PCI_INTERRUPT_LINE, 1, pci_remaps[pirq]); + return pci_remaps[pirq]; + } else { + return pci_read_field(device, PCI_INTERRUPT_LINE, 1); + } +} + +#endif // DRIVERS_PCI_PCI_C diff --git a/kernel/inline_asm.c b/kernel/inline_asm.c index 2757685..ea6c9f3 100644 --- a/kernel/inline_asm.c +++ b/kernel/inline_asm.c @@ -31,13 +31,33 @@ static inline uint8_t inb(uint16_t port) { return ret; } +static uint16_t inw(uint16_t port) { + uint16_t ret; + asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port)); + return ret; +} + +static void outw(uint16_t port, uint16_t val) { + asm volatile ("outw %0, %1" : : "a" (val), "dN" (port) ); +} + +static uint32_t inl(uint16_t port) { + uint32_t ret; + asm volatile ("inl %%dx, %%eax" : "=a" (ret) : "dN" (port)); + return ret; +} + +static void outl(uint16_t port, uint32_t val) { + asm volatile ("outl %%eax, %%dx" : : "dN" (port), "a" (val)); +} + static inline void lidt(void* base, uint16_t size) { // This function works in 32 and 64bit mode struct { uint16_t length; void* base; } __attribute__((packed)) IDTR = { size, base }; - + asm ( "lidt %0" : : "m"(IDTR) ); // let the compiler choose an addressing mode } @@ -61,4 +81,20 @@ static inline void sgdt(gdt_desc* ret) { asm volatile ("sgdt %0" : : "m"(*ret) : "memory"); } -#endif //INLINE ASM_C \ No newline at end of file +static void * memcpy(void * restrict dest, const void * restrict src, long n) { + asm volatile("cld; rep movsb" + : "=c"((int){0}) + : "D"(dest), "S"(src), "c"(n) + : "flags", "memory"); + return dest; +} + +static void * memset(void * dest, int c, long n) { + asm volatile("cld; rep stosb" + : "=c"((int){0}) + : "D"(dest), "a"(c), "c"(n) + : "flags", "memory"); + return dest; +} + +#endif //INLINE ASM_C diff --git a/kernel/kernel.c b/kernel/kernel.c index 7fa4427..426018c 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -2,7 +2,7 @@ #if defined(__linux__) #error "You are not using a cross-compiler, you will most certainly run into trouble" #endif - + /* This tutorial will only work for the 32-bit ix86 targets. */ #if !defined(__i386__) #error "This kernel needs to be compiled with a ix86-elf compiler" @@ -16,6 +16,7 @@ #include "memory.c" #include "interrupts.c" #include "shell.c" +#include "network.c" static inline bool are_interrupts_enabled() { unsigned long flags; @@ -25,7 +26,7 @@ static inline bool are_interrupts_enabled() { return flags & (1 << 9); } -void kernel_main(void) +void kernel_main(void) { /* Initialize terminal interface */ terminal_initialize(); @@ -35,11 +36,11 @@ void kernel_main(void) terminal_putchar('l'); terminal_putchar('l'); terminal_putchar('o'); - - terminal_setcolor(vga_entry_color(VGA_COLOR_GREEN, VGA_COLOR_BLACK)); - terminal_writestring(" kernel"); - terminal_setcolor(vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK)); - terminal_writestring(" World!\n"); + + terminal_setcolor(vga_entry_color(VGA_COLOR_GREEN, VGA_COLOR_BLACK)); + terminal_writestring(" kernel"); + terminal_setcolor(vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK)); + terminal_writestring(" World!\n"); terminal_writestring("Newlines!\n"); char* memory_str = alloc(sizeof(char) * 7); @@ -60,8 +61,9 @@ void kernel_main(void) terminal_writestring((are_interrupts_enabled())? "Interrupts!\n": "No interrupts :(\n"); interrupt_init(); + network_init(); for(;;) { shell_step(); } -} \ No newline at end of file +} diff --git a/kernel/network.c b/kernel/network.c new file mode 100644 index 0000000..cbab03a --- /dev/null +++ b/kernel/network.c @@ -0,0 +1 @@ +#include "drivers/networking/network.c" diff --git a/kernel/util/ringbuffer.c b/kernel/util/ringbuffer.c index 27ff0f7..e1a7936 100644 --- a/kernel/util/ringbuffer.c +++ b/kernel/util/ringbuffer.c @@ -2,7 +2,7 @@ #define RINGBUFFER_C #include -#include "../alloc.c" +#include "../memory.c" /* * Data layout: ↓head