Add half-assed support for IRQ chaining.

We only support 4 total chain entries at the moment, but that can be
"easily expanded"... We don't really have a lite dynamic vector, just
the big fat dynamic lists, so improving on this needs some extra effort.

This commit also drags in a bunch of random network work by necessity.
This commit is contained in:
Kevin Lange 2015-05-18 21:07:06 -07:00
parent 331e0f0ad1
commit 9a72bfc4cd
9 changed files with 271 additions and 94 deletions

View File

@ -26,12 +26,27 @@ extern void _irq13(void);
extern void _irq14(void);
extern void _irq15(void);
static irq_handler_t irq_routines[16] = { NULL };
static irq_handler_chain_t irq_routines[16] = { NULL };
static irq_handler_chain_t irq_routines_a[16] = { NULL };
static irq_handler_chain_t irq_routines_b[16] = { NULL };
static irq_handler_chain_t irq_routines_c[16] = { NULL };
/*
* Install an interupt handler for a hardware device.
*/
void irq_install_handler(size_t irq, irq_handler_t handler) {
void irq_install_handler(size_t irq, irq_handler_chain_t handler) {
if (irq_routines[irq]) {
if (irq_routines_a[irq]) {
if (irq_routines_b[irq]) {
irq_routines_c[irq] = handler;
return;
}
irq_routines_b[irq] = handler;
return;
}
irq_routines_a[irq] = handler;
return;
}
irq_routines[irq] = handler;
}
@ -39,16 +54,10 @@ void irq_install_handler(size_t irq, irq_handler_t handler) {
* Remove an interrupt handler for a hardware device.
*/
void irq_uninstall_handler(size_t irq) {
irq_routines[irq] = 0;
}
/*
* Check to see if an interrupt handler is occupied.
*
* The proper solution here would probably be to have shared IRQs.
*/
int irq_is_handler_free(size_t irq) {
return !irq_routines[irq];
irq_routines[irq] = NULL;
irq_routines_a[irq] = NULL;
irq_routines_b[irq] = NULL;
irq_routines_c[irq] = NULL;
}
/*
@ -104,17 +113,16 @@ void irq_ack(size_t irq_no) {
void irq_handler(struct regs *r) {
IRQ_OFF;
void (*handler)(struct regs *r);
if (r->int_no > 47 || r->int_no < 32) {
handler = NULL;
} else {
handler = irq_routines[r->int_no - 32];
}
if (handler) {
handler(r);
} else {
irq_ack(r->int_no - 32);
IRQ_RES;
return;
}
if (irq_routines [r->int_no - 32] && irq_routines [r->int_no - 32](r)) goto _done;
if (irq_routines_a[r->int_no - 32] && irq_routines_a[r->int_no - 32](r)) goto _done;
if (irq_routines_b[r->int_no - 32] && irq_routines_b[r->int_no - 32](r)) goto _done;
if (irq_routines_c[r->int_no - 32] && irq_routines_c[r->int_no - 32](r)) goto _done;
irq_ack(r->int_no - 32);
_done:
IRQ_RES;
}

View File

@ -50,10 +50,7 @@ static int behind = 0;
/*
* IRQ handler for when the timer fires
*/
void
timer_handler(
struct regs *r
) {
int timer_handler(struct regs *r) {
if (++timer_subticks == SUBTICKS_PER_TICK || (behind && ++timer_subticks == SUBTICKS_PER_TICK)) {
timer_ticks++;
timer_subticks = 0;
@ -68,6 +65,7 @@ timer_handler(
wakeup_sleepers(timer_ticks, timer_subticks);
switch_task(1);
return 1;
}
void relative_time(unsigned long seconds, unsigned long subseconds, unsigned long * out_seconds, unsigned long * out_subseconds) {

View File

@ -96,6 +96,7 @@ struct regs {
typedef struct regs regs_t;
typedef void (*irq_handler_t) (struct regs *);
typedef int (*irq_handler_chain_t) (struct regs *);
/* Panic */
#define HALT_AND_CATCH_FIRE(mesg, regs) halt_and_catch_fire(mesg, __FILE__, __LINE__, regs)
@ -110,7 +111,7 @@ extern void isrs_uninstall_handler(size_t isrs);
/* Interrupt Handlers */
extern void irq_install(void);
extern void irq_install_handler(size_t irq, irq_handler_t);
extern void irq_install_handler(size_t irq, irq_handler_chain_t);
extern void irq_uninstall_handler(size_t irq);
extern int irq_is_handler_free(size_t irq);
extern void irq_gates(void);

View File

@ -135,7 +135,7 @@ DEFINE_SHELL_FUNCTION(ac97_status, "[debug] AC'97 status values") {
}
#define DIVISION 128
static void irq_handler(struct regs * regs) {
static int irq_handler(struct regs * regs) {
uint16_t sr = inports(_device.nabmbar + AC97_PO_SR);
if (sr & AC97_X_SR_LVBCI) {
outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_LVBCI);
@ -150,9 +150,12 @@ static void irq_handler(struct regs * regs) {
outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_BCIS);
} else if (sr & AC97_X_SR_FIFOE) {
outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_FIFOE);
} else {
return 0;
}
irq_ack(_device.irq);
return 1;
}
static int init(void) {
@ -165,10 +168,6 @@ static int init(void) {
_device.nabmbar = pci_read_field(_device.pci_device, AC97_NABMBAR, 2) & ((uint32_t) -1) << 1;
_device.nambar = pci_read_field(_device.pci_device, PCI_BAR0, 4) & ((uint32_t) -1) << 1;
_device.irq = pci_read_field(_device.pci_device, PCI_INTERRUPT_LINE, 1);
if (!irq_is_handler_free(_device.irq)) {
debug_print(ERROR, "AC97 IRQ conflict: IRQ %d already in use", _device.irq);
return 1;
}
irq_install_handler(_device.irq, irq_handler);
/* Enable all matter of interrupts */
outportb(_device.nabmbar + AC97_PO_CR, AC97_X_CR_FEIE | AC97_X_CR_IOCE);

View File

@ -4,9 +4,13 @@
* Copyright (C) 2014 Kevin Lange
*/
#include <module.h>
#include <logging.h>
#include <hashmap.h>
#include <ipv4.h>
#include <printf.h>
static hashmap_t * dns_cache;
uint32_t ip_aton(const char * in) {
char ip[16];
char * c = ip;
@ -106,7 +110,154 @@ uint16_t calculate_tcp_checksum(struct tcp_check_header * p, struct tcp_header *
return ~(sum & 0xFFFF) & 0xFFFF;
}
static struct dirent * readdir_netfs(fs_node_t *node, uint32_t index) {
if (index == 0) {
struct dirent * out = malloc(sizeof(struct dirent));
memset(out, 0x00, sizeof(struct dirent));
out->ino = 0;
strcpy(out->name, ".");
return out;
}
if (index == 1) {
struct dirent * out = malloc(sizeof(struct dirent));
memset(out, 0x00, sizeof(struct dirent));
out->ino = 0;
strcpy(out->name, "..");
return out;
}
index -= 2;
return NULL;
}
size_t print_dns_name(fs_node_t * tty, struct dns_packet * dns, size_t offset) {
uint8_t * bytes = (uint8_t *)dns;
while (1) {
uint8_t c = bytes[offset];
if (c == 0) {
offset++;
return offset;
} else if (c >= 0xC0) {
uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1];
print_dns_name(tty, dns, ref);
offset++;
offset++;
return offset;
} else {
for (int i = 0; i < c; ++i) {
fprintf(tty,"%c",bytes[offset+1+i]);
}
fprintf(tty,".");
offset += c + 1;
}
}
}
static int is_ip(char * name) {
unsigned int dot_count = 0;
unsigned int t = 0;
for (char * c = name; *c != '\0'; ++c) {
if ((*c < '0' || *c > '9') && (*c != '.')) return 0;
if (*c == '.') {
if (t > 255) return 0;
dot_count++;
t = 0;
} else {
t *= 10;
t += *c - '0';
}
if (dot_count == 4) return 0;
}
if (dot_count != 3) return 0;
return 1;
}
static uint32_t socket_read(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) {
/* Sleep until we have something to receive */
return 0;
}
static uint32_t socket_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) {
/* Add the packet to the appropriate interface queue and send it off. */
/* What other things (routing) should we be doing here? Or do we do those somewhere else? */
/* Whatever... */
return 0;
}
uint16_t next_ephemeral_port(void) {
static uint16_t next = 49152;
if (next == 0) {
assert(0 && "All out of ephemeral ports, halting this time.");
}
uint16_t out = next;
next++;
if (next == 0) {
debug_print(WARNING, "Ran out of ephemeral ports - next time I'm going to bail.");
debug_print(WARNING, "You really need to implement a bitmap here.");
}
return out;
}
fs_node_t * socket_ipv4_tcp_create(uint32_t dest, uint16_t target_port, uint16_t source_port) {
/* Okay, first step is to get us added to the table so we can receive syns. */
return NULL;
}
/* TODO: socket_close - TCP close; UDP... just clean us up */
/* TODO: socket_open - idk, whatever */
static fs_node_t * finddir_netfs(fs_node_t * node, char * name) {
/* Should essentially find anything. */
debug_print(WARNING, "Need to look up domain or check if is IP: %s", name);
/* Block until lookup is complete */
if (is_ip(name)) {
debug_print(WARNING, " IP: %x", ip_aton(name));
} else {
if (hashmap_has(dns_cache, name)) {
uint32_t ip = ip_aton(hashmap_get(dns_cache, name));
debug_print(WARNING, " In Cache: %s → %x", name, ip);
} else {
debug_print(WARNING, " Still needs look up.");
}
}
return NULL;
}
static fs_node_t * netfs_create(void) {
fs_node_t * fnode = malloc(sizeof(fs_node_t));
memset(fnode, 0x00, sizeof(fs_node_t));
fnode->inode = 0;
strcpy(fnode->name, "net");
fnode->mask = 0555;
fnode->flags = FS_DIRECTORY;
fnode->readdir = readdir_netfs;
fnode->finddir = finddir_netfs;
fnode->nlink = 1;
return fnode;
}
static int init(void) {
dns_cache = hashmap_create(10);
hashmap_set(dns_cache, "dakko.us", strdup("104.131.140.26"));
/* /dev/net/{domain|ip}/{protocol}/{port} */
vfs_mount("/dev/net", netfs_create());
return 0;
}

View File

@ -34,13 +34,14 @@ static void keyboard_wait(void) {
/*
* Keyboard interrupt callback
*/
static void keyboard_handler(struct regs *r) {
static int keyboard_handler(struct regs *r) {
unsigned char scancode;
keyboard_wait();
scancode = inportb(KEY_DEVICE);
irq_ack(KEY_IRQ);
write_fs(keyboard_pipe, 0, 1, (uint8_t []){scancode});
return 1;
}
/*

View File

@ -70,7 +70,7 @@ static uint8_t mouse_read(void) {
return t;
}
static void mouse_handler(struct regs *r) {
static int mouse_handler(struct regs *r) {
uint8_t status = inportb(MOUSE_STATUS);
while (status & MOUSE_BBIT) {
int8_t mouse_in = inportb(MOUSE_PORT);
@ -78,7 +78,7 @@ static void mouse_handler(struct regs *r) {
switch (mouse_cycle) {
case 0:
mouse_byte[0] = mouse_in;
if (!(mouse_in & MOUSE_V_BIT)) return;
if (!(mouse_in & MOUSE_V_BIT)) {irq_ack(MOUSE_IRQ); return 1; }
++mouse_cycle;
break;
case 1:
@ -136,6 +136,7 @@ finish_packet:
status = inportb(MOUSE_STATUS);
}
irq_ack(MOUSE_IRQ);
return 1;
}
static int ioctl_mouse(fs_node_t * node, int request, void * argp) {

View File

@ -177,8 +177,8 @@ static size_t write_tcp_packet(uint8_t * buffer, uint8_t * payload, size_t paylo
.protocol = IPV4_PROT_TCP,
.checksum = 0, /* fill this in later */
.source = htonl(ip_aton("10.0.2.15")),
.destination = htonl(ip_aton("37.48.83.75")), /* Freenode */
//.destination = htonl(ip_aton("204.28.125.145")), /* Dakko */
//.destination = htonl(ip_aton("185.30.166.35")), /* Freenode */
.destination = htonl(ip_aton("104.131.140.26")), /* Dakko */
//.destination = htonl(ip_aton("192.168.1.145")), /* (host machine) */
//.destination = htonl(ip_aton("107.170.207.248")), /* nyancat.dakko.us */
//.destination = htonl(ip_aton("94.142.241.111")), /* towel (star wars) */
@ -539,50 +539,81 @@ static void rtl_ircd(void * data, char * name) {
}
static fs_node_t * _atty = NULL;
static hashmap_t * _tcp_sockets = NULL;
static hashmap_t * _udp_sockets = NULL;
static void net_handle_tcp(struct tcp_header * tcp, size_t length) {
size_t data_length = length - sizeof(struct tcp_header);
/* Find socket */
if (hashmap_has(_tcp_sockets, (void *)ntohs(tcp->source_port))) {
/* r-next */
if (seq_no != ntohl(tcp->ack_number)) return;
} else {
int flags = ntohs(tcp->flags);
/* r-next */
if (seq_no != ntohl(tcp->ack_number)) return;
if ((flags & TCP_FLAGS_ACK) && !data_length) return;
int flags = ntohs(tcp->flags);
ack_no = ntohl(tcp->seq_number) + data_length;
if ((flags & TCP_FLAGS_ACK) && !data_length) return;
/* XXX socket port verification? */
if (ntohs(tcp->source_port) == 6667) {
ack_no = ntohl(tcp->seq_number) + data_length;
write_fs(irc_socket, 0, data_length, tcp->payload);
/* XXX socket port verification? */
if (ntohs(tcp->source_port) == 6667) {
write_fs(irc_socket, 0, data_length, tcp->payload);
} else if (ntohs(tcp->source_port) == 23) {
write_fs(_atty, 0, data_length, tcp->payload);
} else if (ntohs(tcp->source_port) == 80) {
write_fs(_atty, 0, data_length, tcp->payload);
}
_foo:
{
/* Send ACK */
int my_tx = next_tx_buf();
uint8_t payload[] = { 0 };
size_t packet_size = write_tcp_packet(rtl_tx_buffer[my_tx], payload, 0, (TCP_FLAGS_ACK | DATA_OFFSET_5));
outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]);
outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size);
}
} else if (ntohs(tcp->source_port) == 23) {
write_fs(_atty, 0, data_length, tcp->payload);
} else if (ntohs(tcp->source_port) == 80) {
write_fs(_atty, 0, data_length, tcp->payload);
}
{
/* Send ACK */
int my_tx = next_tx_buf();
uint8_t payload[] = { 0 };
size_t packet_size = write_tcp_packet(rtl_tx_buffer[my_tx], payload, 0, (TCP_FLAGS_ACK | DATA_OFFSET_5));
}
outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]);
outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size);
static void net_handle_udp(struct udp_packet * udp, size_t length) {
size_t data_length = length - sizeof(struct tcp_header);
/* Find socket */
if (hashmap_has(_udp_sockets, (void *)ntohs(udp->source_port))) {
/* Do the thing */
} else {
/* ??? */
}
}
static void net_handle_ipv4(struct ipv4_packet * ipv4) {
struct tcp_header * tcp = (struct tcp_header *)ipv4->payload;
net_handle_tcp(tcp, ntohs(ipv4->length) - sizeof(struct ipv4_packet));
switch (ipv4->protocol) {
case IPV4_PROT_TCP:
net_handle_tcp((struct tcp_header *)ipv4->payload, ntohs(ipv4->length) - sizeof(struct ipv4_packet));
break;
case IPV4_PROT_UDP:
net_handle_udp((struct udp_packet *)ipv4->payload, ntohs(ipv4->length) - sizeof(struct ipv4_packet));
break;
default:
/* XXX */
break;
}
}
@ -605,6 +636,8 @@ static void net_handler(void * data, char * name) {
while (1) {
struct ethernet_packet * eth = net_receive();
if (!eth) continue;
switch (ntohs(eth->type)) {
case ETHERNET_TYPE_IPV4:
net_handle_ipv4((struct ipv4_packet *)eth->payload);
@ -628,30 +661,6 @@ static void net_handler_enqueue(void * buffer) {
spin_unlock(&net_queue_lock);
}
static size_t print_dns_name(fs_node_t * tty, struct dns_packet * dns, size_t offset) {
uint8_t * bytes = (uint8_t *)dns;
while (1) {
uint8_t c = bytes[offset];
if (c == 0) {
offset++;
return offset;
} else if (c >= 0xC0) {
uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1];
print_dns_name(tty, dns, ref);
offset++;
offset++;
return offset;
} else {
for (int i = 0; i < c; ++i) {
fprintf(tty,"%c",bytes[offset+1+i]);
}
fprintf(tty,".");
offset += c + 1;
}
}
}
static void parse_dns_response(fs_node_t * tty, void * last_packet) {
struct ethernet_packet * eth = (struct ethernet_packet *)last_packet;
uint16_t eth_type = ntohs(eth->type);
@ -736,8 +745,11 @@ static void parse_dns_response(fs_node_t * tty, void * last_packet) {
}
}
static void rtl_irq_handler(struct regs *r) {
static int rtl_irq_handler(struct regs *r) {
uint16_t status = inports(rtl_iobase + RTL_PORT_ISR);
if (!status) {
return 0;
}
outports(rtl_iobase + RTL_PORT_ISR, status);
irq_ack(rtl_irq);
@ -760,7 +772,6 @@ static void rtl_irq_handler(struct regs *r) {
if (rx_status & (0x0020 | 0x0010 | 0x0004 | 0x0002)) {
debug_print(WARNING, "rx error :(");
} else {
debug_print(INFO, "net net net");
uint8_t * buf_8 = (uint8_t *)&(buf_start[1]);
last_packet = malloc(rx_size);
@ -789,6 +800,8 @@ static void rtl_irq_handler(struct regs *r) {
dirty_tx++;
if (dirty_tx == 5) dirty_tx = 0;
}
return 1;
}
static void rtl_netd(void * data, char * name) {
@ -798,13 +811,9 @@ static void rtl_netd(void * data, char * name) {
{
fprintf(tty, "Sending DNS query...\n");
uint8_t queries[] = {
//3,'i','r','c',
//8,'f','r','e','e','n','o','d','e',
//3,'n','e','t',
7,'m','o','t','s','u','g','o',
3,'u','c','c',
3,'a','s','n',
2,'a','u',
3,'i','r','c',
8,'f','r','e','e','n','o','d','e',
3,'n','e','t',
0,
0x00, 0x01, /* A */
0x00, 0x01, /* IN */
@ -819,6 +828,9 @@ static void rtl_netd(void * data, char * name) {
sleep_on(rx_wait);
parse_dns_response(tty, last_packet);
#endif
#if 0
{
fprintf(tty, "Sending DNS query...\n");
@ -926,6 +938,7 @@ static void rtl_netd(void * data, char * name) {
create_kernel_tasklet(rtl_ircd, "[ircd]", tty);
_atty = tty;
_tcp_sockets = hashmap_create_int(255);
create_kernel_tasklet(net_handler, "[eth]", tty);
}
@ -1013,6 +1026,7 @@ DEFINE_SHELL_FUNCTION(irc_init, "irc connector") {
memcpy(irc_nick, argv[1], strlen(argv[1])+1);
sprintf(irc_payload, "NICK %s\r\nUSER %s * 0 :%s\r\n", irc_nick, irc_nick, irc_nick);
irc_send(irc_payload);
return 0;
@ -1079,7 +1093,7 @@ DEFINE_SHELL_FUNCTION(http, "Open a prompt to send HTTP commands.") {
while (1) {
fprintf(tty, "http> ");
int c = tty_readline(tty, tmp, 100);
tty_readline(tty, tmp, 100);
if (startswith(tmp, "/quit")) {
break;
@ -1190,6 +1204,8 @@ DEFINE_SHELL_FUNCTION(rtl, "rtl8139 experiments") {
rtl_irq = pci_read_field(rtl_device_pci, PCI_INTERRUPT_LINE, 1);
_irq_found:
rtl_irq = pci_read_field(rtl_device_pci, PCI_INTERRUPT_LINE, 1);
fprintf(tty, "Interrupt Line: %x\n", rtl_irq);
irq_install_handler(rtl_irq, rtl_irq_handler);

View File

@ -50,7 +50,7 @@ static fs_node_t ** pipe_for_port(int port) {
return NULL;
}
static void serial_handler_ac(struct regs *r) {
static int serial_handler_ac(struct regs *r) {
char serial;
int port = 0;
if (inportb(SERIAL_PORT_A+1) & 0x01) {
@ -62,9 +62,10 @@ static void serial_handler_ac(struct regs *r) {
irq_ack(SERIAL_IRQ_AC);
uint8_t buf[] = {convert(serial), 0};
write_fs(*pipe_for_port(port), 0, 1, buf);
return 1;
}
static void serial_handler_bd(struct regs *r) {
static int serial_handler_bd(struct regs *r) {
char serial;
int port = 0;
debug_print(NOTICE, "Received something on secondary port");
@ -77,6 +78,7 @@ static void serial_handler_bd(struct regs *r) {
irq_ack(SERIAL_IRQ_BD);
uint8_t buf[] = {convert(serial), 0};
write_fs(*pipe_for_port(port), 0, 1, buf);
return 1;
}
static void serial_enable(int port) {