Functonal webserver with supporting code changes. WIP COMMIT
[akaros.git] / kern / arch / i386 / ne2k.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * See LICENSE for details.
4  */
5
6 #ifdef __SHARC__
7 #pragma nosharc
8 #endif
9
10 #include <arch/mmu.h>
11 #include <arch/x86.h>
12 #include <arch/smp.h>
13 #include <arch/apic.h>
14 #include <arch/pci.h>
15 #include <arch/ne2k.h>
16
17 #include <ros/memlayout.h>
18
19 #include <atomic.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <trap.h>
23 #include <kmalloc.h>
24
25 #include <pmap.h>
26 #include <timing.h>
27
28 /** @file
29  * @brief NE2K Driver Sketch
30  *
31  * EXPERIMENTAL.
32  *
33  * Rough driver. Appears to work in QEMU. Probably completely broken under heavy load.
34  *
35  * @author Paul Pearce <pearce@eecs.berkeley.edu>
36  *
37  * @todo Everything
38  */
39
40 #define NE2K_RESET_R_ADDR 0x1f
41 #define NE2K_PG0_RW_CR  0x00
42 #define NE2K_PG0_RW_ISR 0x07
43 #define NE2K_PG0_W_IMR  0x0F
44 #define NE2K_PG0_W_PSTRT 0x1
45 #define NE2K_PG0_W_PSTP 0x2
46 #define NE2K_PG0_W_RCR 0xC
47 #define NE2K_PG0_R_RSR 0xC
48 #define NE2K_PG0_R_TSR 0x4
49 #define NE2K_PG0_W_TCR 0xD
50 #define NE2K_PG1_RW_PAR 0x1
51 #define NE2K_PG0_W_RSAR0 0x08
52 #define NE2K_PG0_W_RSAR1 0x09
53 #define NE2K_PG0_W_RBCR0 0x0A
54 #define NE2K_PG0_W_RBCR1 0x0B
55 #define NE2K_PG0_W_TBCR0 0x05
56 #define NE2K_PG0_W_TBCR1 0x06
57 #define NE2K_PG0_W_TPSR  0x04
58 #define NE2K_PG0_W_DCR 0x0E
59 #define NE2K_PG1_RW_CURR 0x07
60 #define NE2K_PG0_RW_BNRY 0x03
61
62 #define NE2K_PAGE_SIZE 256
63
64 #define NE2K_PMEM_START   (16*1024)
65 #define NE2K_PMEM_SIZE    (32*1024)
66 #define NE2K_NUM_PAGES          ((NE2K_PMEM_SIZE - NE2K_PMEM_START) / NE2K_PAGE_SIZE)
67 #define NE2K_NUM_RECV_PAGES     (NE2K_NUM_PAGES / 2)
68 #define NE2K_NUM_SEND_PAGES     (NE2K_NUM_PAGES / 2)
69 #define NE2K_FIRST_RECV_PAGE    (NE2K_PMEM_START / NE2K_PAGE_SIZE)
70 #define NE2K_LAST_RECV_PAGE     NE2K_FIRST_RECV_PAGE + NE2K_NUM_RECV_PAGES
71 #define NE2K_FIRST_SEND_PAGE    NE2K_LAST_RECV_PAGE + 1
72
73
74 extern uint32_t eth_up; // Fix this                               
75 uint32_t ne2k_irq;      // And this
76 uint32_t ne2k_io_base_addr;
77 char device_mac[6];
78
79 void* base_page;
80 uint32_t num_pages = 0;
81
82 extern char *CT(PACKET_HEADER_SIZE + len) (*packet_wrap)(const char *CT(len) data, size_t len);
83 extern int (*send_frame)(const char *CT(len) data, size_t len);
84
85
86 void ne2k_init() {
87         
88         if (ne2k_scan_pci() < 0) return;
89         ne2k_mem_alloc();
90         ne2k_configure_nic();
91         ne2k_read_mac();
92         //ne2k_test_interrupts();
93
94         packet_wrap = &ne2k_packet_wrap;
95         send_frame = &ne2k_send_frame;
96
97         ne2k_setup_interrupts();
98
99         eth_up = 1;
100         
101         return;
102 }
103
104
105 int ne2k_scan_pci() {
106         
107         extern pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
108         extern uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
109
110         cprintf("Searching for NE2000 Network device...");
111
112         for (int i = 0; i < PCI_MAX_BUS; i++)
113                 for (int j = 0; j < PCI_MAX_DEV; j++)
114                         for (int k = 0; k < PCI_MAX_FUNC; k++) {
115                                 uint32_t address;
116                                 uint32_t lbus = i;
117                                 uint32_t ldev = j;
118                                 uint32_t lfunc = k;
119                                 uint32_t lreg = 0; 
120                                 uint32_t result  = 0;
121         
122                                 uint16_t dev_id = pci_dev_map[i][j][k].dev_id;
123                                 uint16_t ven_id = pci_dev_map[i][j][k].ven_id;
124
125                                 // Vender DNE
126                                 if (ven_id == INVALID_VENDOR_ID) 
127                                         continue;
128
129                                 // Ignore non RealTek 8168 Devices
130                                 if (ven_id != NE2K_VENDOR_ID || dev_id != NE2K_DEV_ID)
131                                         continue;
132                                 cprintf(" found on BUS %x DEV %x\n", i, j);
133
134                                 // Find the IRQ
135                                 ne2k_irq = pci_irq_map[i][j][k];
136                                 ne2k_debug("-->IRQ: %u\n", ne2k_irq);
137
138                                 // Loop over the BARs
139                                 for (int k = 0; k <= 5; k++) {
140                                         lreg = 4 + k;
141                                         address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg << 2); 
142                                 outl(PCI_CONFIG_ADDR, address);
143                                 result = inl(PCI_CONFIG_DATA);
144                                         
145                                         if (result == 0) // (0 denotes no valid data)
146                                                 continue;
147
148                                         // Read the bottom bit of the BAR. 
149                                         if (result & PCI_BAR_IO_MASK) {
150                                                 result = result & PCI_IO_MASK;
151                                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
152                                         } else {
153                                                 result = result & PCI_MEM_MASK;
154                                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
155                                         }
156                         
157                                         // TODO Switch to memory mapped instead of IO?
158                                         if (k == 0) // BAR0 denotes the IO Addr for the device
159                                                 ne2k_io_base_addr = result;                                             
160                                 }
161                                 
162                 return 0;
163         }
164         cprintf(" not found. No device configured.\n");
165         
166         return -1;
167 }
168
169 void ne2k_configure_nic() {
170         
171         ne2k_debug("-->Configuring Device.\n");
172         
173         // Reset. Yes reading from this addr resets it
174         inb(ne2k_io_base_addr + NE2K_RESET_R_ADDR);
175
176         // Configure
177         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x22);
178         outb(ne2k_io_base_addr + NE2K_PG0_W_PSTRT,  NE2K_FIRST_RECV_PAGE);
179         outb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY, NE2K_FIRST_RECV_PAGE + 1);
180
181         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (0x22 & 0x3F) | 0x40);
182         outb(ne2k_io_base_addr + NE2K_PG1_RW_CURR, NE2K_FIRST_RECV_PAGE + 2);
183         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0x22);
184         outb(ne2k_io_base_addr + NE2K_PG0_W_PSTP, NE2K_LAST_RECV_PAGE);
185         outb(ne2k_io_base_addr + NE2K_PG0_W_DCR, 0x94); 
186         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x22);
187         
188         outb(ne2k_io_base_addr + NE2K_PG0_W_RCR,  0xDF);
189         outb(ne2k_io_base_addr + NE2K_PG0_W_TCR,  0xE0);
190         
191
192         //uint8_t isr = inb(ne2k_io_base_addr + 0x07);
193         //cprintf("isr: %x\n", isr);
194
195         
196         return;
197 }
198
199 void ne2k_setup_interrupts() {
200         
201         extern handler_t interrupt_handlers[];
202         
203         ne2k_debug("-->Setting interrupts.\n");
204         
205         // Kernel based interrupt stuff
206         register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + ne2k_irq, ne2k_interrupt_handler, (void *)0);
207         
208         ioapic_route_irq(ne2k_irq, 6);  
209         
210         outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR, 0xFF);
211         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0xFF);
212         
213         return;
214 }
215
216 void ne2k_mem_alloc() {
217         
218         num_pages = ROUNDUP(NE2K_NUM_PAGES * NE2K_PAGE_SIZE, PGSIZE) / PGSIZE;
219         base_page = get_cont_pages(LOG2_UP(num_pages), 0);      
220 }
221
222 void ne2k_read_mac() {
223
224         uint8_t cr = inb(ne2k_io_base_addr + NE2K_PG0_RW_CR);
225         
226         // Set correct bits
227         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0xA);
228         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
229         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, 0x0);
230         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, 0x6);
231         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, 0x0);
232
233
234         for (int i = 0; i < 6; i++)
235                 device_mac[i] = inb(ne2k_io_base_addr + 0x10) & inb(ne2k_io_base_addr + 0x10);
236
237         // Set page 1
238         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (cr & 0x3F) | 0x40);
239
240         for (int i = 0; i < 6; i++) 
241            outb(ne2k_io_base_addr + NE2K_PG1_RW_PAR + i, device_mac[i]);
242
243         
244         ne2k_debug("-->DEVICE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & device_mac[0], 0xFF & device_mac[1],        
245                                                                     0xFF & device_mac[2], 0xFF & device_mac[3], 
246                                                                 0xFF & device_mac[4], 0xFF & device_mac[5]);
247         // Restore old setting.
248         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, cr);
249         return;
250 }
251
252 void ne2k_test_interrupts() {
253         
254         cprintf("Generating Interrupt...\n");
255         outb(ne2k_io_base_addr + 0x0A, 0x00);
256         outb(ne2k_io_base_addr + 0x0B, 0x00);
257         outb(ne2k_io_base_addr + 0x00, 0x0A);
258         udelay(10000000);
259
260         cprintf("Generating Interrupt again...\n");
261         outb(ne2k_io_base_addr + 0x0A, 0x00);
262         outb(ne2k_io_base_addr + 0x0B, 0x00);
263         outb(ne2k_io_base_addr + 0x00, 0x0A);
264         udelay(10000000);
265         
266 }
267
268 // We need to evaluate this routine in terms of concurrency.
269 // We also need to figure out whats up with different core interrupts
270 void ne2k_interrupt_handler(trapframe_t *tf, void* data) {
271         
272         ne2k_interrupt_debug("\nNE2K interrupt on core %u!\n", lapic_get_id());
273         uint8_t isr= inb(ne2k_io_base_addr + 0x07);
274         ne2k_interrupt_debug("isr: %x\n", isr);
275         
276         if (isr & 0x1) {
277                 ne2k_interrupt_debug("-->Packet received.\n");
278                 ne2k_handle_rx_packet();
279         }
280
281
282         outb(ne2k_io_base_addr + 0x07, isr);
283         //ne2k_handle_rx_packet();
284         return;                         
285 }
286
287 // @TODO: Is this broken? Didn't change it after kmalloc changed
288 void ne2k_handle_rx_packet() {
289
290         uint8_t bound = inb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY);
291
292         uint8_t cr = inb(ne2k_io_base_addr + NE2K_PG0_RW_CR);
293         // Set page 1
294         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (cr & 0x3F) | 0x40);
295
296         uint8_t next = inb(ne2k_io_base_addr + NE2K_PG1_RW_CURR);
297
298         // Restore old setting.
299         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, cr);
300
301         uint8_t start = NE2K_FIRST_RECV_PAGE;
302         uint8_t stop = NE2K_LAST_RECV_PAGE;
303
304         // Broken mult packets?
305         if (((bound + 1) == next) || (((bound + 1) == stop) && (start == next))) {
306                 return;
307         }
308
309         uint32_t kmalloc_size;
310
311         if (MAX_FRAME_SIZE % NE2K_PAGE_SIZE) {
312                 kmalloc_size = ((MAX_FRAME_SIZE / NE2K_PAGE_SIZE) + 1) * NE2K_PAGE_SIZE;
313         } else {
314                 kmalloc_size = MAX_FRAME_SIZE;
315         }
316         
317         char *rx_buffer = kmalloc(kmalloc_size, 0);
318         
319         if (rx_buffer == NULL) panic ("Can't allocate page for incoming packet.");
320
321         uint8_t curr = bound + 1;
322
323 //cprintf("reading from: %x\n", curr);
324
325         uint8_t header[4];
326         uint16_t packet_len = 0xFFFF;
327         uint16_t page_count = 0;
328         for (int i = 0; i < (MAX_FRAME_SIZE / NE2K_PAGE_SIZE); i++) {
329                 if (curr == stop)
330                         curr = start;                   
331
332                 outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
333                 outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, curr);
334
335
336                 // Fix this. Its hard coded to 256
337                 outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, 0);
338                 outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, 0x1);
339         
340
341                 outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0x0A);
342
343                 for (int j = 0; j < NE2K_PAGE_SIZE; j++) {
344                         uint8_t val = inb(ne2k_io_base_addr + 0x10);
345                         if ((i == 0) && (j < 4)) {
346 //                              cprintf("header %u %x\n", j, (uint8_t)val);
347                                 header[j] = val;
348                         } 
349                         rx_buffer[i*NE2K_PAGE_SIZE + j] = val;
350                 }
351
352
353                 if (i == 0) {
354                         packet_len = ((uint16_t)header[3] << 8) | (uint16_t)header[2];
355 //              cprintf("header 2 %u header 3 %u header 3 shifted %u\n", (uint16_t)header[2], (uint16_t)header[3], (uint16_t)header[3] << 8);
356 //              cprintf("packet len: %u\n", packet_len);
357                         if (packet_len % NE2K_PAGE_SIZE) {
358                                 page_count = (packet_len / NE2K_PAGE_SIZE) + 1;
359                         } else {
360                                 page_count = (packet_len / NE2K_PAGE_SIZE);
361                         }
362                 }
363                 
364                 if ((i + 1) == page_count)
365                         break;
366
367                 curr++;
368
369                 
370         }
371 //cprintf("last page: %x\n", curr);
372         outb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY, curr);
373         
374
375         // Hack for UDP syscall hack. 
376         // This is a quick hack to let us deal with where to put packets coming in. This is not concurrency friendly
377         // In the event that we get 2 incoming frames for our syscall test (shouldnt happen)
378         // We cant process more until another packet comes in. This is ugly, but this code goes away as soon as we integrate a real stack.
379         // This keys off the source port, fix it for dest port. 
380         // Also this may access packet regions that are wrong. If someone addresses empty packet for our interface
381         // and the bits that happened to be in memory before are the right port, this will trigger. this is bad
382         // but since syscalls are a hack for only 1 machine connected, we dont care for now.
383         
384         if (*((uint16_t*)(rx_buffer + 40)) == 0x9bad) {
385                 
386
387                 extern int packet_waiting;      
388                 extern int packet_buffer_size;
389                 extern int packet_buffer_pos;
390                 extern char* packet_buffer;
391                 extern char* packet_buffer_orig;
392
393 #if 0
394                 if (packet_waiting) return;
395                 
396                 // So ugly I want to cry
397                 packet_buffer_size = *((uint16_t*)(rx_buffer + 42)); 
398                 packet_buffer_size = (((uint16_t)packet_buffer_size & 0xff00) >> 8) |  (((uint16_t)packet_buffer_size & 0x00ff) << 8);          
399                 packet_buffer_size = packet_buffer_size - 8;    
400
401                 packet_buffer = rx_buffer + PACKET_HEADER_SIZE + 4;
402
403                 packet_buffer_orig = rx_buffer;
404                 packet_buffer_pos = 0;
405                 
406                 packet_waiting = 1;
407 #endif                          
408                 return;
409         }
410         
411         // END HACKY STUFF
412                 
413         kfree(rx_buffer);
414         
415         return;
416 }
417
418 // copied with love (and modification) from tcp/ip illistrated vl 2 1995 pg 236
419 // bsd licenced
420 uint16_t cksum(char *CT(len) ip, int len) {
421         
422         uint32_t sum = 0;
423         // Next two lines for ivy. Grr.
424         char *curr_ip = ip;
425         int curr_len = len;
426
427         while(curr_len > 1) {
428                 sum += *((uint16_t*) curr_ip);
429                 curr_ip = curr_ip + 2;
430                 
431                 if(sum & 0x80000000)    /* if high order bit set, fold */
432                         sum = (sum & 0xFFFF) + (sum >> 16);
433                         curr_len -= 2;
434                 }
435
436                 if(curr_len)             /* take care of left over byte */
437                         sum += *curr_ip;
438                   
439                 while(sum>>16)
440                         sum = (sum & 0xFFFF) + (sum >> 16);
441
442                 return ~sum;
443 }
444
445
446 // Main routine to send a frame. May be completely broken.
447 int ne2k_send_frame(const char *data, size_t len) {
448
449         if (data == NULL)
450                 return -1;
451         if (len == 0)
452                 return 0;
453
454
455         if (len > MAX_FRAME_SIZE) {
456                 ne2k_frame_debug("-->Frame Too Large!\n");
457                 return -1;
458         }
459
460         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0x00);
461
462
463         // The TPSR takes a page #
464         // The RSAR takes a byte offset, but since a page is 256 bits
465         // and we are writing on page boundries, the low bits are 0, and
466         // the high bits are a page #
467         outb(ne2k_io_base_addr + NE2K_PG0_W_TPSR, NE2K_FIRST_SEND_PAGE);
468         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
469         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, NE2K_FIRST_SEND_PAGE);
470
471         
472         outb(ne2k_io_base_addr + NE2K_PG0_W_TBCR0, len & 0xFF);
473         outb(ne2k_io_base_addr + NE2K_PG0_W_TBCR1, len >> 8);
474
475         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, len & 0xFF);
476         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, len >> 8);
477
478         
479         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x12);
480         
481
482         for (int i = 0; i<len; i = i + 1) {
483                 outb(ne2k_io_base_addr + 0x10, *(uint8_t*)(data + i));
484                 //printk("sent: %x\n", *(uint8_t*)(data + i));
485         }
486         
487         while(( inb(ne2k_io_base_addr + 0x07) & 0x40) == 0);
488
489         outb(ne2k_io_base_addr + 0x07,  0x40);
490
491         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0xFF);
492
493         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x1E);
494         
495         
496         return len;
497 }
498
499 // This function is a complete hack for syscalls until we get a stack.
500 // the day I delete this monstrosity of code I will be a happy man --Paul
501 char *CT(PACKET_HEADER_SIZE + len) ne2k_packet_wrap(const char* data, size_t len) {
502         
503         #define htons(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
504                             (((uint16_t)(A) & 0x00ff) << 8))
505         #define htonl(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \
506                             (((uint32_t)(A) & 0x00ff0000) >> 8)  | \
507                             (((uint32_t)(A) & 0x0000ff00) << 8)  | \
508                             (((uint32_t)(A) & 0x000000ff) << 24))
509  
510         #define ntohs  htons
511         #define ntohl  htohl
512  
513         if ((len == 0) || (data == NULL))
514                 return NULL;
515  
516         // Hard coded to paul's laptop's mac
517         //Format for Makelocal file: -DUSER_MAC_ADDRESS="{0x00, 0x23, 0x32, 0xd5, 0xae, 0x82}"
518         char dest_mac_address[6] = USER_MAC_ADDRESS;
519         
520         
521         uint32_t source_ip = 0xC0A8000A; // 192.168.0.10
522         uint32_t dest_ip   = 0xC0A8000B; // 192.168.0.11
523   
524         
525         if (len > MAX_PACKET_DATA) {
526                 ne2k_frame_debug("Bad packet size for packet wrapping");
527                 return NULL;
528         }
529         
530         struct eth_packet* wrap_buffer = kmalloc(MAX_PACKET_SIZE, 0);
531         
532         if (wrap_buffer == NULL) {
533                 ne2k_frame_debug("Can't allocate page for packet wrapping");
534                 return NULL;
535         }
536         
537  
538         struct ETH_Header *eth_header = &wrap_buffer->eth_head.eth_head;
539         struct IP_Header *ip_header = &wrap_buffer->eth_head.ip_head;
540         struct UDP_Header *udp_header = &wrap_buffer->eth_head.udp_head;
541         
542         // Setup eth data
543         for (int i = 0; i < 6; i++) 
544                 eth_header->dest_mac[i] = dest_mac_address[i];
545                 
546         for (int i = 0; i < 6; i++) 
547                 eth_header->source_mac[i] = device_mac[i];
548                 
549         eth_header->eth_type = htons(0x0800);
550         
551         // Setup IP data
552         ip_header->ip_opts0 = htonl((4<<28) | (5 << 24) | (len + 28));
553         ip_header->ip_opts1 = 0;
554         //ip_header->ip_opts2 = 0x4f2f110a;
555         ip_header->ip_opts2 = 0x0000110a;
556
557         ip_header->source_ip = htonl(source_ip);
558         ip_header->dest_ip = htonl(dest_ip);
559         
560
561         ip_header->ip_opts2 =   ip_header->ip_opts2 | 
562                                 ((uint32_t)cksum((char*)ip_header, sizeof(struct IP_Header)) << 16);
563         // Setup UDP Data
564         udp_header->source_port = htons(44443);
565         udp_header->dest_port = htons(44444);
566         udp_header->length = htons(8 + len);
567         udp_header->checksum = 0;
568         
569         memcpy (&wrap_buffer->data[0], data, len);
570         
571         return (char *CT(PACKET_HEADER_SIZE + len))wrap_buffer; 
572 }