Added a fillmeup syscall
[akaros.git] / kern / arch / i686 / 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 #define SET_PAGE_0() (inb(ne2k_io_base_addr + NE2K_PG0_RW_CR) & 0x3F)
75
76 uint32_t ne2k_irq;      // Fix this
77 uint32_t ne2k_io_base_addr;
78
79 void* base_page;
80 uint32_t num_pages = 0;
81
82 void ne2k_init() {
83         
84         if (ne2k_scan_pci() < 0) return;
85         ne2k_mem_alloc();
86         ne2k_configure_nic();
87         ne2k_read_mac();
88         printk("Network Card MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", 
89            device_mac[0],device_mac[1],device_mac[2],
90            device_mac[3],device_mac[4],device_mac[5]);
91         //ne2k_test_interrupts();
92         send_frame = &ne2k_send_frame;
93
94         ne2k_setup_interrupts();
95
96         eth_up = 1;
97
98         return;
99 }
100
101
102 int ne2k_scan_pci() {
103         
104         extern pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
105         extern uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
106
107         cprintf("Searching for NE2000 Network device...");
108
109         for (int i = 0; i < PCI_MAX_BUS; i++)
110                 for (int j = 0; j < PCI_MAX_DEV; j++)
111                         for (int k = 0; k < PCI_MAX_FUNC; k++) {
112                                 uint32_t address;
113                                 uint32_t lbus = i;
114                                 uint32_t ldev = j;
115                                 uint32_t lfunc = k;
116                                 uint32_t lreg = 0; 
117                                 uint32_t result  = 0;
118         
119                                 uint16_t dev_id = pci_dev_map[i][j][k].dev_id;
120                                 uint16_t ven_id = pci_dev_map[i][j][k].ven_id;
121
122                                 // Vender DNE
123                                 if (ven_id == INVALID_VENDOR_ID) 
124                                         continue;
125
126                                 // Ignore non RealTek 8168 Devices
127                                 if (ven_id != NE2K_VENDOR_ID || dev_id != NE2K_DEV_ID)
128                                         continue;
129                                 cprintf(" found on BUS %x DEV %x\n", i, j);
130
131                                 // Find the IRQ
132                                 ne2k_irq = pci_irq_map[i][j][k];
133                                 ne2k_debug("-->IRQ: %u\n", ne2k_irq);
134
135                                 // Loop over the BARs
136                                 for (int k = 0; k <= 5; k++) {
137                                         lreg = 4 + k;
138                                         address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg << 2); 
139                                 outl(PCI_CONFIG_ADDR, address);
140                                 result = inl(PCI_CONFIG_DATA);
141                                         
142                                         if (result == 0) // (0 denotes no valid data)
143                                                 continue;
144
145                                         // Read the bottom bit of the BAR. 
146                                         if (result & PCI_BAR_IO_MASK) {
147                                                 result = result & PCI_IO_MASK;
148                                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
149                                         } else {
150                                                 result = result & PCI_MEM_MASK;
151                                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
152                                         }
153                         
154                                         // TODO Switch to memory mapped instead of IO?
155                                         if (k == 0) // BAR0 denotes the IO Addr for the device
156                                                 ne2k_io_base_addr = result;                                             
157                                 }
158                                 
159                 return 0;
160         }
161         cprintf(" not found. No device configured.\n");
162         
163         return -1;
164 }
165
166 void ne2k_configure_nic() {
167         
168         ne2k_debug("-->Configuring Device.\n");
169         
170         // Reset. Yes reading from this addr resets it
171         inb(ne2k_io_base_addr + NE2K_RESET_R_ADDR);
172
173         // Configure
174         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x22);
175         outb(ne2k_io_base_addr + NE2K_PG0_W_PSTRT,  NE2K_FIRST_RECV_PAGE);
176         outb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY, NE2K_FIRST_RECV_PAGE + 1);
177
178         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (0x22 & 0x3F) | 0x40);
179         outb(ne2k_io_base_addr + NE2K_PG1_RW_CURR, NE2K_FIRST_RECV_PAGE + 2);
180         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0x22);
181         outb(ne2k_io_base_addr + NE2K_PG0_W_PSTP, NE2K_LAST_RECV_PAGE);
182         outb(ne2k_io_base_addr + NE2K_PG0_W_DCR, 0x94); 
183         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x22);
184         
185         outb(ne2k_io_base_addr + NE2K_PG0_W_RCR,  0xDF);
186         outb(ne2k_io_base_addr + NE2K_PG0_W_TCR,  0xE0);
187         
188
189         //uint8_t isr = inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR);
190         //cprintf("isr: %x\n", isr);
191
192         
193         return;
194 }
195
196 void ne2k_setup_interrupts() {
197         
198         extern handler_t interrupt_handlers[];
199         
200         ne2k_debug("-->Setting interrupts.\n");
201         
202         // Kernel based interrupt stuff
203         register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + ne2k_irq, ne2k_interrupt_handler, (void *)0);
204         
205 #ifdef __CONFIG_DISABLE_MPTABLES__
206         pic_unmask_irq(ne2k_irq);
207         unmask_lapic_lvt(LAPIC_LVT_LINT0);
208         enable_irq();
209 #else
210         ioapic_route_irq(ne2k_irq, 0);  
211 #endif
212         
213         SET_PAGE_0();
214
215         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0xBF);
216
217         outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR, 0xFF);
218         return;
219 }
220
221 void ne2k_mem_alloc() {
222         
223         num_pages = ROUNDUP(NE2K_NUM_PAGES * NE2K_PAGE_SIZE, PGSIZE) / PGSIZE;
224         base_page = get_cont_pages(LOG2_UP(num_pages), 0);      
225 }
226
227 void ne2k_read_mac() {
228
229         uint8_t cr = inb(ne2k_io_base_addr + NE2K_PG0_RW_CR);
230         
231         // Set correct bits
232         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0xA);
233         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
234         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, 0x0);
235         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, 0x6);
236         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, 0x0);
237
238
239         for (int i = 0; i < 6; i++)
240                 device_mac[i] = inb(ne2k_io_base_addr + 0x10) & inb(ne2k_io_base_addr + 0x10);
241
242         // Set page 1
243         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (cr & 0x3F) | 0x40);
244
245         for (int i = 0; i < 6; i++) 
246            outb(ne2k_io_base_addr + NE2K_PG1_RW_PAR + i, device_mac[i]);
247
248         
249         ne2k_debug("-->DEVICE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & device_mac[0], 0xFF & device_mac[1],        
250                                                                     0xFF & device_mac[2], 0xFF & device_mac[3], 
251                                                                 0xFF & device_mac[4], 0xFF & device_mac[5]);
252         // Restore old setting.
253         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, cr);
254         return;
255 }
256
257 void ne2k_test_interrupts() {
258         
259         cprintf("Generating Interrupt...\n");
260         outb(ne2k_io_base_addr + 0x0A, 0x00);
261         outb(ne2k_io_base_addr + 0x0B, 0x00);
262         outb(ne2k_io_base_addr + 0x00, 0x0A);
263         udelay(10000000);
264
265         cprintf("Generating Interrupt again...\n");
266         outb(ne2k_io_base_addr + 0x0A, 0x00);
267         outb(ne2k_io_base_addr + 0x0B, 0x00);
268         outb(ne2k_io_base_addr + 0x00, 0x0A);
269         udelay(10000000);
270         
271 }
272
273 // We need to evaluate this routine in terms of concurrency.
274 // We also need to figure out whats up with different core interrupts
275 void ne2k_interrupt_handler(trapframe_t *tf, void* data) {
276         
277         ne2k_interrupt_debug("\nNE2K interrupt on core %u!\n", lapic_get_id());
278
279         SET_PAGE_0();
280
281         uint8_t isr= inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR);
282         ne2k_interrupt_debug("isr: %x\n", isr);
283         
284         while (isr != 0x0) {
285
286                 // TODO: Other interrupt cases.
287
288                 if (isr & 0x1) {
289                         ne2k_interrupt_debug("-->Packet received.\n");
290                         ne2k_handle_rx_packet();
291                 }
292                 
293                 SET_PAGE_0();
294
295                 // Clear interrupts
296                 isr = inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR);
297                 outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR, isr);
298
299         }
300
301         ne2k_handle_rx_packet();
302         
303         return;                         
304 }
305
306 // @TODO: Is this broken? Didn't change it after kmalloc changed
307 void ne2k_handle_rx_packet() {
308         
309         SET_PAGE_0();
310
311         uint8_t bound = inb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY);
312
313         uint8_t cr = inb(ne2k_io_base_addr + NE2K_PG0_RW_CR);
314         
315         // Set page 1
316         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (cr & 0x3F) | 0x40);
317
318         uint8_t next = inb(ne2k_io_base_addr + NE2K_PG1_RW_CURR);
319
320         // Restore old setting.
321         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, cr);
322
323         uint8_t start = NE2K_FIRST_RECV_PAGE;
324         uint8_t stop = NE2K_LAST_RECV_PAGE;
325
326         // Broken mult packets?
327         if (((bound + 1) == next) || (((bound + 1) == stop) && (start == next))) {
328                 ne2k_debug("NO PACKET TO PROCESS\n");
329                 return;
330         }
331
332         uint32_t kmalloc_size;
333
334         if (MAX_FRAME_SIZE % NE2K_PAGE_SIZE) {
335                 kmalloc_size = ((MAX_FRAME_SIZE / NE2K_PAGE_SIZE) + 1) * NE2K_PAGE_SIZE;
336         } else {
337                 kmalloc_size = MAX_FRAME_SIZE;
338         }
339         
340         char *rx_buffer = kmalloc(kmalloc_size, 0);
341         
342         if (rx_buffer == NULL) panic ("Can't allocate page for incoming packet.");
343
344         uint8_t curr = bound + 1;
345
346         uint8_t header[4];
347         uint16_t packet_len = 0xFFFF;
348         uint16_t page_count = 0;
349         for (int i = 0, n = 0; i < (MAX_FRAME_SIZE / NE2K_PAGE_SIZE); i++) {
350                 if (curr == stop)
351                         curr = start;                   
352
353                 outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
354                 outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, curr);
355
356
357                 // Fix this. Its hard coded to 256
358                 outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, 0);
359                 outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, 0x1);
360         
361                 outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0x0A);
362
363                 for (int j = 0; j < NE2K_PAGE_SIZE; j++) {
364                         uint8_t val = inb(ne2k_io_base_addr + 0x10);
365                         if ((i == 0) && (j < 4)) {
366                                 header[j] = val;
367                         } else { 
368                                 rx_buffer[n++] = val;
369                         }
370                 }
371
372                 if (i == 0) {
373                         packet_len = ((uint16_t)header[3] << 8) | (uint16_t)header[2];
374                         if (packet_len % NE2K_PAGE_SIZE) {
375                                 page_count = (packet_len / NE2K_PAGE_SIZE) + 1;
376                         } else {
377                                 page_count = (packet_len / NE2K_PAGE_SIZE);
378                         }
379                 }
380                 
381                 if ((i + 1) == page_count)
382                         break;
383
384                 curr++;
385         
386         }
387         outb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY, curr);
388
389         if (packet_len == 0) {
390                 ne2k_debug("Triggered on an empty packet.\n");
391                 return;
392         }
393
394 #ifdef __CONFIG_OSDI__
395         struct packetizer_packet *p = (struct packetizer_packet*)rx_buffer;
396         if(ntohs(p->ethertype) == PACKETIZER_ETH_TYPE) {
397                 assert(fillmeup_data.proc != NULL);
398                 assert(fillmeup_data.bufs != NULL);
399                 struct proc *proc = fillmeup_data.proc;
400
401                 int16_t lw;
402                 memcpy_from_user(proc, &lw, fillmeup_data.last_written, sizeof(lw));
403                 lw = (lw + 1) % (fillmeup_data.num_bufs);
404                 memcpy_to_user(proc, fillmeup_data.last_written, &lw, sizeof(lw));
405                 memcpy_to_user(proc, &fillmeup_data.bufs[PACKETIZER_MAX_PAYLOAD * lw], 
406                                p->payload, ntohl(p->payload_size));
407                 //print_packetizer_packet(p);
408                 proc_notify(fillmeup_data.proc, NE_ETC_ETC_ETC, 0);
409
410                 kfree(rx_buffer);
411                 return;
412         }
413 #endif
414
415 #ifdef __CONFIG_APPSERVER__
416         // Treat as a syscall frontend response packet if eth_type says so
417         // Will eventually go away, so not too worried about elegance here...
418         #include <frontend.h>
419         #include <arch/frontend.h>
420         uint16_t eth_type = htons(*(uint16_t*)(rx_buffer + 12));
421         if(eth_type == APPSERVER_ETH_TYPE) {
422                 handle_appserver_packet(rx_buffer, packet_len);
423                 kfree(rx_buffer);
424                 return;
425         }
426 #endif
427
428         spin_lock(&packet_buffers_lock);
429
430         if (num_packet_buffers >= MAX_PACKET_BUFFERS) {
431                 printk("WARNING: DROPPING PACKET!\n");
432                 spin_unlock(&packet_buffers_lock);
433                 kfree(rx_buffer);
434                 return;
435         }
436
437         packet_buffers[packet_buffers_tail] = rx_buffer;
438         packet_buffers_sizes[packet_buffers_tail] = packet_len;
439
440         packet_buffers_tail = (packet_buffers_tail + 1) % MAX_PACKET_BUFFERS;
441         num_packet_buffers++;
442
443         spin_unlock(&packet_buffers_lock);
444         
445         return;
446 }
447
448 // copied with love (and modification) from tcp/ip illistrated vl 2 1995 pg 236
449 // bsd licenced
450 uint16_t cksum(char *CT(len) ip, int len) {
451         
452         uint32_t sum = 0;
453         // Next two lines for ivy. Grr.
454         char *curr_ip = ip;
455         int curr_len = len;
456
457         while(curr_len > 1) {
458                 sum += *((uint16_t*) curr_ip);
459                 curr_ip = curr_ip + 2;
460                 
461                 if(sum & 0x80000000)    /* if high order bit set, fold */
462                         sum = (sum & 0xFFFF) + (sum >> 16);
463                         curr_len -= 2;
464                 }
465
466                 if(curr_len)             /* take care of left over byte */
467                         sum += *curr_ip;
468                   
469                 while(sum>>16)
470                         sum = (sum & 0xFFFF) + (sum >> 16);
471
472                 return ~sum;
473 }
474
475
476 // Main routine to send a frame. May be completely broken.
477 int ne2k_send_frame(const char *data, size_t len) {
478
479         if (data == NULL)
480                 return -1;
481         if (len == 0)
482                 return 0;
483
484
485         if (len > MAX_FRAME_SIZE) {
486                 ne2k_frame_debug("-->Frame Too Large!\n");
487                 return -1;
488         }
489
490         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0x00);
491
492
493         // The TPSR takes a page #
494         // The RSAR takes a byte offset, but since a page is 256 bits
495         // and we are writing on page boundries, the low bits are 0, and
496         // the high bits are a page #
497         outb(ne2k_io_base_addr + NE2K_PG0_W_TPSR, NE2K_FIRST_SEND_PAGE);
498         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
499         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, NE2K_FIRST_SEND_PAGE);
500
501         
502         outb(ne2k_io_base_addr + NE2K_PG0_W_TBCR0, len & 0xFF);
503         outb(ne2k_io_base_addr + NE2K_PG0_W_TBCR1, len >> 8);
504
505         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, len & 0xFF);
506         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, len >> 8);
507
508         
509         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x12);
510         
511
512         for (int i = 0; i<len; i = i + 1) {
513                 outb(ne2k_io_base_addr + 0x10, *(uint8_t*)(data + i));
514                 //ne2k_debug("sent: %x\n", *(uint8_t*)(data + i));
515         }
516         
517         while(( inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR) & 0x40) == 0);
518
519         outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR,  0x40);
520
521         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0xBF);
522
523         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x1E);
524         
525         
526         return len;
527 }
528