1 /*
2  *  Copyright (C) 2005-2009  Anders Gavare.  All rights reserved.
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions are met:
6  *
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. The name of the author may not be used to endorse or promote products
13  *     derived from this software without specific prior written permission.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  *  SUCH DAMAGE.
26  *
27  *
28  *  COMMENT: A simple ethernet controller, for the test machines
29  *
30  *  Basic "ethernet" network device. This is a simple test device which can
31  *  be used to send and receive packets to/from a simulated ethernet network.
32  */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "cpu.h"
39 #include "device.h"
40 #include "emul.h"
41 #include "machine.h"
42 #include "memory.h"
43 #include "misc.h"
44 #include "net.h"
45 
46 #include "testmachine/dev_ether.h"
47 
48 
49 #define	DEV_ETHER_TICK_SHIFT	14
50 
51 struct ether_data {
52 	struct nic_data		nic;
53 
54 	unsigned char		buf[DEV_ETHER_BUFFER_SIZE];
55 	unsigned char		mac[6];
56 
57 	int			status;
58 	int			packet_len;
59 
60 	struct interrupt	irq;
61 };
62 
63 
DEVICE_TICK(ether)64 DEVICE_TICK(ether)
65 {
66 	struct ether_data *d = (struct ether_data *) extra;
67 	int r = 0;
68 
69 	d->status &= ~DEV_ETHER_STATUS_MORE_PACKETS_AVAILABLE;
70 	if (cpu->machine->emul->net != NULL)
71 		r = net_ethernet_rx_avail(cpu->machine->emul->net, &d->nic);
72 	if (r)
73 		d->status |= DEV_ETHER_STATUS_MORE_PACKETS_AVAILABLE;
74 
75 	if (d->status)
76 		INTERRUPT_ASSERT(d->irq);
77 	else
78 		INTERRUPT_DEASSERT(d->irq);
79 }
80 
81 
DEVICE_ACCESS(ether_buf)82 DEVICE_ACCESS(ether_buf)
83 {
84 	struct ether_data *d = (struct ether_data *) extra;
85 
86 	if (writeflag == MEM_WRITE)
87 		memcpy(d->buf + relative_addr, data, len);
88 	else
89 		memcpy(data, d->buf + relative_addr, len);
90 
91 	return 1;
92 }
93 
94 
DEVICE_ACCESS(ether)95 DEVICE_ACCESS(ether)
96 {
97 	struct ether_data *d = (struct ether_data *) extra;
98 	uint64_t idata = 0, odata = 0;
99 	unsigned char *incoming_ptr;
100 	int incoming_len;
101 
102 	if (writeflag == MEM_WRITE)
103 		idata = memory_readmax64(cpu, data, len);
104 
105 	/*  Note: relative_addr + DEV_ETHER_BUFFER_SIZE to get the same
106 	    offsets as in the header file:  */
107 
108 	switch (relative_addr + DEV_ETHER_BUFFER_SIZE) {
109 
110 	case DEV_ETHER_STATUS:
111 		if (writeflag == MEM_READ) {
112 			odata = d->status;
113 			d->status = 0;
114 			INTERRUPT_DEASSERT(d->irq);
115 		} else
116 			fatal("[ ether: WARNING: write to status ]\n");
117 		break;
118 
119 	case DEV_ETHER_PACKETLENGTH:
120 		if (writeflag == MEM_READ)
121 			odata = d->packet_len;
122 		else {
123 			if ((int64_t)idata < 0) {
124 				fatal("[ ether: ERROR: packet len too"
125 				    " short (%i bytes) ]\n", (int)idata);
126 				idata = (uint64_t) -1;
127 			}
128 			if (idata > DEV_ETHER_BUFFER_SIZE) {
129 				fatal("[ ether: ERROR: packet len too"
130 				    " large (%i bytes) ]\n", (int)idata);
131 				idata = DEV_ETHER_BUFFER_SIZE;
132 			}
133 			d->packet_len = idata;
134 		}
135 		break;
136 
137 	case DEV_ETHER_COMMAND:
138 		if (writeflag == MEM_READ) {
139 			fatal("[ ether: WARNING: read from command ]\n");
140 			break;
141 		}
142 
143 		/*  Write:  */
144 		switch (idata) {
145 
146 		case DEV_ETHER_COMMAND_RX:	/*  Receive:  */
147 			if (cpu->machine->emul->net == NULL)
148 				fatal("[ ether: RECEIVE but no net? ]\n");
149 			else {
150 				d->status &= ~DEV_ETHER_STATUS_PACKET_RECEIVED;
151 				if (net_ethernet_rx(cpu->machine->emul->net,
152 				    &d->nic, &incoming_ptr, &incoming_len)) {
153 					d->status |=
154 					    DEV_ETHER_STATUS_PACKET_RECEIVED;
155 					if (incoming_len>DEV_ETHER_BUFFER_SIZE)
156 						incoming_len =
157 						    DEV_ETHER_BUFFER_SIZE;
158 					memcpy(d->buf, incoming_ptr,
159 					    incoming_len);
160 					free(incoming_ptr);
161 					d->packet_len = incoming_len;
162 				}
163 			}
164 			dev_ether_tick(cpu, d);
165 			break;
166 
167 		case DEV_ETHER_COMMAND_TX:	/*  Send  */
168 			if (cpu->machine->emul->net == NULL)
169 				fatal("[ ether: SEND but no net? ]\n");
170 			else
171 				net_ethernet_tx(cpu->machine->emul->net,
172 				    &d->nic, d->buf, d->packet_len);
173 			d->status &= ~DEV_ETHER_STATUS_PACKET_RECEIVED;
174 			dev_ether_tick(cpu, d);
175 			break;
176 
177 		default:fatal("[ ether: UNIMPLEMENTED command 0x"
178 			    "%02x ]\n", idata);
179 			cpu->running = 0;
180 		}
181 		break;
182 
183 	case DEV_ETHER_MAC:
184 		if (writeflag == MEM_READ) {
185 			fatal("[ ether: read of MAC is not allowed! ]\n");
186 		} else {
187 			// Write out the MAC address to the address given.
188 			cpu->memory_rw(cpu, cpu->mem, idata, d->nic.mac_address,
189 			    6, MEM_WRITE, CACHE_NONE);
190 		}
191 		break;
192 
193 	default:if (writeflag == MEM_WRITE) {
194 			fatal("[ ether: unimplemented write to "
195 			    "offset 0x%x: data=0x%x ]\n", (int)
196 			    relative_addr, (int)idata);
197 		} else {
198 			fatal("[ ether: unimplemented read from "
199 			    "offset 0x%x ]\n", (int)relative_addr);
200 		}
201 	}
202 
203 	if (writeflag == MEM_READ)
204 		memory_writemax64(cpu, data, len, odata);
205 
206 	return 1;
207 }
208 
209 
DEVINIT(ether)210 DEVINIT(ether)
211 {
212 	struct ether_data *d;
213 	size_t nlen;
214 	char *n1, *n2;
215 	char tmp[50];
216 
217 	CHECK_ALLOCATION(d = (struct ether_data *) malloc(sizeof(struct ether_data)));
218 	memset(d, 0, sizeof(struct ether_data));
219 
220 	nlen = strlen(devinit->name) + 80;
221 	CHECK_ALLOCATION(n1 = (char *) malloc(nlen));
222 	CHECK_ALLOCATION(n2 = (char *) malloc(nlen));
223 
224 	INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
225 
226 	net_generate_unique_mac(devinit->machine, d->nic.mac_address);
227 	snprintf(tmp, sizeof(tmp), "%02x:%02x:%02x:%02x:%02x:%02x",
228 	    d->nic.mac_address[0], d->nic.mac_address[1],
229 	    d->nic.mac_address[2], d->nic.mac_address[3],
230 	    d->nic.mac_address[4], d->nic.mac_address[5]);
231 
232 	snprintf(n1, nlen, "%s [%s]", devinit->name, tmp);
233 	snprintf(n2, nlen, "%s [%s, control]", devinit->name, tmp);
234 
235 	memory_device_register(devinit->machine->memory, n1, devinit->addr,
236 	    DEV_ETHER_BUFFER_SIZE, dev_ether_buf_access, (void *)d,
237 	    DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK |
238 	    DM_READS_HAVE_NO_SIDE_EFFECTS, d->buf);
239 	memory_device_register(devinit->machine->memory, n2,
240 	    devinit->addr + DEV_ETHER_BUFFER_SIZE,
241 	    DEV_ETHER_LENGTH-DEV_ETHER_BUFFER_SIZE, dev_ether_access, (void *)d,
242 	    DM_DEFAULT, NULL);
243 
244 	net_add_nic(devinit->machine->emul->net, &d->nic);
245 
246 	machine_add_tickfunction(devinit->machine,
247 	    dev_ether_tick, d, DEV_ETHER_TICK_SHIFT);
248 
249 	return 1;
250 }
251 
252