#include #include #include #include #include #include #include #include #include #include #include #include #define PORT 7860 #define MAX_HISTORY 5 * 1024 * 1024 std::vector output_history; int master_read_fd = -1; int master_write_fd = -1; const char* HTML_PAGE = R"( Alpine RISC-V
--- CLICK HERE TO ENABLE TYPING ---
#
)"; bool file_exists(const char* name) { struct stat buffer; return (stat(name, &buffer) == 0); } void start_vm() { if (!file_exists("vmlinuz") || !file_exists("initramfs")) { std::string err = "CRITICAL ERROR: Boot files missing. Check Dockerfile.\n"; output_history.insert(output_history.end(), err.begin(), err.end()); return; } int pipe_in[2], pipe_out[2]; if (pipe(pipe_in) < 0 || pipe(pipe_out) < 0) return; if (fork() == 0) { // CHILD dup2(pipe_in[0], STDIN_FILENO); dup2(pipe_out[1], STDOUT_FILENO); dup2(pipe_out[1], STDERR_FILENO); close(pipe_in[1]); close(pipe_out[0]); const char* bios = file_exists("bios.elf") ? "bios.elf" : "default"; // --- UPDATED BOOT LOGIC --- execlp("qemu-system-riscv64", "qemu-system-riscv64", "-nographic", "-machine", "virt", "-m", "512M", "-smp", "2", "-bios", bios, "-kernel", "vmlinuz", "-initrd", "initramfs", // NEW DRIVE CONFIG FOR ALPINE V3.23 "-device", "virtio-scsi-device,id=scsi0", "-drive", "file=alpine.iso,format=raw,if=none,id=drive0", "-device", "scsi-cd,bus=scsi0.0,drive=drive0", "-serial", "stdio", "-monitor", "none", // Boot from CDROM (sr0) "-append", "console=ttyS0 root=/dev/sr0 modules=sd-mod,usb-storage,sr_mod quiet", NULL ); exit(1); } // PARENT close(pipe_in[0]); close(pipe_out[1]); master_write_fd = pipe_in[1]; master_read_fd = pipe_out[0]; fcntl(master_read_fd, F_SETFL, O_NONBLOCK); std::string msg = "--- SYSTEM ONLINE. LOADING CD-ROM... ---\n"; output_history.insert(output_history.end(), msg.begin(), msg.end()); } void send_http(int client, std::string content, std::string type) { std::string response = "HTTP/1.1 200 OK\r\n" "Content-Type: " + type + "\r\n" "Content-Length: " + std::to_string(content.length()) + "\r\n" "Connection: close\r\n" "\r\n" + content; send(client, response.c_str(), response.length(), 0); } int main() { signal(SIGPIPE, SIG_IGN); int server = socket(AF_INET, SOCK_STREAM, 0); int opt=1; setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in addr; addr.sin_family=AF_INET; addr.sin_addr.s_addr=INADDR_ANY; addr.sin_port=htons(PORT); bind(server, (struct sockaddr*)&addr, sizeof(addr)); listen(server, 10); std::cout << "SERVER LISTENING ON 7860" << std::endl; start_vm(); struct pollfd p[2]; p[0].fd = server; p[0].events = POLLIN; p[1].fd = master_read_fd; p[1].events = POLLIN; while(true) { poll(p, 2, 50); if(p[1].revents & POLLIN) { char buf[4096]; int n = read(master_read_fd, buf, sizeof(buf)); if(n > 0) { std::cout.write(buf, n); output_history.insert(output_history.end(), buf, buf+n); if(output_history.size() > MAX_HISTORY) output_history.erase(output_history.begin(), output_history.begin() + 4096); } } if(p[0].revents & POLLIN) { int client = accept(server, 0, 0); if(client >= 0) { char req[2048]={0}; read(client, req, 2048); std::string s(req); if(s.find("GET / ") != std::string::npos) { send_http(client, HTML_PAGE, "text/html"); } else if(s.find("GET /poll") != std::string::npos) { size_t pos = s.find("offset="); int off = (pos!=std::string::npos) ? std::stoi(s.substr(pos+7)) : 0; std::string data = ""; if(off < output_history.size()) data.assign(output_history.begin()+off, output_history.end()); send_http(client, data, "text/plain"); } else if(s.find("POST /input") != std::string::npos) { size_t pos = s.find("\r\n\r\n"); if(pos != std::string::npos) { std::string v = s.substr(pos+4); if(master_write_fd != -1) write(master_write_fd, v.c_str(), v.length()); } send_http(client, "ok", "text/plain"); } else { std::string err = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"; send(client, err.c_str(), err.length(), 0); } close(client); } } } }