public override bool InitServer() { System.Diagnostics.Debugger.Log(0, "pcnet32", "PCNET32 driver started"); while (Syscalls.ProcessFunctions.GetNet() == null) { ; } net = Syscalls.ProcessFunctions.GetNet() as net.INetInternal; /* Get our ports and interrupt */ foreach (var r in root) { if (r.Name == "interrupt" && (r.Value is tysos.Resources.InterruptLine)) { irq = r.Value as tysos.Resources.InterruptLine; } else if (r.Name == "vmem" && (r.Value is VirtualMemoryResource64)) { buf = r.Value as VirtualMemoryResource64; } } var pciconf = pci.PCIConfiguration.GetPCIConf(root); io = pciconf.GetBAR(0); if (io == null || irq == null || buf == null) { System.Diagnostics.Debugger.Log(0, "ata", "Insufficient resources provided"); return(false); } buf.Map(); System.Diagnostics.Debugger.Log(0, null, "Using " + io.ToString() + ", " + irq.ToString() + " and " + buf.ToString()); // Enable PCI IO space access uint c_04 = pciconf.ReadConfig(0x4); c_04 &= 0xffff0000U; c_04 |= 0x5; // IO space + bus mastering pciconf.WriteConfig(0x4, c_04); // Reset the controller - try both dword and word reads as we don't // know what mode the controller is currently in io.Read(io.Addr32 + 0x18, 4); io.Read(io.Addr32 + 0x14, 2); // wait 1 us - TODO: use timer for (int i = 0; i < 100000; i++) { ; } // Set DWORD mode io.Write(io.Addr32 + 0x10, 4, 0); // Read our MAC address uint mac03 = io.Read(io.Addr32 + 0x0, 4); uint mac47 = io.Read(io.Addr32 + 0x4, 4); hwaddr = new net.HWAddr(); byte[] mac = hwaddr.MAC; mac[0] = (byte)(mac03 & 0xff); mac[1] = (byte)((mac03 >> 8) & 0xff); mac[2] = (byte)((mac03 >> 16) & 0xff); mac[3] = (byte)((mac03 >> 24) & 0xff); mac[4] = (byte)(mac47 & 0xff); mac[5] = (byte)((mac47 >> 8) & 0xff); StringBuilder sb = new StringBuilder("MAC address: "); for (int i = 0; i < 6; i++) { if (i != 0) { sb.Append(":"); } sb.Append(mac[i].ToString("X2")); } System.Diagnostics.Debugger.Log(0, null, sb.ToString()); // Register interrupt handler irq.RegisterHandler(Interrupt); // Set SWSTYLE to 2 (PCnet-PCI II), 32 bit data accesses + addresses uint sstyle = ReadCSR(58); sstyle &= 0xfff0; sstyle |= 2; WriteCSR(58, sstyle); sstyle = ReadCSR(58); System.Diagnostics.Debugger.Log(0, null, "CSR58: " + sstyle.ToString("X4")); /* Set BCR2.ASEL to one (automatic link type detection - should * already be done by H_RESET, but force it to set incase firmware * has altered it). */ uint bcr2 = ReadBCR(2); bcr2 |= 0x2; WriteBCR(2, bcr2); /* Calculate how many buffers we can make */ ulong buf_size = 1548; // 1544 is used in linux - we round up to a multiple of 16 ulong rde_size = 16; ulong init_blk_size = 32; // actually 28, aligned to 16 bytes ulong buf_count = (buf.Length64 - init_blk_size) / (buf_size + rde_size); // split along the lines of 1 transmit buffer to 2 receive buffers ulong tx_count = buf_count / 3; // reduce it to be the greatest power of 2 less than current count int tx_bit_no = -1; for (int i = 31; i >= 0; i--) { if (((1UL << i) & tx_count) != 0) { tx_bit_no = i; break; } } if (tx_bit_no <= 0) { System.Diagnostics.Debugger.Log(0, null, "Insufficient buffer space provided"); return(false); } if (tx_bit_no > 9) { tx_bit_no = 9; } tx_count = 1UL << tx_bit_no; int rx_bit_no = tx_bit_no + 1; if (rx_bit_no > 9) { rx_bit_no = 9; } ulong rx_count = 1UL << rx_bit_no; System.Diagnostics.Debugger.Log(0, null, "Creating " + rx_count.ToString() + " receive buffers and " + tx_count.ToString() + " transmit buffers"); // set up ring buffers - see spec p. 62 uint rdra_offset; // Offset to start of receive ring buffer (within our own buffer) uint tdra_offset; // Offset to start of transmit ring buffer (within our own buffer) rdra_offset = (uint)init_blk_size; tdra_offset = (uint)(rdra_offset + rde_size * rx_count); uint rd_offset; // Offset to start of receive data uint td_offset; // Offset to start of transmit data rd_offset = (uint)(tdra_offset + rde_size * tx_count); td_offset = (uint)(rd_offset + buf_size * rx_count); rxbufs = new ReceiveRBE[(int)rx_count]; txbufs = new TransmitRBE[(int)tx_count]; for (int i = 0; i < (int)rx_count; i++) { rxbufs[i] = new ReceiveRBE(buf, (int)(rdra_offset + i * (int)rde_size), (int)(rd_offset + i * (int)buf_size), i, (int)buf_size); } for (int i = 0; i < (int)tx_count; i++) { txbufs[i] = new TransmitRBE(buf, (int)(tdra_offset + i * (int)rde_size), (int)(td_offset + i * (int)buf_size), i, (int)buf_size); } // Begin setting up the initialization block (p. 156 in spec) - SSIZE32 = 1 byte[] init_blk = buf.ToArray(); byte rlen = (byte)rx_bit_no; // RLEN = log2 of number of receive buffer entries (max = 9, i.e. 512 entries) byte tlen = (byte)tx_bit_no; // TLEN = log2 of number of receive buffer entries (max = 9, i.e. 512 entries) init_blk[0] = 0; // MODE = 0 init_blk[1] = 0; // MODE = 0 init_blk[2] = (byte)(0 | (rlen << 4)); // reserved / rlen init_blk[3] = (byte)(0 | (tlen << 4)); // reserved / tlen for (int i = 0; i < 6; i++) { init_blk[4 + i] = mac[i]; // PADR } init_blk[0xa] = 0; // reserved init_blk[0xb] = 0; // reserved for (int i = 0; i < 8; i++) { init_blk[0xc + i] = 0; // LADRF - disable logical addressing } byte[] rdra_arr = BitConverter.GetBytes(buf.MappedTo.Addr32 + rdra_offset); for (int i = 0; i < 4; i++) { init_blk[0x14 + i] = rdra_arr[i]; } byte[] tdra_arr = BitConverter.GetBytes(buf.MappedTo.Addr32 + tdra_offset); for (int i = 0; i < 4; i++) { init_blk[0x18 + i] = tdra_arr[i]; } // write init block address to CSR1 + 2 uint ibaddr = buf.MappedTo.Addr32; WriteCSR(1, ibaddr & 0xffffU); WriteCSR(2, (ibaddr >> 16) & 0xffffU); // mask out IDON interrupt, ensure little endian mode uint csr3 = (1U << 8); WriteCSR(3, csr3); // set automatic frame padding uint csr4 = ReadCSR(4); csr4 |= (1U << 11); WriteCSR(4, csr4); // set init and interrupt enable in CSR 0 uint csr0 = (1U << 0) | (1U << 6); WriteCSR(0, csr0); // poll until IDON set while ((csr0 & 1U << 8) == 0) { csr0 = ReadCSR(0); } // handle setting start and stop bits (CSR0) in separate Start/Stop functions root.Add(new File.Property { Name = "class", Value = "netdev" }); Tags.Add("class"); return(true); }
bool Interrupt() { uint csr0 = ReadCSR(0); uint csr4 = ReadCSR(4); uint ints = csr0; System.Diagnostics.Debugger.Log(0, "pcnet", "INTERRUPT: CSR0: " + csr0.ToString("X4") + ", CSR4: " + csr4.ToString("X4")); // Is RINT set? if ((ints & 0x0400) != 0) { /* Loop through those buffers we own */ int i = cur_rx_buf; do { ReceiveRBE b = rxbufs[i]; if (b.DriverOwns) { uint dlen = b.MCNT; ushort flags = b.Flags; System.Diagnostics.Debugger.Log(0, "pcnet", "Receive buffer " + i.ToString() + " has message of length " + dlen.ToString() + ", flags: " + flags.ToString("X4")); /* * byte[] d = b.Buffer; * StringBuilder sb = null; * for(uint j = 0; j < dlen; j++) * { * if((j % 8) == 0) * { * if (sb != null) * System.Diagnostics.Debugger.Log(0, "pcnet", sb.ToString()); * * sb = new StringBuilder(j.ToString("X4")); * sb.Append(":"); * } * * sb.Append(" "); * sb.Append(d[j].ToString("X2")); * } * if (sb != null) * System.Diagnostics.Debugger.Log(0, "pcnet", sb.ToString()); */ // Send the message to the net process if (b.Error == false) { byte[] msg = new byte[dlen]; for (uint j = 0; j < dlen; j++) { msg[j] = b.Buffer[j]; } net.PacketReceived(msg, dev_no, 0, msg.Length, null); } // reset the descriptor entry b.Reset(); } else { break; } i = next_rx_buf(i); } while (i != cur_rx_buf); // advance rx pointer cur_rx_buf = i; } // Mark all interrupts as handled csr0 |= 0x7f00; WriteCSR(0, csr0); csr4 |= 0x26a; WriteCSR(4, csr4); return(true); }