1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ethernet.h"
6 
7 #include <assert.h>
8 #include <limits.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12 
13 #include <ddk/debug.h>
14 #include <ddk/io-buffer.h>
15 #include <ddk/protocol/ethernet.h>
16 #include <fbl/algorithm.h>
17 #include <fbl/alloc_checker.h>
18 #include <fbl/auto_call.h>
19 #include <fbl/auto_lock.h>
20 #include <fbl/unique_ptr.h>
21 #include <pretty/hexdump.h>
22 #include <virtio/net.h>
23 #include <virtio/virtio.h>
24 #include <zircon/assert.h>
25 #include <zircon/status.h>
26 #include <zircon/types.h>
27 
28 #include <utility>
29 
30 #include "ring.h"
31 #include "trace.h"
32 
33 // Enables/disables debugging info
34 #define LOCAL_TRACE 0
35 
36 namespace virtio {
37 
38 namespace {
39 
40 // Specifies how many packets can fit in each of the receive and transmit
41 // backlogs.
42 const size_t kBacklog = 32;
43 
44 // Specifies the maximum transfer unit we support and the maximum layer 1
45 // Ethernet packet header length.
46 const size_t kVirtioMtu = 1500;
47 const size_t kEthHeaderSizeBytes = 14;
48 const size_t kEthFrameSize = kVirtioMtu + kEthHeaderSizeBytes;
49 
50 // Other constants determined by the values above and the memory architecture.
51 // The goal here is to allocate single-page I/O buffers.
52 const size_t kFrameSize = sizeof(virtio_net_hdr_t) + kEthFrameSize;
53 const size_t kFramesInBuf = PAGE_SIZE / kFrameSize;
54 const size_t kNumIoBufs = fbl::round_up(kBacklog * 2, kFramesInBuf) / kFramesInBuf;
55 
56 const uint16_t kRxId = 0u;
57 const uint16_t kTxId = 1u;
58 
59 // Strictly for convenience...
60 typedef struct vring_desc desc_t;
61 
62 // Device bridge helpers
virtio_net_unbind(void * ctx)63 void virtio_net_unbind(void* ctx) {
64     virtio::EthernetDevice* eth = static_cast<virtio::EthernetDevice*>(ctx);
65     eth->Unbind();
66 }
67 
virtio_net_release(void * ctx)68 void virtio_net_release(void* ctx) {
69     fbl::unique_ptr<virtio::EthernetDevice> eth(static_cast<virtio::EthernetDevice*>(ctx));
70     eth->Release();
71 }
72 
73 zx_protocol_device_t kDeviceOps = {
74     DEVICE_OPS_VERSION,
75     nullptr, // get_protocol
76     nullptr, // open
77     nullptr, // openat
78     nullptr, // close
79     virtio_net_unbind,
80     virtio_net_release,
81     nullptr, // read
82     nullptr, // write
83     nullptr, // get_size
84     nullptr, // ioctl
85     nullptr, // suspend
86     nullptr, // resume
87     nullptr, // rxrpc
88     nullptr, // rxmsg
89 };
90 
91 // Protocol bridge helpers
virtio_net_query(void * ctx,uint32_t options,ethmac_info_t * info)92 zx_status_t virtio_net_query(void* ctx, uint32_t options, ethmac_info_t* info) {
93     virtio::EthernetDevice* eth = static_cast<virtio::EthernetDevice*>(ctx);
94     return eth->Query(options, info);
95 }
96 
virtio_net_stop(void * ctx)97 void virtio_net_stop(void* ctx) {
98     virtio::EthernetDevice* eth = static_cast<virtio::EthernetDevice*>(ctx);
99     eth->Stop();
100 }
101 
virtio_net_start(void * ctx,const ethmac_ifc_t * ifc)102 zx_status_t virtio_net_start(void* ctx, const ethmac_ifc_t* ifc) {
103     virtio::EthernetDevice* eth = static_cast<virtio::EthernetDevice*>(ctx);
104     return eth->Start(ifc);
105 }
106 
virtio_net_queue_tx(void * ctx,uint32_t options,ethmac_netbuf_t * netbuf)107 zx_status_t virtio_net_queue_tx(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf) {
108     virtio::EthernetDevice* eth = static_cast<virtio::EthernetDevice*>(ctx);
109     return eth->QueueTx(options, netbuf);
110 }
111 
virtio_set_param(void * ctx,uint32_t param,int32_t value,const void * data,size_t data_size)112 static zx_status_t virtio_set_param(void* ctx, uint32_t param, int32_t value, const void* data,
113                                     size_t data_size) {
114     return ZX_ERR_NOT_SUPPORTED;
115 }
116 
117 ethmac_protocol_ops_t kProtoOps = {
118     virtio_net_query,
119     virtio_net_stop,
120     virtio_net_start,
121     virtio_net_queue_tx,
122     virtio_set_param,
123     NULL, // get_bti not implemented because we don't have FEATURE_DMA
124 };
125 
126 // I/O buffer helpers
InitBuffers(const zx::bti & bti,fbl::unique_ptr<io_buffer_t[]> * out)127 zx_status_t InitBuffers(const zx::bti& bti, fbl::unique_ptr<io_buffer_t[]>* out) {
128     zx_status_t rc;
129     fbl::AllocChecker ac;
130     fbl::unique_ptr<io_buffer_t[]> bufs(new (&ac) io_buffer_t[kNumIoBufs]);
131     if (!ac.check()) {
132         zxlogf(ERROR, "out of memory!\n");
133         return ZX_ERR_NO_MEMORY;
134     }
135     memset(bufs.get(), 0, sizeof(io_buffer_t) * kNumIoBufs);
136     size_t buf_size = kFrameSize * kFramesInBuf;
137     for (uint16_t id = 0; id < kNumIoBufs; ++id) {
138         if ((rc = io_buffer_init(&bufs[id], bti.get(), buf_size,
139                                  IO_BUFFER_RW | IO_BUFFER_CONTIG)) != ZX_OK) {
140             zxlogf(ERROR, "failed to allocate I/O buffers: %s\n", zx_status_get_string(rc));
141             return rc;
142         }
143     }
144     *out = std::move(bufs);
145     return ZX_OK;
146 }
147 
ReleaseBuffers(fbl::unique_ptr<io_buffer_t[]> bufs)148 void ReleaseBuffers(fbl::unique_ptr<io_buffer_t[]> bufs) {
149     if (!bufs) {
150         return;
151     }
152     for (size_t i = 0; i < kNumIoBufs; ++i) {
153         if (io_buffer_is_valid(&bufs[i])) {
154             io_buffer_release(&bufs[i]);
155         }
156     }
157 }
158 
159 // Frame access helpers
GetFrame(io_buffer_t ** bufs,uint16_t ring_id,uint16_t desc_id)160 zx_off_t GetFrame(io_buffer_t** bufs, uint16_t ring_id, uint16_t desc_id) {
161     uint16_t i = static_cast<uint16_t>(desc_id + ring_id * kBacklog);
162     *bufs = &((*bufs)[i / kFramesInBuf]);
163     return (i % kFramesInBuf) * kFrameSize;
164 }
165 
GetFrameVirt(io_buffer_t * bufs,uint16_t ring_id,uint16_t desc_id)166 void* GetFrameVirt(io_buffer_t* bufs, uint16_t ring_id, uint16_t desc_id) {
167     zx_off_t offset = GetFrame(&bufs, ring_id, desc_id);
168     uintptr_t vaddr = reinterpret_cast<uintptr_t>(io_buffer_virt(bufs));
169     return reinterpret_cast<void*>(vaddr + offset);
170 }
171 
GetFramePhys(io_buffer_t * bufs,uint16_t ring_id,uint16_t desc_id)172 zx_paddr_t GetFramePhys(io_buffer_t* bufs, uint16_t ring_id, uint16_t desc_id) {
173     zx_off_t offset = GetFrame(&bufs, ring_id, desc_id);
174     return io_buffer_phys(bufs) + offset;
175 }
176 
GetFrameHdr(io_buffer_t * bufs,uint16_t ring_id,uint16_t desc_id)177 virtio_net_hdr_t* GetFrameHdr(io_buffer_t* bufs, uint16_t ring_id, uint16_t desc_id) {
178     return reinterpret_cast<virtio_net_hdr_t*>(GetFrameVirt(bufs, ring_id, desc_id));
179 }
180 
GetFrameData(io_buffer_t * bufs,uint16_t ring_id,uint16_t desc_id,size_t hdr_size)181 uint8_t* GetFrameData(io_buffer_t* bufs, uint16_t ring_id, uint16_t desc_id, size_t hdr_size) {
182     uintptr_t vaddr = reinterpret_cast<uintptr_t>(GetFrameHdr(bufs, ring_id, desc_id));
183     return reinterpret_cast<uint8_t*>(vaddr + hdr_size);
184 }
185 
186 } // namespace
187 
EthernetDevice(zx_device_t * bus_device,zx::bti bti,fbl::unique_ptr<Backend> backend)188 EthernetDevice::EthernetDevice(zx_device_t* bus_device, zx::bti bti, fbl::unique_ptr<Backend> backend)
189     : Device(bus_device, std::move(bti), std::move(backend)), rx_(this), tx_(this), bufs_(nullptr),
190       unkicked_(0), ifc_({nullptr, nullptr}) {
191 }
192 
~EthernetDevice()193 EthernetDevice::~EthernetDevice() {
194     LTRACE_ENTRY;
195 }
196 
Init()197 zx_status_t EthernetDevice::Init() {
198     LTRACE_ENTRY;
199     zx_status_t rc;
200     if (mtx_init(&state_lock_, mtx_plain) != thrd_success ||
201         mtx_init(&tx_lock_, mtx_plain) != thrd_success) {
202         return ZX_ERR_NO_RESOURCES;
203     }
204     fbl::AutoLock lock(&state_lock_);
205 
206     // Reset the device and read our configuration
207     DeviceReset();
208     CopyDeviceConfig(&config_, sizeof(config_));
209     LTRACEF("mac %02x:%02x:%02x:%02x:%02x:%02x\n", config_.mac[0], config_.mac[1], config_.mac[2],
210             config_.mac[3], config_.mac[4], config_.mac[5]);
211     LTRACEF("status %u\n", config_.status);
212     LTRACEF("max_virtqueue_pairs  %u\n", config_.max_virtqueue_pairs);
213 
214     // Ack and set the driver status bit
215     DriverStatusAck();
216 
217     virtio_hdr_len_ = sizeof(virtio_net_hdr_t);
218     if (DeviceFeatureSupported(VIRTIO_F_VERSION_1)) {
219       DriverFeatureAck(VIRTIO_F_VERSION_1);
220     } else {
221       // 5.1.6.1 Legacy Interface: Device Operation
222       //
223       // The legacy driver only presented num_buffers in the struct
224       // virtio_net_hdr when VIRTIO_NET_F_MRG_RXBUF was negotiated; without
225       // that feature the structure was 2 bytes shorter.
226       virtio_hdr_len_ -= 2;
227     }
228 
229     // TODO(aarongreen): Check additional features bits and ack/nak them
230     rc = DeviceStatusFeaturesOk();
231     if (rc != ZX_OK) {
232         zxlogf(ERROR, "%s: Feature negotiation failed (%d)\n", tag(), rc);
233         return rc;
234     }
235 
236     // Plan to clean up unless everything goes right.
237     auto cleanup = fbl::MakeAutoCall([this]() { Release(); });
238 
239     // Allocate I/O buffers and virtqueues.
240     uint16_t num_descs = static_cast<uint16_t>(kBacklog & 0xffff);
241     if ((rc = InitBuffers(bti_, &bufs_)) != ZX_OK || (rc = rx_.Init(kRxId, num_descs)) != ZX_OK ||
242         (rc = tx_.Init(kTxId, num_descs)) != ZX_OK) {
243         zxlogf(ERROR, "failed to allocate virtqueue: %s\n", zx_status_get_string(rc));
244         return rc;
245     }
246 
247     // Associate the I/O buffers with the virtqueue descriptors
248     desc_t* desc = nullptr;
249     uint16_t id;
250 
251     // For rx buffers, we queue a bunch of "reads" from the network that
252     // complete when packets arrive.
253     for (uint16_t i = 0; i < num_descs; ++i) {
254         desc = rx_.AllocDescChain(1, &id);
255         desc->addr = GetFramePhys(bufs_.get(), kRxId, id);
256         desc->len = kFrameSize;
257         desc->flags |= VRING_DESC_F_WRITE;
258         LTRACE_DO(virtio_dump_desc(desc));
259         rx_.SubmitChain(id);
260     }
261 
262     // For tx buffers, we hold onto them until we need to send a packet.
263     for (uint16_t id = 0; id < num_descs; ++id) {
264         desc = tx_.DescFromIndex(id);
265         desc->addr = GetFramePhys(bufs_.get(), kTxId, id);
266         desc->len = 0;
267         desc->flags &= static_cast<uint16_t>(~VRING_DESC_F_WRITE);
268         LTRACE_DO(virtio_dump_desc(desc));
269     }
270 
271     // Start the interrupt thread and set the driver OK status
272     StartIrqThread();
273 
274     // Initialize the zx_device and publish us
275     device_add_args_t args;
276     memset(&args, 0, sizeof(args));
277     args.version = DEVICE_ADD_ARGS_VERSION;
278     args.name = "virtio-net";
279     args.ctx = this;
280     args.ops = &kDeviceOps;
281     args.proto_id = ZX_PROTOCOL_ETHMAC;
282     args.proto_ops = &kProtoOps;
283     if ((rc = device_add(bus_device_, &args, &device_)) != ZX_OK) {
284         zxlogf(ERROR, "failed to add device: %s\n", zx_status_get_string(rc));
285         return rc;
286     }
287     // Give the rx buffers to the host
288     rx_.Kick();
289 
290     // Woohoo! Driver should be ready.
291     cleanup.cancel();
292     DriverStatusOk();
293     return ZX_OK;
294 }
295 
Release()296 void EthernetDevice::Release() {
297     LTRACE_ENTRY;
298     fbl::AutoLock lock(&state_lock_);
299     ReleaseLocked();
300 }
301 
ReleaseLocked()302 void EthernetDevice::ReleaseLocked() {
303     ifc_.ops = nullptr;
304     ReleaseBuffers(std::move(bufs_));
305     Device::Release();
306 }
307 
IrqRingUpdate()308 void EthernetDevice::IrqRingUpdate() {
309     LTRACE_ENTRY;
310     // Lock to prevent changes to ifc_.
311     {
312         fbl::AutoLock lock(&state_lock_);
313         if (!ifc_.ops) {
314             return;
315         }
316         // Ring::IrqRingUpdate will call this lambda on each rx buffer filled by
317         // the underlying device since the last IRQ.
318         // Thread safety analysis is explicitly disabled as clang isn't able to determine that the
319         // state_lock_ is  held when the lambda invoked.
320         rx_.IrqRingUpdate([this](vring_used_elem* used_elem) TA_NO_THREAD_SAFETY_ANALYSIS {
321             uint16_t id = static_cast<uint16_t>(used_elem->id & 0xffff);
322             desc_t* desc = rx_.DescFromIndex(id);
323 
324             // Transitional driver does not merge rx buffers.
325             if ((desc->flags & VRING_DESC_F_NEXT) != 0) {
326                 zxlogf(ERROR, "dropping rx packet; do not support descriptor chaining");
327                 while((desc->flags & VRING_DESC_F_NEXT)) {
328                     uint16_t next_id = desc->next;
329                     rx_.FreeDesc(id);
330                     id = next_id;
331                     desc = rx_.DescFromIndex(id);
332                 }
333                 return;
334             }
335             assert(used_elem->len <= desc->len);
336             uint8_t* data = GetFrameData(bufs_.get(), kRxId, id, virtio_hdr_len_);
337             size_t len = used_elem->len - virtio_hdr_len_;
338             LTRACEF("Receiving %zu bytes:\n", len);
339             LTRACE_DO(hexdump8_ex(data, len, 0));
340 
341             // Pass the data up the stack to the generic Ethernet driver
342             ethmac_ifc_recv(&ifc_, data, len, 0);
343             LTRACE_DO(virtio_dump_desc(desc));
344             rx_.FreeDesc(id);
345         });
346     }
347 
348     // Now recycle the rx buffers.  As in Init(), this means queuing a bunch of
349     // "reads" from the network that will complete when packets arrive.
350     desc_t* desc = nullptr;
351     uint16_t id;
352     bool need_kick = false;
353     while ((desc = rx_.AllocDescChain(1, &id))) {
354         desc->len = kFrameSize;
355         rx_.SubmitChain(id);
356         need_kick = true;
357     }
358 
359     // If we have re-queued any rx buffers, poke the virtqueue to pick them up.
360     if (need_kick) {
361         rx_.Kick();
362     }
363 }
364 
IrqConfigChange()365 void EthernetDevice::IrqConfigChange() {
366     LTRACE_ENTRY;
367     fbl::AutoLock lock(&state_lock_);
368     if (!ifc_.ops) {
369         return;
370     }
371 
372     // Re-read our configuration
373     CopyDeviceConfig(&config_, sizeof(config_));
374     ethmac_ifc_status(&ifc_, (config_.status & VIRTIO_NET_S_LINK_UP) ? ETHMAC_STATUS_ONLINE : 0);
375 }
376 
Query(uint32_t options,ethmac_info_t * info)377 zx_status_t EthernetDevice::Query(uint32_t options, ethmac_info_t* info) {
378     LTRACE_ENTRY;
379     if (options) {
380         return ZX_ERR_INVALID_ARGS;
381     }
382     fbl::AutoLock lock(&state_lock_);
383     if (info) {
384         // TODO(aarongreen): Add info->features = GetFeatures();
385         info->mtu = kVirtioMtu;
386         info->netbuf_size = sizeof(ethmac_netbuf_t);
387         memcpy(info->mac, config_.mac, sizeof(info->mac));
388     }
389     return ZX_OK;
390 }
391 
Stop()392 void EthernetDevice::Stop() {
393     LTRACE_ENTRY;
394     fbl::AutoLock lock(&state_lock_);
395     ifc_.ops = nullptr;
396 }
397 
Start(const ethmac_ifc_t * ifc)398 zx_status_t EthernetDevice::Start(const ethmac_ifc_t* ifc) {
399     LTRACE_ENTRY;
400     if (!ifc) {
401         return ZX_ERR_INVALID_ARGS;
402     }
403     fbl::AutoLock lock(&state_lock_);
404     if (!bufs_ || ifc_.ops) {
405         return ZX_ERR_BAD_STATE;
406     }
407     ifc_ = *ifc;
408     ethmac_ifc_status(&ifc_, (config_.status & VIRTIO_NET_S_LINK_UP) ? ETHMAC_STATUS_ONLINE : 0);
409     return ZX_OK;
410 }
411 
QueueTx(uint32_t options,ethmac_netbuf_t * netbuf)412 zx_status_t EthernetDevice::QueueTx(uint32_t options, ethmac_netbuf_t* netbuf) {
413     LTRACE_ENTRY;
414     const void* data = netbuf->data_buffer;
415     size_t length = netbuf->data_size;
416     // First, validate the packet
417     if (!data || length > kEthFrameSize) {
418         zxlogf(ERROR, "dropping packet; invalid packet\n");
419         return ZX_ERR_INVALID_ARGS;
420     }
421 
422     fbl::AutoLock lock(&tx_lock_);
423 
424     // Flush outstanding descriptors.  Ring::IrqRingUpdate will call this lambda
425     // on each sent tx_buffer, allowing us to reclaim them.
426     auto flush = [this](vring_used_elem* used_elem) {
427         uint16_t id = static_cast<uint16_t>(used_elem->id & 0xffff);
428         desc_t* desc = tx_.DescFromIndex(id);
429         assert((desc->flags & VRING_DESC_F_NEXT) == 0);
430         LTRACE_DO(virtio_dump_desc(desc));
431         tx_.FreeDesc(id);
432     };
433 
434     // Grab a free descriptor
435     uint16_t id;
436     desc_t* desc = tx_.AllocDescChain(1, &id);
437     if (!desc) {
438         tx_.IrqRingUpdate(flush);
439         desc = tx_.AllocDescChain(1, &id);
440     }
441     if (!desc) {
442         zxlogf(ERROR, "dropping packet; out of descriptors\n");
443         return ZX_ERR_NO_RESOURCES;
444     }
445 
446     // Add the data to be sent
447     virtio_net_hdr_t* tx_hdr = GetFrameHdr(bufs_.get(), kTxId, id);
448     memset(tx_hdr, 0, virtio_hdr_len_);
449 
450     // 5.1.6.2.1 Driver Requirements: Packet Transmission
451     //
452     // The driver MUST set num_buffers to zero.
453     //
454     // Implementation note: This field doesn't exist if neither
455     // |VIRTIO_F_VERSION_1| or |VIRTIO_F_MRG_RXBUF| have been negotiated. Since
456     // this field will be part of the payload without these features we elide
457     // the check as we know the memory is valid and will soon be overwritten
458     // with packet data.
459     tx_hdr->num_buffers = 0;
460 
461     // If VIRTIO_NET_F_CSUM is not negotiated, the driver MUST set flags to
462     // zero and SHOULD supply a fully checksummed packet to the device.
463     tx_hdr->flags = 0;
464 
465     // If none of the VIRTIO_NET_F_HOST_TSO4, TSO6 or UFO options have been
466     // negotiated, the driver MUST set gso_type to VIRTIO_NET_HDR_GSO_NONE.
467     tx_hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
468 
469     void* tx_buf = GetFrameData(bufs_.get(), kTxId, id, virtio_hdr_len_);
470     memcpy(tx_buf, data, length);
471     desc->len = static_cast<uint32_t>(virtio_hdr_len_ + length);
472 
473     // Submit the descriptor and notify the back-end.
474     LTRACE_DO(virtio_dump_desc(desc));
475     LTRACEF("Sending %zu bytes:\n", length);
476     LTRACE_DO(hexdump8_ex(tx_buf, length, 0));
477     tx_.SubmitChain(id);
478     ++unkicked_;
479     if ((options & ETHMAC_TX_OPT_MORE) == 0 || unkicked_ > kBacklog / 2) {
480         tx_.Kick();
481         unkicked_ = 0;
482     }
483     return ZX_OK;
484 }
485 
486 } // namespace virtio
487