diff --git a/linux/vnet/tap.c b/linux/vnet/tap.c index 3573e9c..ee02d1e 100644 --- a/linux/vnet/tap.c +++ b/linux/vnet/tap.c @@ -25,14 +25,14 @@ static STDCALL void vnet_unload_tap() { - printf("vnet_unload\n"); + printf("vnet_unload_tap\n"); COVERAGE_ON(); COVERAGE_OFF(); } static STDCALL void vnet_reset_tap() { - printf("vnet_reset\n"); + printf("vnet_reset_tap\n"); COVERAGE_ON(); COVERAGE_OFF(); } @@ -49,18 +49,18 @@ static STDCALL int vnet_transmit_tap(net_buff_t *buf) { struct vnet *net; __asm__ __inline__ __volatile__ ( - "nop" + "" : "=b"(net) : : "memory"); printf("vnet_transmit: %d bytes\n", buf->length); dump_net_buff(buf); - write(net->fdout, buf->data, buf->length); + ssize_t written = write(net->fdout, buf->data, buf->length); buf->length = 0; COVERAGE_OFF(); COVERAGE_ON(); - printf("vnet_transmit: done\n"); + printf("vnet_transmit: %d bytes written\n", written); return 0; } @@ -71,7 +71,7 @@ vnet_init_tap() { int fd, err; if( (fd = open(TAP_DEV, O_RDWR | O_NONBLOCK)) < 0 ) { - perror("Opening /dev/net/tun"); + perror("Opening " TAP_DEV ); return NULL; } @@ -125,18 +125,23 @@ vnet_init_tap() { return NULL; } - struct vnet *net = malloc(sizeof(struct vnet)); - net->netdev.device_type = NET_TYPE_ETH; - net->netdev.mtu = 1514; - net->netdev.name = "UMK0770"; + struct vnet *vnet = malloc(sizeof(struct vnet)); + vnet->eth.net.device_type = NET_TYPE_ETH; + vnet->eth.net.mtu = 1514; + char *devname = malloc(8); + sprintf(devname, "UMKTAP%d", 0); // FIXME: support more devices + vnet->eth.net.name = devname; - net->netdev.unload = vnet_unload_tap; - net->netdev.reset = vnet_reset_tap; - net->netdev.transmit = vnet_transmit_tap; + vnet->eth.net.unload = vnet_unload_tap; + vnet->eth.net.reset = vnet_reset_tap; + vnet->eth.net.transmit = vnet_transmit_tap; - net->fdin = fd; - net->fdout = fd; - net->input_processed = 1; + vnet->fdin = fd; + vnet->fdout = fd; + vnet->input_processed = 1; - return net; + memcpy(vnet->eth.mac, (uint8_t[]){0x80, 0x2b, 0xf9, 0x3b, 0x6c, 0xca}, + sizeof(vnet->eth.mac)); + + return vnet; } diff --git a/shell.c b/shell.c index 826fc0d..4faade0 100644 --- a/shell.c +++ b/shell.c @@ -2892,9 +2892,9 @@ cmd_net_add_device(struct shell_ctx *ctx, int argc, char **argv) { fputs(usage, ctx->fout); return; } - struct vnet *net = vnet_init(VNET_TAP); // TODO: list like block devices + struct vnet *vnet = vnet_init(VNET_TAP); // TODO: list like block devices COVERAGE_ON(); - int32_t dev_num = kos_net_add_device(&net->netdev); + int32_t dev_num = kos_net_add_device(&vnet->eth.net); COVERAGE_OFF(); fprintf(ctx->fout, "device number: %" PRIi32 "\n", dev_num); } diff --git a/umka.h b/umka.h index 6d5290f..a2a0e86 100644 --- a/umka.h +++ b/umka.h @@ -22,8 +22,6 @@ #ifndef _WIN32 #include // for irq0: siginfo_t #else -//typedef int32_t ssize_t; -//typedef int64_t off_t; typedef void siginfo_t; #endif @@ -41,6 +39,8 @@ struct umka_ctx { #define KEYBOARD_MODE_ASCII 0 #define KEYBOARD_MODE_SCANCODES 1 +#define UMKA_IRQ_BASE 0x20 // skip CPU exceptions +#define UMKA_SIGNAL_IRQ SIGSYS #define UMKA_IRQ_MOUSE 14 #define UMKA_IRQ_NETWORK 15 @@ -451,41 +451,21 @@ typedef struct { // Protocol family #define AF_INET4 AF_INET -/* -struct sockaddr_in { - uint16_t sin_family; // sa_family_t - uint16_t sin_port; // in_port_t - uint32_t sin_addr; // struct in_addr - uint8_t sin_zero[8]; // zero -}; - -struct addrinfo { - uint32_t ai_flags; // bitmask of AI_* - uint32_t ai_family; // PF_* - uint32_t ai_socktype; // SOCK_* - uint32_t ai_protocol; // 0 or IPPROTO_* - uint32_t ai_addrlen; // length of ai_addr - uint32_t ai_canonname; // char* - uint32_t ai_addr; // struct sockaddr* - uint32_t ai_next; // struct addrinfo* -}; -*/ - -typedef struct net_device_t net_device_t; +struct net_device; #define NET_BUFFER_SIZE 0x800 typedef struct { void *next; // pointer to next frame in list void *prev; // pointer to previous frame in list - net_device_t *device; // ptr to NET_DEVICE structure + struct net_device *device; // ptr to NET_DEVICE structure uint32_t type; // encapsulation type: e.g. Ethernet size_t length; // size of encapsulated data size_t offset; // offset to actual data (24 bytes for default frame) uint8_t data[]; } net_buff_t; -struct net_device_t { +struct net_device { uint32_t device_type; // type field uint32_t mtu; // Maximal Transmission Unit char *name; // ptr to 0 terminated string @@ -495,17 +475,28 @@ struct net_device_t { STDCALL void (*reset) (void); STDCALL int (*transmit) (net_buff_t *); - uint64_t bytes_tx; // statistics, updated by the driver - uint64_t bytes_rx; - uint32_t packets_tx; - uint32_t packets_rx; - uint32_t link_state; // link state (0 = no link) uint32_t hwacc; // bitmask stating enabled HW accelerations (offload // engines) - uint8_t mac[6]; + uint64_t bytes_tx; // statistics, updated by the driver + uint64_t bytes_rx; + + uint32_t packets_tx; + uint32_t packets_tx_err; + uint32_t packets_tx_drop; + uint32_t packets_tx_ovr; + + uint32_t packets_rx; + uint32_t packets_rx_err; + uint32_t packets_rx_drop; + uint32_t packets_rx_ovr; }; // NET_DEVICE +struct eth_device { + struct net_device net; + uint8_t mac[6]; +}; + typedef struct { uint32_t ip; uint8_t mac[6]; @@ -853,7 +844,7 @@ umka_stack_init() { } static inline int32_t -kos_net_add_device(net_device_t *dev) { +kos_net_add_device(struct net_device *dev) { int32_t dev_num; __asm__ __inline__ __volatile__ ( "call net_add_device" diff --git a/umka_os.c b/umka_os.c index df5a145..8b00d54 100644 --- a/umka_os.c +++ b/umka_os.c @@ -167,21 +167,13 @@ handle_i40(int signo, siginfo_t *info, void *context) { } static void -handle_irq_net(int signo, siginfo_t *info, void *context) { +hw_int(int signo) { (void)signo; - (void)info; - (void)context; - kos_irq_serv_irq10(); -} - -static void -hw_int(int signo, siginfo_t *info, void *context) { - (void)signo; - (void)context; - struct idt_entry *e = kos_idts + info->si_value.sival_int + 0x20; - void (*handler)(void) = (void(*)(void)) (((uintptr_t)e->addr_hi << 16) - + e->addr_lo); - handler(); + size_t irq = atomic_load_explicit(&umka_irq_number, memory_order_acquire); + struct idt_entry *e = kos_idts + UMKA_IRQ_BASE + irq; + uintptr_t handler_addr = ((uintptr_t)e->addr_hi << 16) + e->addr_lo; + void (*irq_handler)(void) = (void(*)(void)) handler_addr; + irq_handler(); umka_sti(); } @@ -332,6 +324,14 @@ main(int argc, char *argv[]) { } } + if (startupfile) { + fstartup = fopen(startupfile, "r"); + if (!fstartup) { + fprintf(stderr, "[!] can't open file for reading: %s\n", + startupfile); + exit(1); + } + } if (infile) { fin = fopen(infile, "r"); if (!fin) { @@ -349,49 +349,41 @@ main(int argc, char *argv[]) { if (boardlogfile) { fboardlog = fopen(boardlogfile, "w"); if (!fboardlog) { - fprintf(stderr, "[!] can't open file for writing: %s\n", outfile); + fprintf(stderr, "[!] can't open file for writing: %s\n", + boardlogfile); exit(1); } } else { fboardlog = fout; } - os = umka_os_init(fin, fout, fboardlog); + os = umka_os_init(fstartup, fout, fboardlog); struct sigaction sa; sa.sa_sigaction = irq0; sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; + sa.sa_flags = SA_SIGINFO | SA_RESTART; if (sigaction(SIGALRM, &sa, NULL) == -1) { - fprintf(stderr, "Can't install SIGALRM handler!\n"); + fprintf(stderr, "Can't install timer interrupt handler!\n"); return 1; } sa.sa_sigaction = handle_i40; sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; + sa.sa_flags = SA_SIGINFO | SA_RESTART; if (sigaction(SIGSEGV, &sa, NULL) == -1) { - fprintf(stderr, "Can't install SIGSEGV handler!\n"); + fprintf(stderr, "Can't install 0x40 interrupt handler!\n"); return 1; } - sa.sa_sigaction = handle_irq_net; + sa.sa_handler = hw_int; sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; + sa.sa_flags = SA_RESTART; - if (sigaction(SIGUSR1, &sa, NULL) == -1) { - fprintf(stderr, "Can't install SIGUSR1 handler!\n"); - return 1; - } - - sa.sa_sigaction = hw_int; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - - if (sigaction(SIGSYS, &sa, NULL) == -1) { - fprintf(stderr, "Can't install SIGSYS handler!\n"); + if (sigaction(UMKA_SIGNAL_IRQ, &sa, NULL) == -1) { + fprintf(stderr, "Can't install hardware interrupt handler!\n"); return 1; } @@ -408,16 +400,16 @@ main(int argc, char *argv[]) { kos_boot.pitch = UMKA_DEFAULT_DISPLAY_WIDTH * UMKA_DEFAULT_DISPLAY_BPP / 8; run_test(os->shell); - os->shell->fin = stdin; + os->shell->fin = fin; umka_stack_init(); // load_app_host("../apps/board_cycle", app); load_app_host("../apps/readdir", app); // load_app("/rd/1/loader"); - struct vnet *net = vnet_init(VNET_TAP); - if (net) { - kos_net_add_device(&net->netdev); + struct vnet *vnet = vnet_init(VNET_TAP); + if (vnet) { + kos_net_add_device(&vnet->eth.net); } else { fprintf(stderr, "[!] can't initialize vnet device\n"); } @@ -427,36 +419,34 @@ main(int argc, char *argv[]) { umka_sys_net_dev_reset(i); umka_sys_net_get_dev_name(i, devname); uint32_t devtype = umka_sys_net_get_dev_type(i); - fprintf(stderr, "[net_drv] device %i: %s %u\n", i, devname, devtype); + fprintf(stderr, "[!] device %i: %s %u\n", i, devname, devtype); } -/* // network setup should be done from the userspace app, e.g. via zeroconf f76ret_t r76; r76 = umka_sys_net_ipv4_set_subnet(1, inet_addr("255.255.255.0")); if (r76.eax == (uint32_t)-1) { - fprintf(stderr, "[net_drv] set subnet error\n"); - return -1; + fprintf(stderr, "[!] set subnet error\n"); +// return -1; } r76 = umka_sys_net_ipv4_set_gw(1, inet_addr("10.50.0.1")); if (r76.eax == (uint32_t)-1) { - fprintf(stderr, "set gw error\n"); - return -1; + fprintf(stderr, "[!] set gw error\n"); +// return -1; } - r76 = umka_sys_net_ipv4_set_dns(1, inet_addr("217.10.36.5")); + r76 = umka_sys_net_ipv4_set_dns(1, inet_addr("192.168.1.1")); if (r76.eax == (uint32_t)-1) { - fprintf(stderr, "[net_drv] set dns error\n"); - return -1; + fprintf(stderr, "[!] set dns error\n"); +// return -1; } r76 = umka_sys_net_ipv4_set_addr(1, inet_addr("10.50.0.2")); if (r76.eax == (uint32_t)-1) { - fprintf(stderr, "[net_drv] set ip addr error\n"); - return -1; + fprintf(stderr, "[!] set ip addr error\n"); +// return -1; } -*/ kos_attach_int_handler(UMKA_IRQ_MOUSE, hw_int_mouse, NULL); diff --git a/vnet.c b/vnet.c index da4e6a4..6ca6882 100644 --- a/vnet.c +++ b/vnet.c @@ -14,6 +14,7 @@ #include #define _POSIX // to have SIGSYS on windows #include +#include #include #include #include @@ -38,8 +39,8 @@ static int vnet_input(void *udata) { umka_sti(); - struct vnet *net = udata; - int fd = net->fdin; + struct vnet *vnet = udata; + int fd = vnet->fdin; int plen = 0; fprintf(stderr, "[vnet] input interrupt\n"); net_buff_t *buf = kos_net_buff_alloc(NET_BUFFER_SIZE); @@ -47,11 +48,12 @@ vnet_input(void *udata) { fprintf(stderr, "[vnet] Can't allocate network buffer!\n"); return 1; } - buf->device = &net->netdev; + buf->device = &vnet->eth.net; plen = read(fd, buf->data, NET_BUFFER_SIZE - offsetof(net_buff_t, data)); if (plen == -1) { plen = 0; // we have just allocated a buffer, so we have to submit it } +//if (plen != 0) fprintf(stderr, "[vnet] read %i bytes\n", plen); for (int i = 0; i < plen; i++) { fprintf(stderr, " %2.2x", buf->data[i]); @@ -61,7 +63,7 @@ vnet_input(void *udata) { buf->length = plen; buf->offset = offsetof(net_buff_t, data); kos_eth_input(buf); - net->input_processed = 1; + vnet->input_processed = 1; return 1; // acknowledge our interrupt } @@ -73,8 +75,9 @@ vnet_input_monitor(struct vnet *net) { while (1) { if (net->input_processed && poll(&pfd, 1, 0)) { net->input_processed = 0; - umka_irq_number = UMKA_IRQ_NETWORK; - raise(SIGSYS); + atomic_store_explicit(&umka_irq_number, UMKA_IRQ_NETWORK, + memory_order_release); + raise(UMKA_SIGNAL_IRQ); umka_sti(); } } @@ -83,41 +86,47 @@ vnet_input_monitor(struct vnet *net) { struct vnet * vnet_init(enum vnet_type type) { // printf("vnet_init\n"); - struct vnet *net; + struct vnet *vnet; switch (type) { case VNET_FILE: - net = vnet_init_file(); + vnet = vnet_init_file(); break; case VNET_TAP: - net = vnet_init_tap(); + vnet = vnet_init_tap(); break; default: fprintf(stderr, "[vnet] bad vnet type: %d\n", type); return NULL; } - if (!net) { + if (!vnet) { fprintf(stderr, "[vnet] device initialization failed\n"); return NULL; } - net->netdev.bytes_tx = 0; - net->netdev.bytes_rx = 0; - net->netdev.packets_tx = 0; - net->netdev.packets_rx = 0; + vnet->eth.net.link_state = ETH_LINK_FD + ETH_LINK_10M; + vnet->eth.net.hwacc = 0; - net->netdev.link_state = ETH_LINK_FD + ETH_LINK_10M; - net->netdev.hwacc = 0; - memcpy(net->netdev.mac, &(uint8_t[6]){0x80, 0x2b, 0xf9, 0x3b, 0x6c, 0xca}, - sizeof(net->netdev.mac)); + vnet->eth.net.bytes_tx = 0; + vnet->eth.net.bytes_rx = 0; - kos_attach_int_handler(UMKA_IRQ_NETWORK, vnet_input, net); + vnet->eth.net.packets_tx = 0; + vnet->eth.net.packets_tx_err = 0; + vnet->eth.net.packets_tx_drop = 0; + vnet->eth.net.packets_tx_ovr = 0; + + vnet->eth.net.packets_rx = 0; + vnet->eth.net.packets_rx_err = 0; + vnet->eth.net.packets_rx_drop = 0; + vnet->eth.net.packets_rx_ovr = 0; + + kos_attach_int_handler(UMKA_IRQ_NETWORK, vnet_input, vnet); fprintf(stderr, "[vnet] start input_monitor thread\n"); uint8_t *stack = malloc(STACK_SIZE); size_t tid = umka_new_sys_threads(0, vnet_input_monitor, stack + STACK_SIZE); appdata_t *t = kos_slot_base + tid; - *(void**)((uint8_t*)t->saved_esp0-12) = net; // param for monitor thread + *(void**)((uint8_t*)t->saved_esp0-12) = vnet; // param for monitor thread // -12 here because in UMKa, unlike real hardware, we don't switch between // kernel and userspace, i.e. stack structure is different - return net; + return vnet; } diff --git a/vnet.h b/vnet.h index 5bca9f5..774d72a 100644 --- a/vnet.h +++ b/vnet.h @@ -22,7 +22,7 @@ enum vnet_type { }; struct vnet { - net_device_t netdev; + struct eth_device eth; int fdin; int fdout; int input_processed; diff --git a/vnet/file.c b/vnet/file.c index e714d81..635df84 100644 --- a/vnet/file.c +++ b/vnet/file.c @@ -7,9 +7,88 @@ Copyright (C) 2023 Ivan Baravy */ -#include +#include +#include +#include +#include + +#include "trace.h" +#include "umka.h" +#include "vnet.h" + +static STDCALL void +vnet_unload_file() { + printf("vnet_unload_file\n"); + COVERAGE_ON(); + COVERAGE_OFF(); +} + +static STDCALL void +vnet_reset_file() { + printf("vnet_reset_file\n"); + COVERAGE_ON(); + COVERAGE_OFF(); +} + +static void +dump_net_buff(net_buff_t *buf) { + for (size_t i = 0; i < buf->length; i++) { + printf("%2.2x ", buf->data[i]); + } + putchar('\n'); +} + +static STDCALL int +vnet_transmit_file(net_buff_t *buf) { + struct vnet *net; + __asm__ __inline__ __volatile__ ( + "" + : "=b"(net) + : + : "memory"); + + printf("vnet_transmit: %d bytes\n", buf->length); + dump_net_buff(buf); + write(net->fdout, buf->data, buf->length); + buf->length = 0; + COVERAGE_OFF(); + COVERAGE_ON(); + printf("vnet_transmit: done\n"); + return 0; +} struct vnet * vnet_init_file() { - return NULL; + int fdin; + int fdout; + + if( (fdin = open("/path/to/fdin", O_RDONLY | O_NONBLOCK)) < 0 ) { + perror("[vnet_file] can't open input file"); + return NULL; + } + + if( (fdout = open("/path/to/fdin", O_WRONLY | O_NONBLOCK)) < 0 ) { + perror("[vnet_file] can't open output file"); + return NULL; + } + + struct vnet *vnet = malloc(sizeof(struct vnet)); + vnet->eth.net.device_type = NET_TYPE_ETH; + vnet->eth.net.mtu = 1514; + char *devname = malloc(8); + sprintf(devname, "UMKFIL%d", 0); // FIXME: support more devices + vnet->eth.net.name = devname; + + vnet->eth.net.unload = vnet_unload_file; + vnet->eth.net.reset = vnet_reset_file; + vnet->eth.net.transmit = vnet_transmit_file; + + vnet->fdin = fdin; + vnet->fdout = fdout; + vnet->input_processed = 1; + + memcpy(vnet->eth.mac, (uint8_t[]){0x80, 0x2b, 0xf9, 0x3b, 0x6c, 0xca}, + sizeof(vnet->eth.mac)); + + return vnet; }