Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Added the NE2K_Send function, which takes several arguments, creates a packet from...
[palacios.git] / palacios / src / geekos / ne2k.c
1 #include <geekos/ne2k.h>
2 #include <geekos/debug.h>
3 #include <geekos/io.h>
4 #include <geekos/irq.h>
5 #include <geekos/malloc.h>
6
7 #define DEBUG 1
8 #define TX_START_BUFF 0x40
9 #define RX_START_BUFF 0x4c
10
11
12 uint_t next = (RX_START_BUFF << 8);
13 static uint_t received = 0;
14 static uint_t send_done = 1;
15
16 static void Dump_Registers()
17 {
18   uint_t data;
19   PrintBoth("Dumping NIC registers for page %x...\n", (In_Byte(NE2K_CR) & 0xc0) >> 6);
20   uint_t i = 0;
21   for(i = 0; i <= 0x0f; i += 0x01) {
22     data = In_Byte(NE2K_BASE_ADDR+i);
23     PrintBoth("\t%x: %x\n", NE2K_BASE_ADDR + i, data);
24   }
25 }
26
27 static void NE2K_Interrupt_Handler(struct Interrupt_State * state)
28 {
29   Begin_IRQ(state);
30   PrintBoth("NIC Interrupt Occured!\n");
31   uchar_t isr_content = In_Byte(NE2K_ISR);
32  // Out_Byte(NE2K_ISR, 0xff); /* Clear all interrupts */
33
34   PrintBoth("Contents of ISR: %x\n", isr_content);
35
36   if(isr_content & 0x01) /* A packet has been received. */
37   { 
38         uchar_t current;
39         do{
40           Out_Byte(NE2K_CR, 0x4a);      
41           current = In_Byte(NE2K_CURR);
42           Out_Byte(NE2K_CR, 0x0a);
43           NE2K_Receive();
44           Out_Byte(NE2K_ISR, 0x01);
45         /* If BNRY and CURR aren't equal, more than one packet has been received. */
46         }while (current > In_Byte(NE2K_BNRY));
47    }
48
49   End_IRQ(state);
50   if(isr_content & 0x02) /* A packet has been successfully transmitted. */
51   {
52     send_done = 1;  
53     Out_Byte(NE2K_ISR, 0x02);
54   }
55   Out_Byte(NE2K_ISR, 0xff); /* Clear all interrupts. */
56 }
57
58 int Init_Ne2k()
59 {
60   PrintBoth("Initializing network card...\n");
61   Out_Byte(NE2K_CR+0x1f, In_Byte(NE2K_CR+0x1f));  /* Reset? */
62
63   struct NE2K_REGS* regs = Malloc(sizeof(struct NE2K_REGS));
64   struct _CR * cr = (struct _CR *)&(regs->cr);
65   struct _RCR * rcr = (struct _RCR*)&(regs->rcr);
66   struct _IMR * imr = (struct _IMR *)&(regs->imr);
67
68   regs->cr = 0x21;
69   regs->dcr = 0x49; /* Word-wide DMA transfer. */
70   regs->isr = 0xff; /* Clear all interrupts. */
71   regs->rcr = 0x20; /* Accept packets shorter than 64 bytes. */
72   regs->tcr = 0x02; /* Internal loopback mode. */
73
74   Out_Byte(NE2K_CR, regs->cr);
75   Out_Byte(NE2K_DCR, regs->dcr);
76   Out_Byte(NE2K_ISR, regs->isr);
77   Out_Byte(NE2K_RCR, regs->rcr);
78   Out_Byte(NE2K_TCR, regs->tcr);
79   Out_Byte(NE2K_IMR, regs->imr);
80
81   /* Remote byte count registers. */
82   Out_Byte(NE2K_RBCR0, 0x00);
83   Out_Byte(NE2K_RBCR1, 0x00);
84   /* Remote start address registers. */
85   Out_Byte(NE2K_RSAR0, 0x00);
86   Out_Byte(NE2K_RSAR1, 0x00);
87
88   Out_Byte(NE2K_TPSR, TX_START_BUFF);      /* Transmit page start register */
89   Out_Byte(NE2K_PSTART, RX_START_BUFF);    /* Page start register */
90 //  Out_Byte(NE2K_BNRY, 0x59);      /* Boundary register */
91   Out_Byte(NE2K_PSTOP, 0x80);     /* Page stop register */
92
93   cr->ps = 0x01;  /* Switch to reg page 1. */
94   Out_Byte(NE2K_CR, regs->cr);
95   /* Current page register: points to first free page that can be used for packet reception. */
96   Out_Byte(NE2K_CURR, RX_START_BUFF);
97   cr->ps = 0x00; /* Switch to page 0 */
98
99   Out_Byte(NE2K_CR, regs->cr);
100   Out_Byte(NE2K_BNRY, RX_START_BUFF); 
101
102   Out_Byte(NE2K_ISR, regs->isr);
103
104   /* Interrupt mask register: setting a bit to 1 enables the
105      corresponding interrupt in ISR. */
106   imr->prxe = 0x1;
107   imr->ptxe = 0x1;
108   imr->rxee = 0x1;
109   imr->txee = 0x1;
110   imr->ovwe = 0x1;
111   imr->cnte = 0x1;
112   Out_Byte(NE2K_IMR, regs->imr);
113
114   cr->ps = 0x01;  /* Switch to reg page 1 */
115   Out_Byte(NE2K_CR, regs->cr);
116
117   /* Set the physical address of the card to 52:54:00:12:34:58 */
118   Out_Byte(NE2K_CR+0x01, 0x52);
119   Out_Byte(NE2K_CR+0x02, 0x54);
120   Out_Byte(NE2K_CR+0x03, 0x00);
121   Out_Byte(NE2K_CR+0x04, 0x12);
122   Out_Byte(NE2K_CR+0x05, 0x34);
123   Out_Byte(NE2K_CR+0x06, 0x58);
124
125   /* Set the multicast address registr to all 1s; accepts all multicast packets */
126   uint_t i;
127   for(i = 0x08; i <= 0x0f; i++) {
128     Out_Byte(NE2K_CR+i, 0xff);
129   }
130
131   regs->cr = 0x21;  //set CR to start value
132   Out_Byte(NE2K_CR, regs->cr);
133
134   regs->tcr = 0x00;
135   Out_Byte(NE2K_TCR, regs->tcr);
136
137   rcr->sep = 0x1;
138   rcr->ar = 0x1;
139   rcr->ab = 0x1;
140   rcr->am = 0x1;
141   rcr->pro = 0x1; /* Promiscuous mode: accept all packets. */
142   rcr->mon = 0x0;
143   Out_Byte(NE2K_RCR, regs->rcr);
144
145   cr->sta = 0x1;  // toggle start bit
146   cr->stp = 0x0;
147   Out_Byte(NE2K_CR, regs->cr);
148   
149   Dump_Registers();
150
151   cr->ps = NE2K_PAGE1;
152   Out_Byte(NE2K_CR, regs->cr);
153   Dump_Registers();
154
155   cr->ps = NE2K_PAGE2;  
156   Out_Byte(NE2K_CR, regs->cr);
157   Dump_Registers();
158
159   cr->ps = NE2K_PAGE0;
160   Out_Byte(NE2K_CR, regs->cr);
161
162   // Reset?
163 //  Out_Byte(NE2K_CR+0x1f, In_Byte(NE2K_CR+0x1f));
164
165   Install_IRQ(NE2K_IRQ, NE2K_Interrupt_Handler);
166   Enable_IRQ(NE2K_IRQ);
167 /*
168   for(i = 0; i < 2; i++)
169   {
170     NE2K_Transmit(regs);
171     PrintBoth("Transmitting a packet\n");
172   }
173 */
174
175   uchar_t src_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x58 };
176   uchar_t dest_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
177
178   uint_t size = 64;
179   uchar_t *data = Malloc(size);
180   data = "This is a 64-byte string that will be used to test transmission.";
181
182   for(i = 0; i < 4; i++) {
183     NE2K_Send(regs, src_addr, dest_addr, 0x01, data, size);
184   }
185
186   Free(data);
187
188   return 0;
189 }
190
191 /* Assumes src and dest are arrays of 6 characters. */
192 int NE2K_Send(struct NE2K_REGS *regs, uchar_t src[], uchar_t dest[], uint_t type, uchar_t *data, uint_t size)
193 {
194   struct _CR * cr = (struct _CR*)&(regs->cr);
195   uint_t packet_size = size + 16;
196   regs->cr = 0x21;
197   cr->stp = 0x0;  //toggle start on
198   cr->sta = 0x1;
199   Out_Byte(NE2K_CR, regs->cr);
200   
201   // Read-before-write bug fix?
202   Out_Byte(NE2K_RBCR0, 0x42);
203   Out_Byte(NE2K_RBCR1, 0x00);
204   Out_Byte(NE2K_RSAR0, 0x42);
205   Out_Byte(NE2K_RSAR1, 0x00);
206
207   cr->rd = 0x01;  // set remote DMA to 'remote read'
208   Out_Byte(NE2K_CR, regs->cr);
209
210   regs->isr = 0x40;  // clear and set Remote DMA high
211   Out_Byte(NE2K_ISR, regs->isr);
212   
213   /* Set remote byte count registers */
214   Out_Byte(NE2K_RBCR0, packet_size & 0xff);
215   Out_Byte(NE2K_RBCR1, (packet_size >> 8) & 0xff);
216
217   /* Set transmit byte count registers. */
218   Out_Byte(NE2K_TBCR0, packet_size & 0xff);
219   Out_Byte(NE2K_TBCR1, (packet_size >> 8) & 0xff);
220
221   Out_Byte(NE2K_RSAR0, 0x00);
222   Out_Byte(NE2K_RSAR1, TX_START_BUFF);
223
224   regs->cr = 0x16;
225   Out_Byte(NE2K_CR, regs->cr);
226
227   /* Destination Address */
228   Out_Word(NE2K_CR + 0x10, (dest[1] << 8) | dest[0]);
229   Out_Word(NE2K_CR + 0x10, (dest[3] << 8) | dest[2]);
230   Out_Word(NE2K_CR + 0x10, (dest[5] << 8) | dest[4]);
231
232   /* Source Address */
233   Out_Word(NE2K_CR + 0x10, (src[1] << 8) | src[0]);
234   Out_Word(NE2K_CR + 0x10, (src[3] << 8) | src[2]);
235   Out_Word(NE2K_CR + 0x10, (src[5] << 8) | src[4]);
236
237   /* Type */
238   Out_Word(NE2K_CR + 0x10, packet_size);
239
240   uint_t i;
241   for(i = 0; i < size; i += 2) {
242     Out_Word(NE2K_CR + 0x10, (*(data + i + 1) << 8) | *(data + i));
243   }
244
245   return 0;
246 }
247
248 int NE2K_Transmit(struct NE2K_REGS *regs)
249 {
250   while(!send_done);
251   send_done = 0;
252
253   struct _CR * cr = (struct _CR*)&(regs->cr);
254   uint_t packet_size = 80;
255   regs->cr = 0x21;
256   cr->stp = 0x0;  //toggle start on
257   cr->sta = 0x1;
258   Out_Byte(NE2K_CR, regs->cr);
259   
260   // Read-before-write bug fix?
261   Out_Byte(NE2K_RBCR0, 0x42);
262   Out_Byte(NE2K_RBCR1, 0x00);
263   Out_Byte(NE2K_RSAR0, 0x42);
264   Out_Byte(NE2K_RSAR1, 0x00);
265
266   cr->rd = 0x01;  // set remote DMA to 'remote read'
267   Out_Byte(NE2K_CR, regs->cr);
268
269   regs->isr = 0x40;  // clear and set Remote DMA high
270   Out_Byte(NE2K_ISR, regs->isr);
271   
272   Out_Byte(NE2K_RBCR0, packet_size);
273   Out_Byte(NE2K_RBCR1, 0x00);
274
275   Out_Byte(NE2K_TBCR0, packet_size);
276   Out_Byte(NE2K_TBCR1, 0x00);
277
278   Out_Byte(NE2K_RSAR0, 0x00);
279   Out_Byte(NE2K_RSAR1, 0x40);
280
281   regs->cr = 0x16;
282   Out_Byte(NE2K_CR, regs->cr);
283
284   /* Begin pushing the packet into the dataport (located at 0x10 from the base address) */
285   /* Destination address = 52:54:00:12:34:56 */
286   Out_Word(NE2K_CR+0x10, 0x5452);
287   Out_Word(NE2K_CR+0x10, 0x1200);
288   Out_Word(NE2K_CR+0x10, 0x5634);
289
290   /* Source address = 52:54:00:12:34:58 */
291   Out_Word(NE2K_CR+0x10, 0x5452);
292   Out_Word(NE2K_CR+0x10, 0x1200);
293   Out_Word(NE2K_CR+0x10, 0x5834);
294
295   /* Type length and data; currently random data */
296   uint_t i;
297   uint_t n = 0;
298   for(i = 1; i <= packet_size/2-12; i++, n+=2) {
299     //Out_Word(NE2K_CR+0x10, 0x0f0b);
300     Out_Word(NE2K_CR+0x10, (n<<8) | (n+1));
301   }
302
303   //regs->isr = 0x40;
304   //Out_Byte(NE2K_ISR, regs->isr); /* Do we need this here? */
305
306   return 0;
307 }
308
309 int NE2K_Receive()
310 {
311   PrintBoth("Packet Received\n");
312
313   Out_Byte(NE2K_CR, 0x22);
314
315   Out_Byte(NE2K_RBCR1, 0x00); 
316 //  Out_Byte(NE2K_RBCR0, 0x60);
317   
318 //  Out_Byte(NE2K_RSAR0, 0x42);
319   Out_Byte(NE2K_RSAR1, next >> 8);
320   Out_Byte(NE2K_RSAR0, next & 0xff);
321   Out_Byte(NE2K_CR, 0x0a);
322
323   /* 
324    * A four byte header is added to the beginning of each received packet.
325    * The first byte is the location of the next packet in the ring buffer.
326    * The second byte is the receive status code.
327    * The third and fourth bytes are the size of the packet.
328    */
329
330   uint_t i;
331   uint_t data;
332   PrintBoth("\nPacket data:\n\t");
333
334   data = In_Word(NE2K_CR + 0x10);
335   PrintBoth("%x ", data);
336
337   /* Get the location of the next packet */
338   next = data & 0xff00;
339
340   uint_t packet_size =  In_Word(NE2K_CR + 0x10) - 4;
341   Out_Byte(NE2K_RBCR0, packet_size & 0xff);
342   Out_Byte(NE2K_RBCR1, (packet_size>>8) & 0xff);
343
344 #if DEBUG
345         PrintBoth("packetsize = %x\n\t", packet_size);
346 #endif
347
348   /* Copy the received packet over from the ring buffer. */
349   for(i = 0; i < packet_size; i+=2) {
350     data = In_Word(NE2K_CR + 0x10);
351     PrintBoth("%x ", data);
352     
353 #if 0
354     PrintBoth("BNRY = %x\n", In_Byte(NE2K_BNRY));
355     Out_Byte(NE2K_CR, 0x4a);
356     PrintBoth("CURR = %x\n", In_Byte(NE2K_CURR));  
357     Out_Byte(NE2K_CR, 0x0a);
358 #endif
359
360     if(!(i%10))
361       PrintBoth("\n\t");
362   }
363
364 //Out_Byte(NE2K_RBCR0, (In_Byte(NE2K_RBCR0))-2);
365 //Out_Byte(NE2K_RSAR0, (In_Byte(NE2K_RSAR0))+2);
366
367   PrintBoth("\n%d packets have been received", ++received);
368   PrintBoth("\n\n");
369
370   Out_Byte(NE2K_ISR, 0x40);
371
372   /* The BNRY register stores the location of the first packet that hasn't been read yet */
373   Out_Byte(NE2K_BNRY, next >> 8);
374
375   return 0;
376 }
377
378
379
380