/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: IntelRxRingBuffer.cs // // Notes: // // Adaptor class for the Rx ring buffer. // using Microsoft.Contracts; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Io; using Microsoft.Singularity.Io.Net; using Microsoft.Singularity.V1.Services; using Microsoft.SingSharp; using System; namespace Microsoft.Singularity.Drivers.Network.Intel { internal class IntelRxRingBuffer { IntelRingBuffer! rxRingBuffer; ExRef! rxPacketsInDevice; internal IntelRxRingBuffer(uint capacity) requires capacity > 0 && IntelRingBuffer.IsPowerOf2(capacity); { this.rxRingBuffer = new IntelRingBuffer(capacity); this.rxPacketsInDevice = new ExRef( new [ExHeap] PacketFifo((int) capacity), false ); } internal void Reset() { rxRingBuffer.Reset(); } /////////////////////////////////////////////////////////////////////// // // Buffer Operations, should only be called when a lock is held // this ring buffer. // private void LockedPushRecvBuffer(UIntPtr packetVirtAddr, int length) { PlatformService.InvalidateDCache(packetVirtAddr, (UIntPtr)length); ulong controlBits = (ulong) ByteOrder.HostToLittleEndian(length); rxRingBuffer.Push(packetVirtAddr, controlBits); } static int pass = 0; internal void LockedPushRecvBuffer([Claims]Packet*! in ExHeap packet) { DebugStub.Assert(packet->FragmentCount == 1); DebugStub.Assert(!rxRingBuffer.IsFull); UIntPtr address; int length; packet->GetFragmentRange(0, out address, out length); this.LockedPushRecvBuffer(address, length); PacketFifo*! in ExHeap liveFifo = (!)this.rxPacketsInDevice.Acquire(); liveFifo->Push(packet); rxPacketsInDevice.Release(liveFifo); } internal void Dump() { rxRingBuffer.Dump("rx", 8); } private FromDeviceFlags GetRecvPktFlags(uint stat_err_flags) { FromDeviceFlags fromDevFlags = 0; if (((RxErrStatFields.CRC_ERROR | RxErrStatFields.SYMBOL_ERROR | RxErrStatFields.SEQUENCE_ERROR | RxErrStatFields.CARRIER_EXT_ERROR | RxErrStatFields.RX_DATA_ERROR) & stat_err_flags) != 0) { Intel.DebugPrint("Packet Rsv Error\n"); fromDevFlags |= FromDeviceFlags.ReceiveError; } else { fromDevFlags |= FromDeviceFlags.ReceiveSuccess; } if (((stat_err_flags & RxErrStatFields.IGNORE_CHECKSUM) == 0) && ((stat_err_flags & RxErrStatFields.IP_CHECKSUM_CALC) != 0)) { if ((stat_err_flags & RxErrStatFields.IP_CHECKSUM_ERROR) != 0) { Intel.DebugPrint("Bad Ip Checksum\n"); fromDevFlags |= FromDeviceFlags.BadIp4Checksum; } else { // Good IP checksum flag??? } } if (((stat_err_flags & RxErrStatFields.IGNORE_CHECKSUM) == 0) && ((stat_err_flags & RxErrStatFields.TCP_CHECKSUM_CALC)!= 0)) { if ((stat_err_flags & RxErrStatFields.TCP_CHECKSUM_ERROR) != 0) { fromDevFlags |= (FromDeviceFlags.BadTcp4Checksum | FromDeviceFlags.BadUdp4Checksum); // don't know if UDP or TCP Intel.DebugPrint("Bad TCP/UDP Checksum\n"); } else { fromDevFlags |= (FromDeviceFlags.GoodTcp4Checksum | FromDeviceFlags.GoodUdp4Checksum); } } DebugStub.Assert((fromDevFlags == (FromDeviceFlags.ReceiveSuccess)) || (fromDevFlags == (FromDeviceFlags.ReceiveSuccess | FromDeviceFlags.GoodTcp4Checksum | FromDeviceFlags.GoodUdp4Checksum))); return fromDevFlags; } private Packet*! in ExHeap MakePacketFromDescriptor(UIntPtr fragmentVirtAddr, ulong controlBits) { PacketFifo*! in ExHeap inDevPkts = rxPacketsInDevice.Acquire(); Packet*! in ExHeap packet = inDevPkts->Pop(); int length = (int) ((controlBits & RxDescriptor.LENGTH_MASK) >> RxDescriptor.LENGTH_SHIFT); uint stat_err = (uint) ((controlBits & RxDescriptor.ERR_STAT_MASK) >> RxDescriptor.ERR_STAT_SHIFT); // can't deal with fragments yet DebugStub.Assert((stat_err & RxErrStatFields.END_OF_PACKET) != 0); DebugStub.Assert(packet->GetFragmentVirtualAddress(0) == fragmentVirtAddr); packet->FromDeviceFlags = GetRecvPktFlags(stat_err); packet->SetFragmentLength(0, length); rxPacketsInDevice.Release(inDevPkts); return packet; } internal void LockedDrainRecvBuffer(PacketFifo*! in ExHeap toUser) { UIntPtr fragmentVirtAddr; ulong controlBits; while (rxRingBuffer.Peek(out fragmentVirtAddr, out controlBits)) { Packet*! in ExHeap packet = MakePacketFromDescriptor(fragmentVirtAddr, controlBits); toUser->Push(packet); rxRingBuffer.Pop(); } } /////////////////////////////////////////////////////////////////////// // // Ring buffer properties // internal UIntPtr BaseAddress { get { return rxRingBuffer.BaseAddress; } } [Pure] internal uint Capacity { get { return rxRingBuffer.Capacity; } } [Pure] internal uint Free { get { return rxRingBuffer.Free; } } [Pure] internal bool IsFull { get { return rxRingBuffer.IsFull; } } [Pure] internal uint Count { get { return rxRingBuffer.Count; } } [Pure] internal uint Tail { get { return rxRingBuffer.Tail; } } [Pure] internal uint Head { get { return rxRingBuffer.Head; } } [Pure] internal uint DescLength { get { return rxRingBuffer.DescLength; } } } }