Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
804de7cec2 | ||
|
|
8b81805b0e | ||
|
|
fe28bd8a95 | ||
|
|
9caf62273c | ||
|
|
dc09bac586 | ||
|
|
ce9f4f6db2 |
338
app/irc/irc.cpp
Normal file
338
app/irc/irc.cpp
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/trace.h>
|
||||
#include <app.h>
|
||||
#include <lib/minip.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/mutex.h>
|
||||
|
||||
#include "lktl.h"
|
||||
|
||||
#define LOCAL_TRACE 1
|
||||
|
||||
//#define IRC_SERVER IPV4(176,58,122,119) // irc.libera.chat
|
||||
#define IRC_SERVER IPV4(88,99,244,30) // irc.sortix.org
|
||||
//#define IRC_SERVER IPV4(192,168,1,110) // localhost
|
||||
#define IRC_PORT 6667
|
||||
#define IRC_USER "geist"
|
||||
#define IRC_NICK "geist-lk"
|
||||
#define IRC_CHAN "#sortix"
|
||||
//#define IRC_CHAN "#osdev"
|
||||
|
||||
class irc_client {
|
||||
public:
|
||||
irc_client();
|
||||
~irc_client();
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
status_t connect();
|
||||
status_t handshake();
|
||||
status_t read_loop();
|
||||
status_t console_input_line(const char *line, bool &exit);
|
||||
|
||||
void set_server(uint32_t server) { server_ip_ = server; }
|
||||
void set_server_port(uint16_t port) { server_port_ = port; }
|
||||
|
||||
private:
|
||||
mutex_t lock_ = MUTEX_INITIAL_VALUE(lock_);
|
||||
tcp_socket_t *sock_ = nullptr;
|
||||
|
||||
uint32_t server_ip_ = 0;
|
||||
uint16_t server_port_ = 0;
|
||||
enum {
|
||||
INITIAL,
|
||||
CONNECTED,
|
||||
HANDSHOOK,
|
||||
} state_ = INITIAL;
|
||||
};
|
||||
|
||||
irc_client::irc_client() = default;
|
||||
irc_client::~irc_client() = default;
|
||||
|
||||
void irc_client::init() {
|
||||
}
|
||||
|
||||
void irc_client::shutdown() {
|
||||
lktl::auto_lock al(&lock_);
|
||||
|
||||
if (sock_) {
|
||||
if (state_ == HANDSHOOK) {
|
||||
// send quit
|
||||
tcp_write(sock_, "QUIT\r\n", strlen("QUIT\r\n"));
|
||||
// XXX flush socket
|
||||
thread_sleep(1000);
|
||||
}
|
||||
tcp_close(sock_);
|
||||
sock_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
status_t irc_client::connect() {
|
||||
lktl::auto_lock al(&lock_);
|
||||
|
||||
if (server_ip_ == 0 || server_port_ == 0) {
|
||||
return ERR_NOT_CONFIGURED;
|
||||
}
|
||||
|
||||
auto err = tcp_connect(&sock_, server_ip_, server_port_);
|
||||
if (err < 0) {
|
||||
printf("err %d connecting to server\n", err);
|
||||
return ERR_CHANNEL_CLOSED; // TODO: better one
|
||||
}
|
||||
|
||||
state_ = CONNECTED;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t irc_client::read_loop() {
|
||||
char line[1024];
|
||||
int pos = 0;
|
||||
for (;;) {
|
||||
char c;
|
||||
ssize_t r = tcp_read(sock_, &c, sizeof(c));
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
TRACEF("tcp_read returns 0?\n");
|
||||
return ERR_GENERIC;
|
||||
}
|
||||
|
||||
// TODO: make sure we dont overwrite the line
|
||||
|
||||
// append the char to our accumulated line
|
||||
if (c == '\r') {
|
||||
// consume \r
|
||||
continue;
|
||||
}
|
||||
|
||||
// store the char
|
||||
line[pos++] = c;
|
||||
|
||||
if (c != '\n') {
|
||||
// we're done, loop around
|
||||
continue;
|
||||
}
|
||||
|
||||
// we've completed a line, process it
|
||||
line[pos] = 0; // terminate the string
|
||||
pos = 0; // next time around we start over
|
||||
|
||||
lktl::auto_lock al(&lock_);
|
||||
|
||||
if (strncmp(line, "PING", strlen("PING"))== 0) {
|
||||
// handle a PONG
|
||||
tcp_write(sock_, "PONG\r\n", strlen("PONG\r\n"));
|
||||
printf("%s", line);
|
||||
printf("PING/PONG\n");
|
||||
} else {
|
||||
printf("%s", line);
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t irc_client::console_input_line(const char *line, bool &exit) {
|
||||
//printf("CONSOLE LINE '%s'\n", line);
|
||||
|
||||
if (strlen(line) == 0) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// see if it starts with /
|
||||
if (line[0] == '/') {
|
||||
if (line[1] == 0) {
|
||||
// malformed command
|
||||
return NO_ERROR;
|
||||
}
|
||||
// look for quit command
|
||||
if (strncmp(&line[1], "quit", strlen("quit")) == 0) {
|
||||
shutdown();
|
||||
exit = true;
|
||||
return NO_ERROR;
|
||||
} else {
|
||||
printf("bad command\n");
|
||||
return NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
lktl::auto_lock al(&lock_);
|
||||
|
||||
// send it as a privmsg
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "PRIVMSG #sortix :%s\r\n", line);
|
||||
status_t err = tcp_write(sock_, buf, strlen(buf));
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t irc_client::handshake() {
|
||||
lktl::auto_lock al(&lock_);
|
||||
|
||||
// send USER and NICK
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "USER %s host server :geist\r\n", IRC_USER);
|
||||
status_t err = tcp_write(sock_, buf, strlen(buf));
|
||||
if (err < 0) {
|
||||
printf("error %d writing to server\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "NICK %s\r\n", IRC_NICK);
|
||||
err = tcp_write(sock_, buf, strlen(buf));
|
||||
if (err < 0) {
|
||||
printf("error %d writing to server\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "JOIN %s\r\n", IRC_CHAN);
|
||||
err = tcp_write(sock_, buf, strlen(buf));
|
||||
if (err < 0) {
|
||||
printf("error %d writing to server\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
state_ = HANDSHOOK;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// console worker thread
|
||||
static int console_thread_worker(void *arg) {
|
||||
irc_client *irc = static_cast<irc_client *>(arg);
|
||||
|
||||
LTRACEF("top of console thread\n");
|
||||
|
||||
// read a line from the console, giving it to the irc client object at EOL
|
||||
status_t err;
|
||||
char line[256];
|
||||
int pos = 0;
|
||||
bool exit = false;
|
||||
while (!exit) {
|
||||
int c = getchar();
|
||||
if (c <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos == sizeof(line)) {
|
||||
printf("line too long, discarding\n");
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
//printf("char %c (%d)\n", c, c);
|
||||
switch (c) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
if (pos > 0) {
|
||||
putchar('\n');
|
||||
// end of a line with characters in it, feed it to the irc client
|
||||
line[pos++] = 0; // null terminate
|
||||
err = irc->console_input_line(line, exit);
|
||||
if (err < 0) {
|
||||
exit = true;
|
||||
}
|
||||
pos = 0;
|
||||
}
|
||||
break;
|
||||
case '\b': // backspace
|
||||
case 127: // DEL
|
||||
if (pos > 0) {
|
||||
pos--;
|
||||
fputs("\b \b", stdout); // wipe out a character
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
line[pos++] = (char)c;
|
||||
putchar(c);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LTRACEF("console thread exiting\n");
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
static void irc_app_entry(const struct app_descriptor *app, void *args) {
|
||||
LTRACE_ENTRY;
|
||||
printf("welcome to IRC!\n");
|
||||
|
||||
// create a local state object
|
||||
irc_client *irc = new irc_client();
|
||||
if (!irc) {
|
||||
return;
|
||||
}
|
||||
|
||||
status_t err;
|
||||
|
||||
irc->init();
|
||||
|
||||
// clean up and delete the object on the way out
|
||||
auto cleanup = [&irc]() {
|
||||
printf("cleaning up IRC\n");
|
||||
irc->shutdown();
|
||||
delete irc;
|
||||
};
|
||||
auto ac = lktl::make_auto_call(cleanup);
|
||||
|
||||
// configure the parameters
|
||||
irc->set_server(IRC_SERVER);
|
||||
irc->set_server_port(IRC_PORT);
|
||||
|
||||
err = irc->connect();
|
||||
if (err < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
err = irc->handshake();
|
||||
if (err < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// start two threads
|
||||
thread_t *console_thread;
|
||||
thread_t *server_thread;
|
||||
|
||||
console_thread = thread_create("irc console", console_thread_worker, irc, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
|
||||
thread_resume(console_thread);
|
||||
|
||||
auto server_thread_worker = [](void *arg) -> int {
|
||||
irc_client *_irc = static_cast<irc_client *>(arg);
|
||||
printf("top of server thread\n");
|
||||
|
||||
_irc->read_loop();
|
||||
|
||||
return 0;
|
||||
};
|
||||
server_thread = thread_create("irc socket", server_thread_worker, irc, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
|
||||
thread_resume(server_thread);
|
||||
|
||||
thread_join(server_thread, nullptr, INFINITE_TIME);
|
||||
thread_join(console_thread, nullptr, INFINITE_TIME);
|
||||
|
||||
LTRACE_EXIT;
|
||||
}
|
||||
|
||||
APP_START(irc)
|
||||
.init = nullptr,
|
||||
.entry = irc_app_entry,
|
||||
.flags = APP_FLAG_NO_AUTOSTART,
|
||||
.stack_size = 0,
|
||||
APP_END
|
||||
|
||||
92
app/irc/lktl.h
Normal file
92
app/irc/lktl.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
// Copyright 2016 The Fuchsia Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/mutex.h>
|
||||
|
||||
// Macro used to simplify the task of deleting all of the default copy
|
||||
// constructors and assignment operators.
|
||||
#define DISALLOW_COPY_ASSIGN_AND_MOVE(_class_name) \
|
||||
_class_name(const _class_name&) = delete; \
|
||||
_class_name(_class_name&&) = delete; \
|
||||
_class_name& operator=(const _class_name&) = delete; \
|
||||
_class_name& operator=(_class_name&&) = delete
|
||||
|
||||
// Macro used to simplify the task of deleting the non rvalue reference copy
|
||||
// constructors and assignment operators. (IOW - forcing move semantics)
|
||||
#define DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(_class_name) \
|
||||
_class_name(const _class_name&) = delete; \
|
||||
_class_name& operator=(const _class_name&) = delete
|
||||
|
||||
// Macro used to simplify the task of deleting the new and new[]
|
||||
// operators. (IOW - disallow heap allocations)
|
||||
#define DISALLOW_NEW \
|
||||
static void* operator new(size_t) = delete; \
|
||||
static void* operator new[](size_t) = delete
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace lktl {
|
||||
|
||||
// call a routine when the object goes out of scope
|
||||
template <typename T>
|
||||
class auto_call {
|
||||
public:
|
||||
constexpr explicit auto_call(T call) : call_(call) {}
|
||||
~auto_call() {
|
||||
if (armed_) {
|
||||
call_();
|
||||
}
|
||||
}
|
||||
|
||||
// move
|
||||
auto_call(auto_call &&ac) : armed_(ac.armed_), call_(ac.call_) {
|
||||
ac.cancel();
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
armed_ = false;
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(auto_call);
|
||||
|
||||
bool armed_ = true;
|
||||
T call_;
|
||||
};
|
||||
|
||||
// create an auto caller with implicit template specialization.
|
||||
//
|
||||
// example:
|
||||
// auto ac = make_auto_call([]() { printf("a lambda!\n"); });
|
||||
template <typename T>
|
||||
inline auto_call<T> make_auto_call(T c) {
|
||||
return auto_call<T>(c);
|
||||
}
|
||||
|
||||
// auto mutex scope guard
|
||||
class auto_lock {
|
||||
public:
|
||||
explicit auto_lock(mutex_t *m) : m_(m) {
|
||||
mutex_acquire(m_);
|
||||
}
|
||||
|
||||
~auto_lock() {
|
||||
mutex_release(m_);
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_ASSIGN_AND_MOVE(auto_lock);
|
||||
|
||||
mutex_t *m_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace lktl
|
||||
12
app/irc/rules.mk
Normal file
12
app/irc/rules.mk
Normal file
@@ -0,0 +1,12 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
MODULE := $(LOCAL_DIR)
|
||||
|
||||
MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/irc.cpp \
|
||||
|
||||
MODULE_DEPS := \
|
||||
lib/libcpp \
|
||||
lib/minip
|
||||
|
||||
include make/module.mk
|
||||
12
app/telnetd/rules.mk
Normal file
12
app/telnetd/rules.mk
Normal file
@@ -0,0 +1,12 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
MODULE := $(LOCAL_DIR)
|
||||
|
||||
MODULE_SRCS += $(LOCAL_DIR)/telnetd.cpp
|
||||
|
||||
MODULE_DEPS := \
|
||||
lib/cksum \
|
||||
lib/libcpp \
|
||||
lib/minip
|
||||
|
||||
include make/module.mk
|
||||
72
app/telnetd/telnetd.cpp
Normal file
72
app/telnetd/telnetd.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <app.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/trace.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <lk/compiler.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <lib/minip.h>
|
||||
#include <lib/tftp.h>
|
||||
#include <lib/cksum.h>
|
||||
#include <platform.h>
|
||||
|
||||
#define LOCAL_TRACE 1
|
||||
|
||||
static int telnet_worker(void *arg) {
|
||||
tcp_socket_t *s = static_cast<tcp_socket_t *>(arg);
|
||||
|
||||
char buf[128];
|
||||
for (;;) {
|
||||
ssize_t err = tcp_read(s, buf, sizeof(buf));
|
||||
if (err < 0) {
|
||||
printf("TELENT: error from read, exiting\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
hexdump8(buf, err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void telnetd_entry(const struct app_descriptor *app, void *args) {
|
||||
printf("TELNET: waiting for network configuration\n");
|
||||
minip_wait_for_configured(INFINITE_TIME);
|
||||
printf("TELNET: starting telnet server\n");
|
||||
|
||||
// starting telnet stack
|
||||
tcp_socket_t *listen_socket;
|
||||
status_t err = tcp_open_listen(&listen_socket, 23);
|
||||
if (err < 0) {
|
||||
printf("tcp_open_listen returns %d\n", err);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
tcp_socket_t *accept_socket;
|
||||
|
||||
err = tcp_accept(listen_socket, &accept_socket);
|
||||
LTRACEF("tcp_accept returns returns %d, handle %p\n", err, accept_socket);
|
||||
if (err < 0) {
|
||||
TRACEF("error accepting socket, retrying\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("TELNET: starting worker\n");
|
||||
thread_detach_and_resume(thread_create("chargen_worker", &telnet_worker, accept_socket, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
APP_START(inetsrv)
|
||||
.init = nullptr,
|
||||
.entry = telnetd_entry,
|
||||
.flags = 0,
|
||||
.stack_size = 0,
|
||||
APP_END
|
||||
@@ -172,14 +172,15 @@ static void zynq_common_target_init(uint level) {
|
||||
sysparam_read("net0.ip_mask", &ip_mask, sizeof(ip_mask));
|
||||
sysparam_read("net0.ip_gateway", &ip_gateway, sizeof(ip_gateway));
|
||||
|
||||
minip_set_macaddr(mac_addr);
|
||||
gem_set_macaddr(mac_addr);
|
||||
|
||||
minip_set_eth(gem_send_raw_pkt, NULL, mac_addr);
|
||||
|
||||
if (!use_dhcp && ip_addr != IPV4_NONE) {
|
||||
minip_init(gem_send_raw_pkt, NULL, ip_addr, ip_mask, ip_gateway);
|
||||
minip_start_static(ip_addr, ip_mask, ip_gateway);
|
||||
} else {
|
||||
/* Configure IP stack and hook to the driver */
|
||||
minip_init_dhcp(gem_send_raw_pkt, NULL);
|
||||
minip_start_dhcp();
|
||||
}
|
||||
gem_set_callback(minip_rx_driver_callback);
|
||||
#endif
|
||||
|
||||
@@ -147,50 +147,13 @@ void arch_enter_uspace(vaddr_t entry_point, vaddr_t user_stack_top) {
|
||||
riscv_csr_write(sstatus, status);
|
||||
riscv_csr_write(sepc, entry_point);
|
||||
riscv_csr_write(sscratch, kernel_stack_top);
|
||||
|
||||
riscv_fpu_zero();
|
||||
|
||||
// put the current tp (percpu pointer) just below the top of the stack
|
||||
// the exception code will recover it when coming from user space
|
||||
((uintptr_t *)kernel_stack_top)[-1] = (uintptr_t)riscv_get_percpu();
|
||||
asm volatile(
|
||||
#if RISCV_FPU
|
||||
// zero out the fpu state
|
||||
"csrw fcsr, 0\n"
|
||||
// TODO: figure out how to do this more cleanly
|
||||
// without 'fd' in the march line the assembler wont let us emit a direct
|
||||
// fpu opcode. Tried unsuccessfully to use the .insn operand. below is a
|
||||
// series of fmv.d.x fN, zero instructions to wipe out the complete state.
|
||||
".word 0xf2000053\n" // fmv.d.x f0, zero
|
||||
".word 0xf20000d3\n" // fmv.d.x f1, zero
|
||||
".word 0xf2000153\n" // ...
|
||||
".word 0xf20001d3\n"
|
||||
".word 0xf2000253\n"
|
||||
".word 0xf20002d3\n"
|
||||
".word 0xf2000353\n"
|
||||
".word 0xf20003d3\n"
|
||||
".word 0xf2000453\n"
|
||||
".word 0xf20004d3\n"
|
||||
".word 0xf2000553\n"
|
||||
".word 0xf20005d3\n"
|
||||
".word 0xf2000653\n"
|
||||
".word 0xf20006d3\n"
|
||||
".word 0xf2000753\n"
|
||||
".word 0xf20007d3\n"
|
||||
".word 0xf2000853\n"
|
||||
".word 0xf20008d3\n"
|
||||
".word 0xf2000953\n"
|
||||
".word 0xf20009d3\n"
|
||||
".word 0xf2000a53\n"
|
||||
".word 0xf2000ad3\n"
|
||||
".word 0xf2000b53\n"
|
||||
".word 0xf2000bd3\n"
|
||||
".word 0xf2000c53\n"
|
||||
".word 0xf2000cd3\n"
|
||||
".word 0xf2000d53\n"
|
||||
".word 0xf2000dd3\n"
|
||||
".word 0xf2000e53\n"
|
||||
".word 0xf2000ed3\n"
|
||||
".word 0xf2000f53\n"
|
||||
".word 0xf2000fd3\n" // fmv.d.x f31, zero
|
||||
#endif
|
||||
// set the user stack pointer
|
||||
"mv sp, %0\n"
|
||||
// zero out the rest of the integer state
|
||||
|
||||
72
arch/riscv/fpu_asm.S
Normal file
72
arch/riscv/fpu_asm.S
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/asm.h>
|
||||
#include <arch/riscv.h>
|
||||
#include <arch/riscv/asm.h>
|
||||
|
||||
// enable full use of all of the fpu instructions
|
||||
#if __riscv_xlen == 32
|
||||
.attribute arch, "rv32imafdc"
|
||||
#elif __riscv_xlen == 64
|
||||
.attribute arch, "rv64imafdc"
|
||||
#else
|
||||
#error unknown xlen
|
||||
#endif
|
||||
|
||||
// conditionally use fcvt or fmv based on 32 or 64bit ISA
|
||||
.macro ZERO_FPU_REG reg, width
|
||||
#if __riscv_xlen == 32
|
||||
fcvt.\width\().w \reg, zero
|
||||
#elif __riscv_xlen == 64
|
||||
fmv.\width\().x \reg, zero
|
||||
#endif
|
||||
.endm
|
||||
|
||||
// called just before entering user space for the first time.
|
||||
// must not use the stack and is okay to be called with interrupts disabled.
|
||||
FUNCTION(riscv_fpu_zero)
|
||||
#if RISCV_FPU
|
||||
// zero out the fpu state
|
||||
// TODO: handle single precision implementations
|
||||
csrw fcsr, zero
|
||||
ZERO_FPU_REG f0, d
|
||||
ZERO_FPU_REG f1, d
|
||||
ZERO_FPU_REG f2, d
|
||||
ZERO_FPU_REG f3, d
|
||||
ZERO_FPU_REG f4, d
|
||||
ZERO_FPU_REG f5, d
|
||||
ZERO_FPU_REG f6, d
|
||||
ZERO_FPU_REG f7, d
|
||||
ZERO_FPU_REG f8, d
|
||||
ZERO_FPU_REG f9, d
|
||||
ZERO_FPU_REG f10, d
|
||||
ZERO_FPU_REG f11, d
|
||||
ZERO_FPU_REG f12, d
|
||||
ZERO_FPU_REG f13, d
|
||||
ZERO_FPU_REG f14, d
|
||||
ZERO_FPU_REG f15, d
|
||||
ZERO_FPU_REG f16, d
|
||||
ZERO_FPU_REG f17, d
|
||||
ZERO_FPU_REG f18, d
|
||||
ZERO_FPU_REG f19, d
|
||||
ZERO_FPU_REG f20, d
|
||||
ZERO_FPU_REG f21, d
|
||||
ZERO_FPU_REG f22, d
|
||||
ZERO_FPU_REG f23, d
|
||||
ZERO_FPU_REG f24, d
|
||||
ZERO_FPU_REG f25, d
|
||||
ZERO_FPU_REG f26, d
|
||||
ZERO_FPU_REG f27, d
|
||||
ZERO_FPU_REG f28, d
|
||||
ZERO_FPU_REG f29, d
|
||||
ZERO_FPU_REG f30, d
|
||||
ZERO_FPU_REG f31, d
|
||||
#endif
|
||||
ret
|
||||
END_FUNCTION(riscv_fpu_zero)
|
||||
|
||||
@@ -214,6 +214,9 @@ enum handler_return riscv_software_exception(void);
|
||||
enum handler_return riscv_platform_irq(void);
|
||||
void riscv_syscall_handler(struct riscv_short_iframe *frame);
|
||||
|
||||
// initialize the fpu state to zero
|
||||
void riscv_fpu_zero(void);
|
||||
|
||||
// If using S mode, time seems to be implemented in clint.h
|
||||
// TODO: clean up by moving into its own header
|
||||
#if RISCV_S_MODE
|
||||
|
||||
@@ -6,6 +6,7 @@ MODULE_SRCS += $(LOCAL_DIR)/start.S
|
||||
MODULE_SRCS += $(LOCAL_DIR)/arch.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/asm.S
|
||||
MODULE_SRCS += $(LOCAL_DIR)/exceptions.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/fpu_asm.S
|
||||
MODULE_SRCS += $(LOCAL_DIR)/thread.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/mmu.cpp
|
||||
MODULE_SRCS += $(LOCAL_DIR)/mp.c
|
||||
|
||||
@@ -60,6 +60,8 @@ public:
|
||||
|
||||
bool is_e1000e() const { return id_feat_->e1000e; }
|
||||
|
||||
const uint8_t *mac_addr() const { return mac_addr_; }
|
||||
|
||||
private:
|
||||
static const size_t rxring_len = 64;
|
||||
static const size_t txring_len = 64;
|
||||
@@ -428,10 +430,6 @@ status_t e1000::init_device(pci_location_t loc, const e1000_id_features *id) {
|
||||
}
|
||||
LTRACEF("IRQ number %#x\n", irq_base);
|
||||
|
||||
// set up minip's macaddr
|
||||
// TODO: move to something smarter
|
||||
minip_set_macaddr(mac_addr_);
|
||||
|
||||
unmask_interrupt(irq_base);
|
||||
|
||||
// set up the rx ring
|
||||
@@ -513,9 +511,7 @@ status_t e1000::init_device(pci_location_t loc, const e1000_id_features *id) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// XXX REMOVE HACK
|
||||
extern "C"
|
||||
int e1000_tx(pktbuf_t *p) {
|
||||
static int e1000_tx(pktbuf_t *p) {
|
||||
if (the_e) {
|
||||
the_e->tx(p);
|
||||
}
|
||||
@@ -523,6 +519,16 @@ int e1000_tx(pktbuf_t *p) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
status_t e1000_register_with_minip() {
|
||||
if (the_e) {
|
||||
minip_set_eth(e1000_tx, the_e, the_e->mac_addr());
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
static void e1000_init(uint level) {
|
||||
LTRACE_ENTRY;
|
||||
|
||||
|
||||
11
docs/lk_tap.txt
Normal file
11
docs/lk_tap.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
# Setting up a tun/tap network for qemu
|
||||
sudo ip tuntap add mode tap user $USER name qemu0
|
||||
sudo ip link set qemu0 up
|
||||
|
||||
# manually making bridge
|
||||
sudo brctl addbr br0
|
||||
sudo brctl addif br0 qemu0
|
||||
sudo brctl addif br0 <physical nic>
|
||||
sudo ip link set br0 up
|
||||
|
||||
# alternatively using the network config to create the bridge and merge it with particular vlan
|
||||
@@ -224,6 +224,7 @@ status_t elf_load(elf_handle_t *handle) {
|
||||
void *ptr = (void *)(uintptr_t)pheader->p_vaddr;
|
||||
|
||||
if (handle->mem_alloc_hook) {
|
||||
// TODO: pass flags re: X bit, etc
|
||||
status_t err = handle->mem_alloc_hook(handle, &ptr, pheader->p_memsz, load_count, 0);
|
||||
if (err < 0) {
|
||||
LTRACEF("mem hook failed, abort\n");
|
||||
@@ -233,7 +234,7 @@ status_t elf_load(elf_handle_t *handle) {
|
||||
}
|
||||
|
||||
// read the file portion of the segment into memory at vaddr
|
||||
LTRACEF("reading segment at offset " ELF_OFF_PRINT_U " to address %p\n", pheader->p_offset, ptr);
|
||||
LTRACEF("reading segment at offset 0x" ELF_OFF_PRINT_X " to address %p\n", pheader->p_offset, ptr);
|
||||
readerr = handle->read_hook(handle, ptr, pheader->p_offset, pheader->p_filesz);
|
||||
if (readerr < (ssize_t)pheader->p_filesz) {
|
||||
LTRACEF("error %ld reading program header %u\n", readerr, i);
|
||||
|
||||
@@ -16,26 +16,19 @@
|
||||
#include <kernel/mutex.h>
|
||||
#include <lk/trace.h>
|
||||
|
||||
typedef union {
|
||||
uint32_t u;
|
||||
uint8_t b[4];
|
||||
} ipv4_t;
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
static struct list_node arp_list;
|
||||
typedef struct {
|
||||
struct list_node node;
|
||||
uint32_t addr;
|
||||
uint8_t mac[6];
|
||||
} arp_entry_t;
|
||||
|
||||
static struct list_node arp_list = LIST_INITIAL_VALUE(arp_list);
|
||||
static mutex_t arp_mutex = MUTEX_INITIAL_VALUE(arp_mutex);
|
||||
|
||||
void arp_cache_init(void) {
|
||||
list_initialize(&arp_list);
|
||||
}
|
||||
void arp_cache_init(void) {}
|
||||
|
||||
static inline void mru_update(struct list_node *entry) {
|
||||
static void mru_update(struct list_node *entry) {
|
||||
if (arp_list.next == entry)
|
||||
return;
|
||||
|
||||
@@ -77,7 +70,7 @@ void arp_cache_update(uint32_t addr, const uint8_t mac[6]) {
|
||||
}
|
||||
|
||||
arp->addr = addr;
|
||||
memcpy(arp->mac, mac, sizeof(arp->mac));
|
||||
mac_addr_copy(arp->mac, mac);
|
||||
list_add_head(&arp_list, &arp->node);
|
||||
}
|
||||
|
||||
|
||||
@@ -253,6 +253,9 @@ void dhcp::udp_callback(void *data, size_t sz, uint32_t srcip, uint16_t srcport)
|
||||
#endif
|
||||
sz -= sizeof(dhcp_msg_t);
|
||||
opt = msg->options;
|
||||
#if TRACE_DHCP
|
||||
printf("\toptions: ");
|
||||
#endif
|
||||
while (sz >= 2) {
|
||||
sz -= 2;
|
||||
if (opt[1] > sz) {
|
||||
@@ -319,6 +322,9 @@ done:
|
||||
}
|
||||
state_ = CONFIGURED;
|
||||
configured_ = true;
|
||||
|
||||
// signal that minip is ready to be used
|
||||
minip_set_configured();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -372,9 +378,7 @@ status_t dhcp::start() {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void minip_init_dhcp(tx_func_t tx_func, void *tx_arg) {
|
||||
minip_init(tx_func, tx_arg, IPV4_NONE, IPV4_NONE, IPV4_NONE);
|
||||
|
||||
void minip_start_dhcp() {
|
||||
static dhcp d;
|
||||
d.start();
|
||||
}
|
||||
|
||||
@@ -8,15 +8,14 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <lk/compiler.h>
|
||||
#include <endian.h>
|
||||
#include <iovec.h>
|
||||
#include <lib/pktbuf.h>
|
||||
#include <lk/compiler.h>
|
||||
#include <lk/list.h>
|
||||
#include <stdint.h>
|
||||
#include <iovec.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <lib/pktbuf.h>
|
||||
|
||||
__BEGIN_CDECLS
|
||||
|
||||
#define IPV4(a,b,c,d) (((a)&0xFF)|(((b)&0xFF)<<8)|(((c)&0xFF)<<16)|(((d)&0xFF)<<24))
|
||||
@@ -29,12 +28,21 @@ typedef int (*tx_func_t)(pktbuf_t *p);
|
||||
typedef void (*udp_callback_t)(void *data, size_t len,
|
||||
uint32_t srcaddr, uint16_t srcport, void *arg);
|
||||
|
||||
/* initialize minip with static configuration */
|
||||
void minip_init(tx_func_t tx_func, void *tx_arg,
|
||||
uint32_t ip, uint32_t netmask, uint32_t gateway);
|
||||
/* initialize and start minip with static configuration */
|
||||
void minip_start_static(uint32_t ip, uint32_t netmask, uint32_t gateway);
|
||||
|
||||
/* initialize minip with DHCP configuration */
|
||||
void minip_init_dhcp(tx_func_t tx_func, void *tx_arg);
|
||||
/* initialize and start minip with DHCP configuration
|
||||
* note: may take a while to have an ip address assigned, check
|
||||
* for configuration with minip_is_configured()
|
||||
*/
|
||||
void minip_start_dhcp(void);
|
||||
|
||||
/* ethernet driver install hook */
|
||||
void minip_set_eth(tx_func_t tx_handler, void *tx_arg, const uint8_t *macaddr);
|
||||
|
||||
/* check or wait for minip to be configured */
|
||||
bool minip_is_configured(void);
|
||||
status_t minip_wait_for_configured(lk_time_t timeout);
|
||||
|
||||
/* packet rx hook to hand to ethernet driver */
|
||||
void minip_rx_driver_callback(pktbuf_t *p);
|
||||
@@ -45,17 +53,14 @@ void minip_set_macaddr(const uint8_t *addr);
|
||||
|
||||
uint32_t minip_get_ipaddr(void);
|
||||
void minip_set_ipaddr(const uint32_t addr);
|
||||
|
||||
uint32_t minip_get_netmask(void);
|
||||
void minip_set_netmask(const uint32_t mask);
|
||||
uint32_t minip_get_broadcast(void); // computed from ipaddr & netmask
|
||||
uint32_t minip_get_gateway(void);
|
||||
void minip_set_gateway(const uint32_t addr);
|
||||
void minip_set_hostname(const char *name);
|
||||
const char *minip_get_hostname(void);
|
||||
|
||||
uint32_t minip_get_broadcast(void);
|
||||
|
||||
uint32_t minip_get_netmask(void);
|
||||
void minip_set_netmask(const uint32_t netmask);
|
||||
|
||||
uint32_t minip_get_gateway(void);
|
||||
void minip_set_gateway(const uint32_t gateway);
|
||||
void minip_set_configured(void); // set by dhcp or static init to signal minip is ready to be used
|
||||
|
||||
/* udp */
|
||||
typedef struct udp_socket udp_socket_t;
|
||||
@@ -69,6 +74,7 @@ status_t udp_close(udp_socket_t *handle);
|
||||
/* tcp */
|
||||
typedef struct tcp_socket tcp_socket_t;
|
||||
|
||||
status_t tcp_connect(tcp_socket_t **handle, uint32_t addr, uint16_t port);
|
||||
status_t tcp_open_listen(tcp_socket_t **handle, uint16_t port);
|
||||
status_t tcp_accept_timeout(tcp_socket_t *listen_socket, tcp_socket_t **accept_socket, lk_time_t timeout);
|
||||
status_t tcp_close(tcp_socket_t *socket);
|
||||
@@ -81,6 +87,7 @@ static inline status_t tcp_accept(tcp_socket_t *listen_socket, tcp_socket_t **ac
|
||||
|
||||
/* utilities */
|
||||
void gen_random_mac_address(uint8_t *mac_addr);
|
||||
uint32_t minip_parse_ipaddr(const char *addr, size_t len);
|
||||
|
||||
uint32_t minip_parse_ipaddr(const char *addr, size_t len);
|
||||
void printip(uint32_t x);
|
||||
|
||||
@@ -89,7 +89,13 @@ enum {
|
||||
extern tx_func_t minip_tx_handler;
|
||||
typedef struct udp_hdr udp_hdr_t;
|
||||
static const uint8_t bcast_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
typedef uint32_t ipv4_addr;
|
||||
typedef union {
|
||||
uint32_t u;
|
||||
uint8_t b[4];
|
||||
} ipv4_t;
|
||||
|
||||
// ARP cache
|
||||
void arp_cache_init(void);
|
||||
void arp_cache_update(uint32_t addr, const uint8_t mac[6]);
|
||||
uint8_t *arp_cache_lookup(uint32_t addr);
|
||||
@@ -101,7 +107,7 @@ uint16_t rfc1701_chksum(const uint8_t *buf, size_t len);
|
||||
uint16_t rfc768_chksum(struct ipv4_hdr *ipv4, udp_hdr_t *udp);
|
||||
uint16_t ones_sum16(uint32_t sum, const void *_buf, int len);
|
||||
|
||||
/* Helper methods for building headers */
|
||||
// Helper methods for building headers
|
||||
void minip_build_mac_hdr(struct eth_hdr *pkt, const uint8_t *dst, uint16_t type);
|
||||
void minip_build_ipv4_hdr(struct ipv4_hdr *ipv4, uint32_t dst, uint8_t proto, uint16_t len);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "minip-internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <lk/err.h>
|
||||
#include <stdio.h>
|
||||
#include <lk/debug.h>
|
||||
@@ -20,10 +21,10 @@
|
||||
#include <lk/trace.h>
|
||||
#include <malloc.h>
|
||||
#include <lk/list.h>
|
||||
#include <lk/init.h>
|
||||
#include <kernel/event.h>
|
||||
#include <kernel/thread.h>
|
||||
|
||||
static struct list_node arp_list = LIST_INITIAL_VALUE(arp_list);
|
||||
|
||||
// TODO
|
||||
// 1. Tear endian code out into something that flips words before/after tx/rx calls
|
||||
|
||||
@@ -38,11 +39,37 @@ static uint8_t minip_mac[6] = {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
|
||||
|
||||
static char minip_hostname[32] = "";
|
||||
|
||||
static volatile bool minip_configured = false;
|
||||
static event_t minip_configured_event = EVENT_INITIAL_VALUE(minip_configured_event, false, 0);
|
||||
|
||||
/* This function is called by minip to send packets */
|
||||
tx_func_t minip_tx_handler;
|
||||
void *minip_tx_arg;
|
||||
|
||||
static void dump_mac_address(const uint8_t *mac);
|
||||
static void dump_ipv4_addr(uint32_t addr);
|
||||
|
||||
/* if all the important configuration bits are set, signal that we're configured */
|
||||
static void check_and_set_configured(void) {
|
||||
if (minip_ip == IPV4_NONE) return;
|
||||
if (minip_netmask == IPV4_NONE) return;
|
||||
if (minip_broadcast == IPV4_BCAST) return;
|
||||
// minip_gateway doesn't have to be set
|
||||
if (minip_mac[0] == 0xcc &&
|
||||
minip_mac[1] == 0xcc &&
|
||||
minip_mac[2] == 0xcc &&
|
||||
minip_mac[3] == 0xcc &&
|
||||
minip_mac[4] == 0xcc &&
|
||||
minip_mac[5] == 0xcc) return;
|
||||
|
||||
// we're configured
|
||||
printf("MINIP: setting configured state\n");
|
||||
minip_set_configured();
|
||||
}
|
||||
|
||||
void minip_set_hostname(const char *name) {
|
||||
strlcpy(minip_hostname, name, sizeof(minip_hostname));
|
||||
check_and_set_configured();
|
||||
}
|
||||
|
||||
const char *minip_get_hostname(void) {
|
||||
@@ -57,10 +84,6 @@ void minip_get_macaddr(uint8_t *addr) {
|
||||
mac_addr_copy(addr, minip_mac);
|
||||
}
|
||||
|
||||
void minip_set_macaddr(const uint8_t *addr) {
|
||||
mac_addr_copy(minip_mac, addr);
|
||||
}
|
||||
|
||||
uint32_t minip_get_ipaddr(void) {
|
||||
return minip_ip;
|
||||
}
|
||||
@@ -68,6 +91,7 @@ uint32_t minip_get_ipaddr(void) {
|
||||
void minip_set_ipaddr(const uint32_t addr) {
|
||||
minip_ip = addr;
|
||||
compute_broadcast_address();
|
||||
check_and_set_configured();
|
||||
}
|
||||
|
||||
uint32_t minip_get_broadcast(void) {
|
||||
@@ -81,14 +105,30 @@ uint32_t minip_get_netmask(void) {
|
||||
void minip_set_netmask(const uint32_t netmask) {
|
||||
minip_netmask = netmask;
|
||||
compute_broadcast_address();
|
||||
check_and_set_configured();
|
||||
}
|
||||
|
||||
uint32_t minip_get_gateway(void) {
|
||||
return minip_gateway;
|
||||
}
|
||||
|
||||
void minip_set_gateway(const uint32_t gateway) {
|
||||
minip_gateway = gateway;
|
||||
void minip_set_gateway(const uint32_t addr) {
|
||||
minip_gateway = addr;
|
||||
// TODO: check that it is reacheable on local network
|
||||
check_and_set_configured();
|
||||
}
|
||||
|
||||
void minip_set_configured(void) {
|
||||
minip_configured = true;
|
||||
event_signal(&minip_configured_event, true);
|
||||
}
|
||||
|
||||
bool minip_is_configured(void) {
|
||||
return minip_configured;
|
||||
}
|
||||
|
||||
status_t minip_wait_for_configured(lk_time_t timeout) {
|
||||
return event_wait_timeout(&minip_configured_event, timeout);
|
||||
}
|
||||
|
||||
void gen_random_mac_address(uint8_t *mac_addr) {
|
||||
@@ -100,22 +140,24 @@ void gen_random_mac_address(uint8_t *mac_addr) {
|
||||
mac_addr[0] |= (1<<1);
|
||||
}
|
||||
|
||||
/* This function is called by minip to send packets */
|
||||
tx_func_t minip_tx_handler;
|
||||
void *minip_tx_arg;
|
||||
void minip_start_static(uint32_t ip, uint32_t mask, uint32_t gateway) {
|
||||
minip_set_ipaddr(ip);
|
||||
minip_set_netmask(mask);
|
||||
minip_set_gateway(gateway);
|
||||
}
|
||||
|
||||
void minip_init(tx_func_t tx_handler, void *tx_arg,
|
||||
uint32_t ip, uint32_t mask, uint32_t gateway) {
|
||||
void minip_set_eth(tx_func_t tx_handler, void *tx_arg, const uint8_t *macaddr) {
|
||||
LTRACEF("handler %p, arg %p, macaddr %p\n", tx_handler, tx_arg, macaddr);
|
||||
|
||||
DEBUG_ASSERT(minip_tx_handler == NULL);
|
||||
DEBUG_ASSERT(minip_tx_arg == NULL);
|
||||
// TODO: assert mac address is not already set
|
||||
|
||||
// set up the low level driver handler
|
||||
minip_tx_handler = tx_handler;
|
||||
minip_tx_arg = tx_arg;
|
||||
|
||||
minip_ip = ip;
|
||||
minip_netmask = mask;
|
||||
minip_gateway = gateway;
|
||||
compute_broadcast_address();
|
||||
|
||||
arp_cache_init();
|
||||
net_timer_init();
|
||||
mac_addr_copy(minip_mac, macaddr);
|
||||
}
|
||||
|
||||
static uint16_t ipv4_payload_len(struct ipv4_hdr *pkt) {
|
||||
@@ -209,13 +251,24 @@ status_t minip_ipv4_send(pktbuf_t *p, uint32_t dest_addr, uint8_t proto) {
|
||||
struct ipv4_hdr *ip = pktbuf_prepend(p, sizeof(struct ipv4_hdr));
|
||||
struct eth_hdr *eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
|
||||
|
||||
|
||||
// are we sending a broadcast packet?
|
||||
if (dest_addr == IPV4_BCAST || dest_addr == minip_broadcast) {
|
||||
dst_mac = bcast_mac;
|
||||
goto ready;
|
||||
}
|
||||
|
||||
dst_mac = get_dest_mac(dest_addr);
|
||||
// is this a local subnet packet or do we need to send to the router?
|
||||
uint32_t target_addr = dest_addr;
|
||||
if ((dest_addr & minip_netmask) != (minip_ip & minip_netmask)) {
|
||||
// need to use the gateway
|
||||
if (minip_gateway == IPV4_NONE) {
|
||||
return ERR_NOT_FOUND; // TODO: better error code
|
||||
}
|
||||
|
||||
target_addr = minip_gateway;
|
||||
}
|
||||
|
||||
dst_mac = arp_get_dest_mac(target_addr);
|
||||
if (!dst_mac) {
|
||||
pktbuf_free(p, true);
|
||||
ret = -EHOSTUNREACH;
|
||||
@@ -499,3 +552,12 @@ void printip_named(const char *s, uint32_t x) {
|
||||
printf("%s ", s);
|
||||
printip(x);
|
||||
}
|
||||
|
||||
// run static initialization
|
||||
static void minip_init(uint level) {
|
||||
arp_cache_init();
|
||||
net_timer_init();
|
||||
}
|
||||
|
||||
|
||||
LK_INIT_HOOK(minip, minip_init, LK_INIT_LEVEL_THREADING);
|
||||
|
||||
116
lib/minip/tcp.c
116
lib/minip/tcp.c
@@ -25,8 +25,6 @@
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
typedef uint32_t ipv4_addr;
|
||||
|
||||
typedef struct tcp_header {
|
||||
uint16_t source_port;
|
||||
uint16_t dest_port;
|
||||
@@ -114,6 +112,9 @@ typedef struct tcp_socket {
|
||||
struct tcp_socket *accepted;
|
||||
|
||||
net_timer_t time_wait_timer;
|
||||
|
||||
/* connect waiting */
|
||||
event_t connect_event;
|
||||
} tcp_socket_t;
|
||||
|
||||
#define DEFAULT_MSS (1460)
|
||||
@@ -216,7 +217,7 @@ static void dump_socket(tcp_socket_t *s) {
|
||||
}
|
||||
|
||||
static tcp_socket_t *lookup_socket(ipv4_addr remote_ip, ipv4_addr local_ip, uint16_t remote_port, uint16_t local_port) {
|
||||
LTRACEF("remote ip 0x%x local ip 0x%x remote port %u local port %u\n", remote_ip, local_ip, remote_port, local_port);
|
||||
LTRACEF_LEVEL(2, "remote ip 0x%x local ip 0x%x remote port %u local port %u\n", remote_ip, local_ip, remote_port, local_port);
|
||||
|
||||
mutex_acquire(&tcp_socket_list_lock);
|
||||
|
||||
@@ -286,7 +287,7 @@ static void inc_socket_ref(tcp_socket_t *s) {
|
||||
DEBUG_ASSERT(s);
|
||||
|
||||
__UNUSED int oldval = atomic_add(&s->ref, 1);
|
||||
LTRACEF("caller %p, thread %p, socket %p, ref now %d\n", __GET_CALLER(), get_current_thread(), s, oldval + 1);
|
||||
LTRACEF_LEVEL(2, "caller %p, thread %p, socket %p, ref now %d\n", __GET_CALLER(), get_current_thread(), s, oldval + 1);
|
||||
DEBUG_ASSERT(oldval > 0);
|
||||
}
|
||||
|
||||
@@ -294,12 +295,13 @@ static bool dec_socket_ref(tcp_socket_t *s) {
|
||||
DEBUG_ASSERT(s);
|
||||
|
||||
int oldval = atomic_add(&s->ref, -1);
|
||||
LTRACEF("caller %p, thread %p, socket %p, ref now %d\n", __GET_CALLER(), get_current_thread(), s, oldval - 1);
|
||||
LTRACEF_LEVEL(2, "caller %p, thread %p, socket %p, ref now %d\n", __GET_CALLER(), get_current_thread(), s, oldval - 1);
|
||||
|
||||
if (oldval == 1) {
|
||||
LTRACEF("destroying socket\n");
|
||||
event_destroy(&s->tx_event);
|
||||
event_destroy(&s->rx_event);
|
||||
event_destroy(&s->connect_event);
|
||||
|
||||
free(s->rx_buffer_raw);
|
||||
free(s->tx_buffer);
|
||||
@@ -482,6 +484,44 @@ void tcp_input(pktbuf_t *p, uint32_t src_ip, uint32_t dst_ip) {
|
||||
|
||||
break;
|
||||
|
||||
/* active connection state */
|
||||
case STATE_SYN_SENT:
|
||||
if ((packet_flags & PKT_SYN) == 0) {
|
||||
// we got data on the packet without a syn, reset
|
||||
goto send_reset;
|
||||
}
|
||||
|
||||
if ((packet_flags & PKT_ACK) == 0) {
|
||||
// simultaneous SYN/ACK
|
||||
// TODO: handle
|
||||
goto send_reset;
|
||||
}
|
||||
|
||||
LTRACEF("ack num %d tx win_low %d\n", header->ack_num, s->tx_win_low);
|
||||
|
||||
if (header->ack_num != s->tx_win_low + 1) {
|
||||
// they didn't ack our syn
|
||||
goto send_reset;
|
||||
}
|
||||
|
||||
// remember their sequence
|
||||
s->rx_win_low = header->seq_num + 1;
|
||||
s->rx_win_high = s->rx_win_low + s->rx_win_size - 1;
|
||||
|
||||
s->tx_win_low++;
|
||||
s->tx_win_high = s->tx_win_low + header->win_size;
|
||||
s->tx_highest_seq = s->tx_win_low;
|
||||
|
||||
s->state = STATE_ESTABLISHED;
|
||||
|
||||
send_ack(s);
|
||||
|
||||
event_signal(&s->connect_event, true);
|
||||
|
||||
break;
|
||||
|
||||
/* established state */
|
||||
|
||||
case STATE_ESTABLISHED:
|
||||
if (packet_flags & PKT_ACK) {
|
||||
/* they're acking us */
|
||||
@@ -565,9 +605,6 @@ fin_wait_2:
|
||||
case STATE_TIME_WAIT:
|
||||
/* /dev/null of packets */
|
||||
break;
|
||||
|
||||
case STATE_SYN_SENT:
|
||||
PANIC_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -887,6 +924,7 @@ static void tcp_wakeup_waiters(tcp_socket_t *s) {
|
||||
// wake up any waiters
|
||||
event_signal(&s->rx_event, true);
|
||||
event_signal(&s->tx_event, true);
|
||||
event_signal(&s->connect_event, true);
|
||||
}
|
||||
|
||||
static void tcp_remote_close(tcp_socket_t *s) {
|
||||
@@ -938,11 +976,72 @@ static tcp_socket_t *create_tcp_socket(bool alloc_buffers) {
|
||||
}
|
||||
|
||||
sem_init(&s->accept_sem, 0);
|
||||
event_init(&s->connect_event, false, 0);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* user api */
|
||||
status_t tcp_connect(tcp_socket_t **handle, uint32_t addr, uint16_t port) {
|
||||
tcp_socket_t *s;
|
||||
|
||||
if (!handle)
|
||||
return ERR_INVALID_ARGS;
|
||||
|
||||
s = create_tcp_socket(true);
|
||||
if (!s)
|
||||
return ERR_NO_MEMORY;
|
||||
|
||||
// XXX add some entropy to try to better randomize things
|
||||
lk_bigtime_t t = current_time_hires();
|
||||
printf("%lld\n", t);
|
||||
rand_add_entropy(&t, sizeof(t));
|
||||
|
||||
// set up the socket for outgoing connections
|
||||
s->local_ip = minip_get_ipaddr();
|
||||
s->local_port = (rand() + 1024) & 0xffff; // TODO: allocate sanely
|
||||
DEBUG_ASSERT(s->local_port <= 0xffff);
|
||||
s->remote_ip = addr;
|
||||
s->remote_port = port;
|
||||
|
||||
if (LOCAL_TRACE) {
|
||||
dump_socket(s);
|
||||
}
|
||||
|
||||
// send a SYN packet
|
||||
mutex_acquire(&s->lock);
|
||||
|
||||
s->state = STATE_SYN_SENT;
|
||||
add_socket_to_list(s);
|
||||
|
||||
/* set up a mss option for sending back */
|
||||
tcp_mss_option_t mss_option;
|
||||
mss_option.kind = 0x2;
|
||||
mss_option.len = 0x4;
|
||||
mss_option.mss = ntohs(s->mss);
|
||||
|
||||
tcp_send(s->remote_ip, s->remote_port, s->local_ip, s->local_port, NULL, 0, PKT_SYN, &mss_option, 0x4, 0, s->tx_win_low, s->rx_win_size);
|
||||
|
||||
// TODO: handle retransmit
|
||||
|
||||
mutex_release(&s->lock);
|
||||
|
||||
// block to wait for a successful connection
|
||||
if (event_wait(&s->connect_event) == ERR_TIMED_OUT) {
|
||||
return ERR_TIMED_OUT;
|
||||
}
|
||||
|
||||
status_t err = NO_ERROR;
|
||||
mutex_acquire(&s->lock);
|
||||
if (s->state != STATE_ESTABLISHED) {
|
||||
err = ERR_CHANNEL_CLOSED;
|
||||
}
|
||||
mutex_release(&s->lock);
|
||||
|
||||
*handle = s;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t tcp_open_listen(tcp_socket_t **handle, uint16_t port) {
|
||||
tcp_socket_t *s;
|
||||
@@ -1150,6 +1249,7 @@ status_t tcp_close(tcp_socket_t *socket) {
|
||||
|
||||
// XXX set up fin retransmit timer here
|
||||
break;
|
||||
case STATE_SYN_SENT:
|
||||
case STATE_FIN_WAIT_1:
|
||||
case STATE_FIN_WAIT_2:
|
||||
case STATE_CLOSING:
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include <lk/err.h>
|
||||
#include <lk/init.h>
|
||||
#include <lk/trace.h>
|
||||
#include <arch/x86/mmu.h>
|
||||
#include <platform.h>
|
||||
@@ -300,9 +301,16 @@ void platform_init(void) {
|
||||
#endif
|
||||
|
||||
platform_init_mmu_mappings();
|
||||
}
|
||||
|
||||
#if WITH_LIB_MINIP
|
||||
extern int e1000_tx(pktbuf_t *p);
|
||||
minip_init_dhcp(e1000_tx, 0);
|
||||
#endif
|
||||
void _start_minip(uint level) {
|
||||
extern status_t e1000_register_with_minip(void);
|
||||
status_t err = e1000_register_with_minip();
|
||||
if (err == NO_ERROR) {
|
||||
minip_start_dhcp();
|
||||
}
|
||||
}
|
||||
|
||||
LK_INIT_HOOK(start_minip, _start_minip, LK_INIT_LEVEL_APPS - 1);
|
||||
#endif
|
||||
|
||||
@@ -226,16 +226,16 @@ void platform_init(void) {
|
||||
TRACEF("found virtio networking interface\n");
|
||||
|
||||
/* start minip */
|
||||
minip_set_macaddr(mac_addr);
|
||||
minip_set_eth(virtio_net_send_minip_pkt, NULL, mac_addr);
|
||||
|
||||
__UNUSED uint32_t ip_addr = IPV4(192, 168, 0, 99);
|
||||
__UNUSED uint32_t ip_mask = IPV4(255, 255, 255, 0);
|
||||
__UNUSED uint32_t ip_gateway = IPV4_NONE;
|
||||
|
||||
//minip_init(virtio_net_send_minip_pkt, NULL, ip_addr, ip_mask, ip_gateway);
|
||||
minip_init_dhcp(virtio_net_send_minip_pkt, NULL);
|
||||
|
||||
virtio_net_start();
|
||||
|
||||
//minip_start_static(ip_addr, ip_mask, ip_gateway);
|
||||
minip_start_dhcp();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -106,16 +106,16 @@ void platform_init(void) {
|
||||
TRACEF("found virtio networking interface\n");
|
||||
|
||||
/* start minip */
|
||||
minip_set_macaddr(mac_addr);
|
||||
minip_set_eth(virtio_net_send_minip_pkt, NULL, mac_addr);
|
||||
|
||||
__UNUSED uint32_t ip_addr = IPV4(192, 168, 0, 99);
|
||||
__UNUSED uint32_t ip_mask = IPV4(255, 255, 255, 0);
|
||||
__UNUSED uint32_t ip_gateway = IPV4_NONE;
|
||||
|
||||
//minip_init(virtio_net_send_minip_pkt, NULL, ip_addr, ip_mask, ip_gateway);
|
||||
minip_init_dhcp(virtio_net_send_minip_pkt, NULL);
|
||||
|
||||
virtio_net_start();
|
||||
|
||||
//minip_start_static(ip_addr, ip_mask, ip_gateway);
|
||||
minip_start_dhcp();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -198,16 +198,19 @@ void platform_init(void) {
|
||||
TRACEF("found virtio networking interface\n");
|
||||
|
||||
/* start minip */
|
||||
minip_set_macaddr(mac_addr);
|
||||
minip_set_eth(virtio_net_send_minip_pkt, NULL, mac_addr);
|
||||
|
||||
virtio_net_start();
|
||||
|
||||
#if 0
|
||||
__UNUSED uint32_t ip_addr = IPV4(192, 168, 0, 99);
|
||||
__UNUSED uint32_t ip_mask = IPV4(255, 255, 255, 0);
|
||||
__UNUSED uint32_t ip_gateway = IPV4_NONE;
|
||||
|
||||
//minip_init(virtio_net_send_minip_pkt, NULL, ip_addr, ip_mask, ip_gateway);
|
||||
minip_init_dhcp(virtio_net_send_minip_pkt, NULL);
|
||||
|
||||
virtio_net_start();
|
||||
minip_start_static(ip_addr, ip_mask, ip_gateway);
|
||||
#else
|
||||
minip_start_dhcp();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# main project for qemu-riscv64-supervisor
|
||||
MODULES += \
|
||||
app/irc \
|
||||
app/shell
|
||||
SUBARCH := 64
|
||||
RISCV_MODE := supervisor
|
||||
|
||||
include project/virtual/test.mk
|
||||
include project/virtual/fs.mk
|
||||
include project/virtual/minip.mk
|
||||
include project/virtual/inetapps.mk
|
||||
include project/target/qemu-virt-riscv.mk
|
||||
|
||||
|
||||
8
project/virtual/inetapps.mk
Normal file
8
project/virtual/inetapps.mk
Normal file
@@ -0,0 +1,8 @@
|
||||
# some internet apps that depend on minip
|
||||
|
||||
MODULES += \
|
||||
app/inetsrv \
|
||||
app/irc \
|
||||
app/telnetd \
|
||||
|
||||
include project/virtual/minip.mk
|
||||
@@ -1,6 +1,4 @@
|
||||
# modules related to the minip stack
|
||||
|
||||
MODULES += \
|
||||
lib/minip \
|
||||
app/inetsrv
|
||||
|
||||
lib/minip
|
||||
|
||||
@@ -104,7 +104,7 @@ fi
|
||||
|
||||
BLOCK_ARGS=" -drive if=none,file=blk.bin,id=blk,format=raw -device virtio-blk-device,drive=blk"
|
||||
NET_ARGS=" -netdev user,id=vmnic,hostname=qemu -device virtio-net-device,netdev=vmnic"
|
||||
NET_TAP_ARGS=" -netdev tap,id=vmnic -device virtio-net-device,netdev=vmnic"
|
||||
NET_TAP_ARGS=" -netdev tap,id=vmnic,ifname=qemu0,script=no -device virtio-net-device,netdev=vmnic"
|
||||
NO_DISPLAY_ARGS=" -nographic"
|
||||
DISPLAY_ARGS=" -device virtio-gpu-device -serial stdio"
|
||||
|
||||
@@ -130,7 +130,7 @@ if (( $DO_NET )); then
|
||||
fi
|
||||
if (( $DO_NET_TAP )); then
|
||||
ARGS+=$NET_TAP_ARGS
|
||||
SUDO="sudo "
|
||||
#SUDO="sudo "
|
||||
fi
|
||||
if (( $DO_DISPLAY )); then
|
||||
ARGS+=$DISPLAY_ARGS
|
||||
|
||||
@@ -123,13 +123,13 @@ void target_init(void) {
|
||||
eth_init(mac_addr, PHY_KSZ8721);
|
||||
|
||||
/* start minip */
|
||||
minip_set_macaddr(mac_addr);
|
||||
minip_set_eth(stm32_eth_send_minip_pkt, NULL, mac_addr);
|
||||
|
||||
uint32_t ip_addr = IPV4(192, 168, 0, 98);
|
||||
uint32_t ip_mask = IPV4(255, 255, 255, 0);
|
||||
uint32_t ip_gateway = IPV4_NONE;
|
||||
|
||||
minip_init(stm32_eth_send_minip_pkt, NULL, ip_addr, ip_mask, ip_gateway);
|
||||
minip_start_static(ip_addr, ip_mask, ip_gateway);
|
||||
#endif
|
||||
|
||||
#if WITH_LIB_FS_SPIFS
|
||||
|
||||
@@ -67,13 +67,13 @@ void target_init(void) {
|
||||
eth_init(mac_addr, PHY_DP83848);
|
||||
|
||||
/* start minip */
|
||||
minip_set_macaddr(mac_addr);
|
||||
minip_set_eth(stm32_eth_send_minip_pkt, NULL, mac_addr);
|
||||
|
||||
uint32_t ip_addr = IPV4(192, 168, 0, 99);
|
||||
uint32_t ip_mask = IPV4(255, 255, 255, 0);
|
||||
uint32_t ip_gateway = IPV4_NONE;
|
||||
|
||||
minip_init(stm32_eth_send_minip_pkt, NULL, ip_addr, ip_mask, ip_gateway);
|
||||
minip_start_static(ip_addr, ip_mask, ip_gateway);
|
||||
#endif
|
||||
|
||||
TRACE_EXIT;
|
||||
|
||||
@@ -64,13 +64,13 @@ void target_init(void) {
|
||||
eth_init(mac_addr, PHY_LAN8742A);
|
||||
|
||||
/* start minip */
|
||||
minip_set_macaddr(mac_addr);
|
||||
minip_set_eth(stm32_eth_send_minip_pkt, NULL, mac_addr);
|
||||
|
||||
uint32_t ip_addr = IPV4(192, 168, 0, 98);
|
||||
uint32_t ip_mask = IPV4(255, 255, 255, 0);
|
||||
uint32_t ip_gateway = IPV4_NONE;
|
||||
|
||||
minip_init(stm32_eth_send_minip_pkt, NULL, ip_addr, ip_mask, ip_gateway);
|
||||
minip_start_static(ip_addr, ip_mask, ip_gateway);
|
||||
#endif
|
||||
|
||||
// start usb
|
||||
|
||||
Reference in New Issue
Block a user