#include <cstdint> #include <memory> #include <utility> #include "drv/ATA.hpp" #include "drv/drivers.hpp" #include "drv/keyboard.hpp" #include "drv/mouse.hpp" #include "fs/mbr.hpp" #include "hwcomm/PCI.hpp" #include "hwcomm/interrupts.hpp" #include "net/arp.hpp" #include "net/etherframe.hpp" #include "net/icmp.hpp" #include "net/ipv4.hpp" #include "net/tcp.hpp" #include "net/udp.hpp" #include "utils/struct.hpp" #include "Console.hpp" #include "Demo.hpp" #include "GDT.hpp" #include "assert.hpp" #include "memorymanagement.hpp" #include "multiboot.hpp" #include "multitasking.hpp" #include "print.hpp" #include "syscalls.hpp" struct PrintfUDPHandler : public net::UDPHandler { virtual void handleUDPMessage(net::UDPSocket &/*socket*/, span<std::uint8_t> msg) override { char foo[] = " "; kprint("UDP: "); for (std::uint8_t c : msg) { foo[0] = c; kprint(foo); } } }; static bool startsWith(const char s[], const char prefix[]) { while (*s == *prefix && *prefix != '\0') { ++s; ++prefix; } return (*prefix == '\0'); } struct PrintfTCPHandler : public net::TCPHandler { virtual bool handleTCPMessage(net::TCPSocket &socket, span<std::uint8_t> msg) override { char foo[] = " "; kprint("TCP: "); for (std::uint8_t c : msg) { foo[0] = c; kprint(foo); } if (msg.size() > 9 && startsWith(reinterpret_cast<const char *>(msg.data()), "GET / HTTP")) { char response[] = "HTTP/1.1 200 OK\r\n" "Server: MyOS\r\n" "Content-Type: text/html\r\n" "\r\n" "<html>" "<head>" "<title>Test OS</title>" "</head>" "<body>" "<b>Test Operating System</b>" "<br/>" "</body>" "</html>" "\r\n"; socket.send(as_bytes(response).before(1)); socket.disconnect(); } return true; } }; struct NetworkStack { NetworkStack(drv::EthernetDriver *net, NetOrder<std::uint32_t> gatewayIP, NetOrder<std::uint32_t> subnetMask) : etherframe(*net), arp(etherframe), ipv4(etherframe, arp, gatewayIP, subnetMask), icmp(ipv4), udp(ipv4), tcp(ipv4) { arp.broadcastMACAddress(gatewayIP); icmp.requestEchoReply(gatewayIP); } net::EtherFrameProvider etherframe; net::ARP arp; net::IPProvider ipv4; net::ICMP icmp; net::UDPProvider udp; net::TCPProvider tcp; PrintfUDPHandler udpHandler; PrintfTCPHandler tcpHandler; }; extern "C" void stop(); static void heapDemo(MemoryManager &mm); static void ataDemo(); static std::unique_ptr<NetworkStack> netDemo(TaskManager &taskManager, drv::DriverManager &drvManager); static bool strEqual(const char s[], const char t[]); static Demo demo; extern "C" void * memset(void *s, int c, std::size_t n) { auto p = static_cast<std::uint8_t *>(s); while (n-- != 0U) { *p++ = c; } return s; } extern "C" void callConstructors() { using constructor = void (*)(); extern constructor startCtors, endCtors; for (constructor *ctor = &startCtors; ctor != &endCtors; ++ctor) { (*ctor)(); } } extern "C" void kernelEntry(multiboot_info *multibootInfo, unsigned int /*multibootMagic*/) { kprint("Hello, OSless World!\n"); std::uint32_t memupper = multibootInfo->mem_upper; extern void *kernelEnd; auto top = reinterpret_cast<std::uint8_t *>(memupper*1024 + 1*1024*1024); auto bottom = reinterpret_cast<std::uint8_t *>(&kernelEnd); MemoryManager memoryManager(bottom, top - bottom); kprint("heap start: 0x", &kernelEnd, "\n"); heapDemo(memoryManager); GlobalDescriptorTable gdt; hwcomm::InterruptManager interrupts(gdt); SyscallHandler syscalls(0x80); kprint("Initializing Hardware, Stage 1\n"); drv::DriverManager drvManager; drv::KeyboardDriver keyboard(demo); drvManager.addDriver(keyboard); drv::MouseDriver mouse(demo); drvManager.addDriver(mouse); hwcomm::PCIController pciController; pciController.selectDrivers(drvManager, interrupts); kprint("Initializing Hardware, Stage 2\n"); drvManager.activateAll(); ataDemo(); TaskManager taskManager(gdt); kprint("Initializing Hardware, Stage 3\n"); interrupts.activate(); std::unique_ptr<NetworkStack> networkStack = netDemo(taskManager, drvManager); taskManager.addTask(std::unique_ptr<Task>(new Task([]() { demo.run(); }))); stop(); } static void heapDemo(MemoryManager &mm) { void *allocated = mm.malloc(1024); kprint("allocated: 0x", allocated, "\n"); mm.free(allocated); allocated = mm.malloc(1024); kprint("allocated: 0x", allocated, "\n"); mm.free(allocated); } static void ataDemo() { kprint("\nS-ATA primary master: "); drv::ATA ata0m(true, 0x1f0); ata0m.identify(); kprint("\nS-ATA primary slave: "); drv::ATA ata0s(false, 0x1f0); ata0s.identify(); kprint("\nS-ATA secondary master: "); drv::ATA ata1m(true, 0x170); ata1m.identify(); kprint("\nS-ATA secondary slave: "); drv::ATA ata1s(false, 0x170); ata1s.identify(); kprint("\n"); fs::MBR::readPartitions(ata0m); // third: 0x1E8 // fourth: 0x168 } static std::unique_ptr<NetworkStack> netDemo(TaskManager &taskManager, drv::DriverManager &drvManager) { auto ourIP = toNetOrder<std::uint32_t>(0x0a00020f); // 10.0.2.15 auto gatewayIP = toNetOrder<std::uint32_t>(0x0a000202); // 10.0.2.2 auto subnetMask = toNetOrder<std::uint32_t>(0xffffff00); // 255.255.255.0 for (drv::Driver *drv : drvManager) { if (strEqual(drv->getName(), "rtl8139") || strEqual(drv->getName(), "amd_am79c973")) { auto net = static_cast<drv::EthernetDriver *>(drv); net->setIPAddress(ourIP); kprint("MAC: ", net->getMAC().BE, "\n"); auto networkStack = new NetworkStack(net, gatewayIP, subnetMask); taskManager.addTask(std::unique_ptr<Task>(new Task([=]() { net::UDPSocket &udpServer = networkStack->udp.listen(1234); networkStack->udp.bind(udpServer, &networkStack->udpHandler); net::UDPSocket &udpClient = networkStack->udp.connect(gatewayIP, 1235); networkStack->udp.bind(udpClient, &networkStack->udpHandler); const std::uint8_t data[] = { 'H', 'e', 'l', 'l', 'o', '!' }; udpClient.send(data); }))); taskManager.addTask(std::unique_ptr<Task>(new Task([=]() { net::TCPSocket &tcpServer = networkStack->tcp.listen(1234); networkStack->tcp.bind(tcpServer, &networkStack->tcpHandler); net::TCPSocket &tcpClient = networkStack->tcp.connect(gatewayIP, 1235); networkStack->tcp.bind(tcpClient, &networkStack->tcpHandler); const std::uint8_t data[] = { 'H', 'e', 'l', 'l', 'o', '!' }; tcpClient.send(data); }))); return std::unique_ptr<NetworkStack>(networkStack); } } return {}; } static bool strEqual(const char s[], const char t[]) { while (*s == *t && *s != '\0') { ++s; ++t; } return (*s == '\0'); } extern "C" void __cxa_pure_virtual() { kassert(false, "Pure virtual function called!\n"); }