122 |
uint16_t rcnt; |
uint16_t rcnt; |
123 |
uint32_t rsar; |
uint32_t rsar; |
124 |
uint8_t rsr; |
uint8_t rsr; |
125 |
|
uint8_t rxcr; |
126 |
uint8_t isr; |
uint8_t isr; |
127 |
uint8_t dcfg; |
uint8_t dcfg; |
128 |
uint8_t imr; |
uint8_t imr; |
131 |
uint8_t mult[8]; /* multicast mask array */ |
uint8_t mult[8]; /* multicast mask array */ |
132 |
int irq; |
int irq; |
133 |
PCIDevice *pci_dev; |
PCIDevice *pci_dev; |
134 |
NetDriverState *nd; |
VLANClientState *vc; |
135 |
|
uint8_t macaddr[6]; |
136 |
uint8_t mem[NE2000_MEM_SIZE]; |
uint8_t mem[NE2000_MEM_SIZE]; |
137 |
} NE2000State; |
} NE2000State; |
138 |
|
|
141 |
int i; |
int i; |
142 |
|
|
143 |
s->isr = ENISR_RESET; |
s->isr = ENISR_RESET; |
144 |
memcpy(s->mem, s->nd->macaddr, 6); |
memcpy(s->mem, s->macaddr, 6); |
145 |
s->mem[14] = 0x57; |
s->mem[14] = 0x57; |
146 |
s->mem[15] = 0x57; |
s->mem[15] = 0x57; |
147 |
|
|
169 |
} |
} |
170 |
} |
} |
171 |
|
|
172 |
|
#define POLYNOMIAL 0x04c11db6 |
173 |
|
|
174 |
|
/* From FreeBSD */ |
175 |
|
/* XXX: optimize */ |
176 |
|
static int compute_mcast_idx(const uint8_t *ep) |
177 |
|
{ |
178 |
|
uint32_t crc; |
179 |
|
int carry, i, j; |
180 |
|
uint8_t b; |
181 |
|
|
182 |
|
crc = 0xffffffff; |
183 |
|
for (i = 0; i < 6; i++) { |
184 |
|
b = *ep++; |
185 |
|
for (j = 0; j < 8; j++) { |
186 |
|
carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); |
187 |
|
crc <<= 1; |
188 |
|
b >>= 1; |
189 |
|
if (carry) |
190 |
|
crc = ((crc ^ POLYNOMIAL) | carry); |
191 |
|
} |
192 |
|
} |
193 |
|
return (crc >> 26); |
194 |
|
} |
195 |
|
|
196 |
/* return the max buffer size if the NE2000 can receive more data */ |
/* return the max buffer size if the NE2000 can receive more data */ |
197 |
static int ne2000_can_receive(void *opaque) |
static int ne2000_can_receive(void *opaque) |
198 |
{ |
{ |
218 |
{ |
{ |
219 |
NE2000State *s = opaque; |
NE2000State *s = opaque; |
220 |
uint8_t *p; |
uint8_t *p; |
221 |
int total_len, next, avail, len, index; |
int total_len, next, avail, len, index, mcast_idx; |
222 |
uint8_t buf1[60]; |
uint8_t buf1[60]; |
223 |
|
static const uint8_t broadcast_macaddr[6] = |
224 |
|
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
225 |
|
|
226 |
#if defined(DEBUG_NE2000) |
#if defined(DEBUG_NE2000) |
227 |
printf("NE2000: received len=%d\n", size); |
printf("NE2000: received len=%d\n", size); |
228 |
#endif |
#endif |
229 |
|
|
230 |
|
if (!ne2000_can_receive(s)) |
231 |
|
return; |
232 |
|
|
233 |
|
/* XXX: check this */ |
234 |
|
if (s->rxcr & 0x10) { |
235 |
|
/* promiscuous: receive all */ |
236 |
|
} else { |
237 |
|
if (!memcmp(buf, broadcast_macaddr, 6)) { |
238 |
|
/* broadcast address */ |
239 |
|
if (!(s->rxcr & 0x04)) |
240 |
|
return; |
241 |
|
} else if (buf[0] & 0x01) { |
242 |
|
/* multicast */ |
243 |
|
if (!(s->rxcr & 0x08)) |
244 |
|
return; |
245 |
|
mcast_idx = compute_mcast_idx(buf); |
246 |
|
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) |
247 |
|
return; |
248 |
|
} else if (s->mem[0] == buf[0] && |
249 |
|
s->mem[2] == buf[1] && |
250 |
|
s->mem[4] == buf[2] && |
251 |
|
s->mem[6] == buf[3] && |
252 |
|
s->mem[8] == buf[4] && |
253 |
|
s->mem[10] == buf[5]) { |
254 |
|
/* match */ |
255 |
|
} else { |
256 |
|
return; |
257 |
|
} |
258 |
|
} |
259 |
|
|
260 |
|
|
261 |
/* if too small buffer, then expand it */ |
/* if too small buffer, then expand it */ |
262 |
if (size < MIN_BUF_SIZE) { |
if (size < MIN_BUF_SIZE) { |
263 |
memcpy(buf1, buf, size); |
memcpy(buf1, buf, size); |
332 |
index -= NE2000_PMEM_SIZE; |
index -= NE2000_PMEM_SIZE; |
333 |
/* fail safe: check range on the transmitted length */ |
/* fail safe: check range on the transmitted length */ |
334 |
if (index + s->tcnt <= NE2000_PMEM_END) { |
if (index + s->tcnt <= NE2000_PMEM_END) { |
335 |
qemu_send_packet(s->nd, s->mem + index, s->tcnt); |
qemu_send_packet(s->vc, s->mem + index, s->tcnt); |
336 |
} |
} |
337 |
/* signal end of transfert */ |
/* signal end of transfert */ |
338 |
s->tsr = ENTSR_PTX; |
s->tsr = ENTSR_PTX; |
379 |
case EN0_RCNTHI: |
case EN0_RCNTHI: |
380 |
s->rcnt = (s->rcnt & 0x00ff) | (val << 8); |
s->rcnt = (s->rcnt & 0x00ff) | (val << 8); |
381 |
break; |
break; |
382 |
|
case EN0_RXCR: |
383 |
|
s->rxcr = val; |
384 |
|
break; |
385 |
case EN0_DCFG: |
case EN0_DCFG: |
386 |
s->dcfg = val; |
s->dcfg = val; |
387 |
break; |
break; |
670 |
return 0; |
return 0; |
671 |
} |
} |
672 |
|
|
673 |
void isa_ne2000_init(int base, int irq, NetDriverState *nd) |
void isa_ne2000_init(int base, int irq, NICInfo *nd) |
674 |
{ |
{ |
675 |
NE2000State *s; |
NE2000State *s; |
676 |
|
|
677 |
s = qemu_mallocz(sizeof(NE2000State)); |
s = qemu_mallocz(sizeof(NE2000State)); |
678 |
if (!s) |
if (!s) |
679 |
return; |
return; |
689 |
register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); |
register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); |
690 |
register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
691 |
s->irq = irq; |
s->irq = irq; |
692 |
s->nd = nd; |
memcpy(s->macaddr, nd->macaddr, 6); |
693 |
|
|
694 |
ne2000_reset(s); |
ne2000_reset(s); |
695 |
|
|
696 |
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); |
s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); |
697 |
|
|
698 |
|
snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
699 |
|
"ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x", |
700 |
|
s->macaddr[0], |
701 |
|
s->macaddr[1], |
702 |
|
s->macaddr[2], |
703 |
|
s->macaddr[3], |
704 |
|
s->macaddr[4], |
705 |
|
s->macaddr[5]); |
706 |
|
|
707 |
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); |
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); |
|
|
|
708 |
} |
} |
709 |
|
|
710 |
/***********************************************************/ |
/***********************************************************/ |
735 |
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
736 |
} |
} |
737 |
|
|
738 |
void pci_ne2000_init(PCIBus *bus, NetDriverState *nd) |
void pci_ne2000_init(PCIBus *bus, NICInfo *nd) |
739 |
{ |
{ |
740 |
PCINE2000State *d; |
PCINE2000State *d; |
741 |
NE2000State *s; |
NE2000State *s; |
760 |
s = &d->ne2000; |
s = &d->ne2000; |
761 |
s->irq = 16; // PCI interrupt |
s->irq = 16; // PCI interrupt |
762 |
s->pci_dev = (PCIDevice *)d; |
s->pci_dev = (PCIDevice *)d; |
763 |
s->nd = nd; |
memcpy(s->macaddr, nd->macaddr, 6); |
764 |
ne2000_reset(s); |
ne2000_reset(s); |
765 |
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); |
s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); |
766 |
|
|
767 |
|
snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
768 |
|
"ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", |
769 |
|
s->macaddr[0], |
770 |
|
s->macaddr[1], |
771 |
|
s->macaddr[2], |
772 |
|
s->macaddr[3], |
773 |
|
s->macaddr[4], |
774 |
|
s->macaddr[5]); |
775 |
|
|
776 |
/* XXX: instance number ? */ |
/* XXX: instance number ? */ |
777 |
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); |
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); |
778 |
register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, |
register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, |