Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Model of BM DMA network card for QEMU

20 views
Skip to first unread message

wz...@ise.pw.edu.pl

unread,
Apr 6, 2012, 7:09:41 PM4/6/12
to
Model of the network card with bus mastering DMA for QEMU.
Sources are published as PUBLIC DOMAIN. No warranty at all.
Sources were prepared for qemu 0.14.


#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.11).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh06732
# Made on 2012-04-07 01:05 CEST by <wzab@WZLap>.
# Source directory was `/home/wzab/tmp/wz_nic'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 530 -rw-r--r-- wzab_enc1.h
# 22545 -rw-r--r-- wzab_nic1.c
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false

for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done

if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done

if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'

else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU `touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= wzab_enc1.h ==============
if test -n "${keep_file}" && test -f 'wzab_enc1.h'
then
${echo} "x - SKIPPING wzab_enc1.h (file already exists)"
else
${echo} "x - extracting wzab_enc1.h (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wzab_enc1.h' &&
//Definitions of 32-bit registers
#define WZENC1_NOF_PAGES 4
typedef struct WzEnc1Page {
X uint32_t PhysAddr;
X uint32_t Offset;
X uint32_t Length;
} WzEnc1Page;
X
typedef struct WzEnc1Regs {
X uint32_t Ctrl;
X uint32_t Status;
X WzEnc1Page Pages[WZENC1_NOF_PAGES];
} WzEnc1Regs;
X
X
//Commands
#define ENC1_CMD_DECR 1
#define ENC1_CMD_ENCR 2
#define ENC1_CMD_DATA 3
#define ENC1_CMD_STOP 4
#define ENC1_CMD_ENAIRQ 5
#define ENC1_CMD_DISIRQ 6
#define ENC1_CMD_ACKIRQ 7
X
//Errors
#define ENC1_ERR_NOTINIT 1
#define ENC1_ERR_BUSY 2
X
X
SHAR_EOF
(set 20 11 06 16 13 16 00 'wzab_enc1.h'
eval "${shar_touch}") && \
chmod 0644 'wzab_enc1.h'
if test $? -ne 0
then ${echo} "restore of wzab_enc1.h failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wzab_enc1.h': 'MD5 check failed'
) << \SHAR_EOF
1bfb98c4cf516aaa9e539570047bd7bc wzab_enc1.h
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wzab_enc1.h'` -ne 530 && \
${echo} "restoration warning: size of 'wzab_enc1.h' is not 530"
fi
fi
# ============= wzab_nic1.c ==============
if test -n "${keep_file}" && test -f 'wzab_nic1.c'
then
${echo} "x - SKIPPING wzab_nic1.c (file already exists)"
else
${echo} "x - extracting wzab_nic1.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wzab_nic1.c' &&
/*
X * QEMU - Emulation of network adapter with Bus Mastering DMA and scattered packet buffers
X *
X * Copyright Wojciech M. Zabolotny ( wz...@ise.pw.edu.pl ) 17.06.2011
X *
X * Permission is hereby granted, free of charge, to any person obtaining a copy
X * of this software and associated documentation files (the "Software"), to deal
X * in the Software without restriction, including without limitation the rights
X * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
X * copies of the Software, and to permit persons to whom the Software is
X * furnished to do so, subject to the following conditions:
X *
X * The above copyright notice and this permission notice shall be included in
X * all copies or substantial portions of the Software.
X *
X * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
X * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
X * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
X * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
X * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
X * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
X * THE SOFTWARE.
X */
X
/* based on mipsnet.c taken from original QEMU sources */
X
//#define DEBUG_wzab1 1
#define MAX_ETH_FRAME_SIZE 1514
//PCI IDs below are not registred! Use only for experiments!
#define PCI_VENDOR_ID_WZAB 0xabba
#define PCI_DEVICE_ID_WZAB_WZNIC1 0x0232
X
//Simulated processing time
#define NIC1_PROCESSING_TIME 5000000
#include <string.h>
#include "hw.h"
#include "pci.h"
#include "net.h"
#include "qemu-timer.h"
#include "wzab_nic1.h"
#include <stdint.h>
X
#define min(x,y) ((x<y) ? x : y)
/*
X Description of functionalities.
X The emulated hardware is a network adapter working with packet buffers
X located in the host's memory.
X There are two packet buffers - transmit buffer and receive buffer.
X Each of them may span across several pages.
X
X Packet buffers are served as circular buffers.
X Each packet is stored in a special form, allowing to separate individual
X packets:
X A. Header:
X 1. Packet magic number
X 2. Packet length (including the header and the contents)
X 3. Packet flags (not used yet)
X B. Packet contents
X
X Packet transmission:
X Driver writes the packet to the packet buffer. After the packet is stored,
X the driver updates the head pointer in the Tx packet buffer.
*/
/* Structure used as a pointer to data in Tx/Rx buffers */
typedef struct
{
X int page;
X int offset; //in 32 bit words!
} WzNic1Ptr;
X
typedef struct WzNic1State
{
X PCIDevice dev;
X union
X {
X WzNic1Regs r;
X uint32_t u32[sizeof ( WzNic1Regs ) /sizeof ( uint32_t ) ];
X } regs;
X WzNic1Ptr Tx_Tail;
X WzNic1Ptr Tx_Head;
X WzNic1Ptr Rx_Tail;
X WzNic1Ptr Rx_Head;
X uint32_t wz_nic1_mmio_io_addr;
X QEMUTimer * timer;
X NICState *nic;
X NICConf conf;
unsigned int Error:
X 1;
unsigned int TxCorruptedBuffer:
X 1 ;
unsigned int Tx_Irq_Enabled :
X 1;
unsigned int Rx_Irq_Enabled :
X 1;
unsigned int Rx_Enabled :
X 1;
unsigned int tx_irq_pending :
X 1;
unsigned int rx_irq_pending :
X 1;
unsigned int irq_pending :
X 1;
unsigned int promiscous :
X 1;
} WzNic1State;
X
//Some prototypes...
uint32_t wz_nic1_mem_readl ( void *opaque, target_phys_addr_t addr );
void wz_nic1_mem_writel ( void *opaque, target_phys_addr_t addr, uint32_t val );
int wz_nic1_init ( PCIBus *bus );
void wz_nic1_send_packets ( WzNic1State * s );
void wz_nic1_update_irq(WzNic1State * s);
static NetClientInfo wz_nic1_nc_info;
X
X
static void wz_nic1_reset ( WzNic1State *s )
{
X memset ( ( void * ) s->regs.u32,0,sizeof ( s->regs.u32 ) );
#ifdef DEBUG_wzab1
X printf ( "wzab_nic1 reset!\n" );
#endif
}
X
/* called for read accesses to our register memory area */
uint32_t wz_nic1_mem_readl ( void *opaque, target_phys_addr_t addr )
{
X int i_addr;
#ifdef DEBUG_wzab1
X printf ( "Memory read: address %x\n ", ( unsigned int ) addr );
#endif
X WzNic1State *s = opaque;
X if ( addr>=sizeof ( WzNic1Regs ) )
X {
X //Read above registers area - return "0xbada4ea" to show it
X return 0xbada4ea;
X }
X else if ( addr == offsetof ( WzNic1Regs, Status ) )
X {
X //Reading of the Status - synthesize the correct value
X uint32_t res = s->Error & 0xffff ; //Lower 16 bits!
X if ( s->irq_pending ) res |= NIC1_ST_IRQ;
X if ( s->tx_irq_pending ) res |= NIC1_ST_TX_IRQ;
X if ( s->Tx_Irq_Enabled ) res |= NIC1_ST_TX_IRQ_ENA;
X if ( s->rx_irq_pending ) res |= NIC1_ST_RX_IRQ;
X if ( s->Rx_Irq_Enabled ) res |= NIC1_ST_RX_IRQ_ENA;
X if ( s->promiscous ) res |= NIC1_ST_PROMISCOUS;
X //
X if (s->Rx_Enabled) res |= NIC1_ST_ENA_RX;
X if (s->TxCorruptedBuffer) res |= NIC1_ST_TX_COR_BUF;
X if (s->Error) res |= NIC1_ST_ERROR;
#ifdef DEBUG_wzab1
X printf ( "Status=%d\n",res );
#endif
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, RxTail ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = s->Rx_Tail.offset+(s->Rx_Tail.page<<10);
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, RxHead ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = s->Rx_Head.offset+(s->Rx_Head.page<<10);
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, RxNumOfBytes ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = WZNIC1_NOF_RX_PAGES * 4096;
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, TxTail ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = s->Tx_Tail.offset+(s->Tx_Tail.page<<10);
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, TxHead ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = s->Tx_Head.offset+(s->Tx_Head.page<<10);
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, TxNumOfBytes ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = WZNIC1_NOF_TX_PAGES * 4096;
X qemu_mutex_unlock_iothread();
X return res;
X }
X else
X {
X i_addr = addr/4;
X //Read the register
X return s->regs.u32[i_addr];
X }
}
X
/* Function used to dereference bytes/words in the Tx buffer */
static inline uint32_t tx_buf_addr ( WzNic1State *s, WzNic1Ptr ptr )
{
X return ( s->regs.r.TxPages[ptr.page].PhysAddr ) +4* ( ptr.offset );
}
X
static inline void tx_increase_ptr ( WzNic1State *s, WzNic1Ptr * ptr )
{
X int tmp = ptr->offset + 1;
X if ( tmp>=1024 )
X {
X tmp -= 1024;
X ptr->page ++;
X if ( ptr->page >= WZNIC1_NOF_TX_PAGES )
X ptr->page= ptr->page % WZNIC1_NOF_TX_PAGES;
X }
X ptr->offset = tmp;
}
X
static inline void tx_add_ptr (WzNic1State *s, WzNic1Ptr * ptr, uint32_t val)
{
X uint32_t tmp = ptr->offset+val;
X uint32_t npages = tmp >> 10; //Number of pages
X ptr->offset = tmp & 0x3ff; //lower 10 bits, as pages are 4096 bytes long
X ptr->page = (ptr->page + npages) % WZNIC1_NOF_TX_PAGES;
}
X
/* Function used to dereference bytes/words in the Rx buffer */
static inline uint32_t rx_buf_addr ( WzNic1State *s, WzNic1Ptr ptr )
{
X return ( s->regs.r.RxPages[ptr.page].PhysAddr ) +4* ( ptr.offset );
}
X
static inline void rx_increase_ptr ( WzNic1State *s, WzNic1Ptr * ptr )
{
X int tmp = ptr->offset + 1;
X if ( tmp>=1024 )
X {
X tmp -= 1024;
X ptr->page ++;
X if ( ptr->page >= WZNIC1_NOF_RX_PAGES )
X ptr->page= ptr->page % WZNIC1_NOF_RX_PAGES;
X }
X ptr->offset = tmp;
}
X
static inline void rx_add_ptr (WzNic1State *s, WzNic1Ptr * ptr, uint32_t val)
{
X uint32_t tmp = ptr->offset+val;
X uint32_t npages = tmp >> 10; //Number of pages
X ptr->offset = tmp & 0x3ff; //lower 10 bits, as pages are 4096 bytes long
X ptr->page = (ptr->page + npages) % WZNIC1_NOF_RX_PAGES;
}
X
static inline uint32_t rx_buf_space(WzNic1State *s)
{
X const uint32_t num_of_bytes = WZNIC1_NOF_RX_PAGES*4096;
X int space;
X qemu_mutex_lock_iothread();
X int head = s->Rx_Head.page*4096+s->Rx_Head.offset*4;
X int tail = s->Rx_Tail.page*4096+s->Rx_Tail.offset*4;
X qemu_mutex_unlock_iothread();
X space = tail-head;
X if (space <= 0) space += num_of_bytes;
X space --;
X return space;
}
/* Procedure sending the packets from the Tx buffer */
void wz_nic1_send_packets ( WzNic1State * s )
{
X //Check if there is anything to send
X //We have a few options to send the packets
X //either we send all packets immediately, or we simulate delay associated
X //with sending of packets
X /* Sending of all packets at the same time is easier */
X while (1)
X {
X //There is something to send
X //Check the header
X WzNic1Ptr ptr;
X uint32_t flags, tmp;
X int bptr;
X uint32_t len_in_bytes; //Length of the packet without the header
X uint32_t len_in_u32; //Length of the packet in 32-bit words
X int niov; //Number of iovecs to send the packet
X qemu_mutex_lock_iothread();
X if ((s->Tx_Tail.offset == s->Tx_Head.offset) &&
X (s->Tx_Tail.page == s->Tx_Head.page)) {
X qemu_mutex_unlock_iothread();
X return; //No more packets to send
X }
X memcpy ( &ptr,&s->Tx_Tail,sizeof ( ptr ) );
X qemu_mutex_unlock_iothread();
X bptr = tx_buf_addr ( s, ptr );
X cpu_physical_memory_read(bptr,&tmp,4);
X if (tmp != WZNIC1_PKT_MAGIC_NUMBER )
X {
X s->TxCorruptedBuffer = 1;
X s->Error = 1;
X //Error - set the error flag and return
X return;
X }
X //Take the packet length in bytes
X tx_increase_ptr ( s,&ptr );
X cpu_physical_memory_read(tx_buf_addr ( s,ptr ),&len_in_bytes,4);
X len_in_u32 = ( len_in_bytes+3 ) >>2;
X tx_increase_ptr ( s,&ptr );
X //Take the flags
X cpu_physical_memory_read(tx_buf_addr ( s,ptr ),&flags,4);
X //Mark the packet as serviced
X {
X //To be done!!!
X }
X tx_increase_ptr ( s,&ptr );
X //Now the pointer points to the first word containing the packet data
X //Send the packet
X {
X //Allocate temporary buffer on stack (hmmm... is it safe for long buffers?)
X uint32_t pkt_buf[len_in_u32];
X int len = len_in_bytes;
X int i=0;
X while (len>0) {
X //Copy the whole world
X cpu_physical_memory_read(tx_buf_addr ( s,ptr ),&pkt_buf[i],4);
X tx_increase_ptr ( s,&ptr );
X len -= 4;
X i++;
X }
X if(0){
X int i;
X printf("send: ");
X for(i=0;i<10;i++) printf("%2.2x ",(int) pkt_buf[i]);
X printf("\n");
X }
X qemu_send_packet ( &s->nic->nc, pkt_buf, len_in_bytes);
X }
X /*
X * The code below could be nice and efficient, but requires
X * use of cpu_physical_memory_map,
X //Send the packet using the iovec
X //Calculate the number of iovecs needed to send
X niov = ( 4*ptr.offset + len_in_bytes + 0xfff ) >>12;
X {
X struct iovec iov[niov]; //Use the GCC extension - dynamic allocation on stack
X //Fill the iovec structures
X int bytes_left = len_in_bytes;
X int offs=ptr.offset;
X int i;
X for ( i=0;i<niov;i++ )
X {
X iov[i].iov_base = s->regs.r.TxPages[ ( ptr.page+i ) % WZNIC1_NOF_TX_PAGES].PhysAddr+offs;
X iov[i].iov_len = min ( 4096-offs,bytes_left );
X bytes_left -= min ( 4096-offs,bytes_left );
X offs=0;
X }
X //After this loop our packet is ready, so transmit it!
X qemu_sendv_packet ( &s->nic->nc, iov, niov );
X //Finally update interrupts
X wz_nic1_update_irq ( s );
X }
X */
X qemu_mutex_lock_iothread();
X memcpy ( &s->Tx_Tail,&ptr,sizeof ( ptr ) );
X qemu_mutex_unlock_iothread();
X wz_nic1_update_irq(s);
X }
X return;
}
X
static int wz_nic1_buffer_full ( WzNic1State *s )
{
X //Calculate the amount of free buffer
X
X if ( rx_buf_space(s) <= MAX_ETH_FRAME_SIZE+20 )
X return 1;
X return 0;
}
X
static int wz_nic1_can_receive ( VLANClientState *nc )
{
X WzNic1State *s = DO_UPCAST ( NICState, nc, nc )->opaque;
X if (s->Rx_Enabled==0) return 0;
X return !wz_nic1_buffer_full ( s );
}
X
static ssize_t wz_nic1_receive ( VLANClientState *nc, const uint8_t *buf, size_t size )
{
X WzNic1State *s = DO_UPCAST ( NICState, nc, nc )->opaque;
X
X if ( !wz_nic1_can_receive ( nc ) )
X return -1;
#ifdef DEBUG_wzab1
X printf ( "wz_nic1: receiving len=%zu\n", size );
#endif
X
X /* Just accept everything. */
X {
X WzNic1Ptr ptr;
X int bptr;
X size_t tmp_size;
X uint32_t tmp;
X int i;
X memcpy ( &ptr,&s->Rx_Head,sizeof ( ptr ) );
X bptr = rx_buf_addr ( s, ptr ); //To jest adres w maszynie wirtualnej!!!
X tmp = WZNIC1_PKT_MAGIC_NUMBER;
X cpu_physical_memory_write(bptr,&tmp,4);
X /* Write packet header */
X //We are already sure, that the packet will fit
X rx_increase_ptr ( s,&ptr );
X bptr = rx_buf_addr (s, ptr );
X cpu_physical_memory_write(bptr,&size,4); //Length of the packet
X rx_increase_ptr ( s, &ptr );
X bptr = rx_buf_addr (s, ptr );
X tmp = 0 ; //Flags - @@ to be corrected!
X cpu_physical_memory_write(bptr,&tmp,4); //Flags of the packet
X rx_increase_ptr ( s, &ptr );
X //Now we can copy the data
X tmp_size = size;
X while ( tmp_size >= 4 )
X {
X bptr = rx_buf_addr (s, ptr );
X cpu_physical_memory_write(bptr,buf,4); //Contents of the packet
X rx_increase_ptr ( s, &ptr );
X tmp_size -= 4;
X buf+=4;
X }
X //Last part of the buffer must be copied byte by byte...
X //We are working on a LE platform, so we can handle it as follows:
X if (tmp_size) {
X //First we have to check if such "remainder" exists...
X tmp = 0;
X i=0;
X while (tmp_size) {
X tmp |= ((uint32_t) *buf) << (8*i);
X i++;
X buf++;
X tmp_size--;
X }
X bptr = rx_buf_addr (s, ptr );
X cpu_physical_memory_write(bptr,&tmp,4); //Rest of the content of the packet
X //OK. The whole packet is stored, so now we have to update the pointer
X rx_increase_ptr ( s, &ptr );
X }
X qemu_mutex_lock_iothread();
X memcpy ( &s->Rx_Head, &ptr, sizeof ( ptr ) );
X qemu_mutex_unlock_iothread();
X }
X wz_nic1_update_irq( s );
X return size;
}
X
X
/* called for write accesses to our register memory area */
void wz_nic1_mem_writel ( void *opaque, target_phys_addr_t addr, uint32_t val )
{
X WzNic1State *s = opaque;
X int i_addr;
#ifdef DEBUG_wzab1
X printf ( "wzab1: zapis pod adres = 0x%08x, 0x%08x\n", ( unsigned int ) addr, val );
#endif
X /* Check which register is accessed */
X if ( addr>=sizeof ( WzNic1Regs ) )
X {
X //Write above registers area - ignore it!
X }
X else
X {
X i_addr = addr/4;
X //Write the value
X s->regs.u32[i_addr]=val;
X //Interprete its special meaning
X if (addr==offsetof (WzNic1Regs,RxTail))
X {
X uint32_t tmp;
X qemu_mutex_lock_iothread();
X s->Rx_Tail.offset=val & 0x3ff;
X tmp=val >> 10;
X if (tmp >= WZNIC1_NOF_RX_PAGES) tmp = 0;
X s->Rx_Tail.page = tmp;
X qemu_mutex_unlock_iothread();
X }
X if (addr==offsetof (WzNic1Regs,TxHead))
X {
X uint32_t tmp;
X qemu_mutex_lock_iothread();
X s->Tx_Head.offset=val & 0x3ff;
X tmp=val >> 10;
X if (tmp >= WZNIC1_NOF_TX_PAGES) tmp = 0;
X s->Tx_Head.page = tmp;
X qemu_mutex_unlock_iothread();
X }
X if ( addr==offsetof ( WzNic1Regs,Ctrl ) )
X {
X //Write to control register - we need to check what operation is required
X switch ( val )
X {
X case NIC1_CMD_ENA_TX_IRQ:
X s->Tx_Irq_Enabled = 1;
X break;
X case NIC1_CMD_DIS_TX_IRQ:
X s->Tx_Irq_Enabled = 0;
X break;
X case NIC1_CMD_ENA_RX_IRQ:
X s->Rx_Irq_Enabled = 1;
X break;
X case NIC1_CMD_DIS_RX_IRQ:
X s->Rx_Irq_Enabled = 0;
X break;
X case NIC1_CMD_ENA_RX:
X s->Rx_Enabled = 1;
X break;
X case NIC1_CMD_DIS_RX:
X s->Rx_Enabled = 0;
X break;
X case NIC1_CMD_SEND:
X wz_nic1_send_packets(s);
X break;
X case NIC1_CMD_CLEAR:
X s->Rx_Enabled = 0;
X s->TxCorruptedBuffer = 0;
X s->Error = 0;
X s->Rx_Tail.offset=0;
X s->Rx_Tail.page=0;
X s->Rx_Head.offset=0;
X s->Rx_Head.page=0;
X s->Tx_Tail.offset=0;
X s->Tx_Tail.page=0;
X s->Tx_Head.offset=0;
X s->Tx_Head.page=0;
X break;
X case NIC1_CMD_ENA_PROMISCOUS:
X s->promiscous = 1;
X break;
X case NIC1_CMD_DIS_PROMISCOUS:
X s->promiscous = 0;
X break;
X
X }
X }
X }
X wz_nic1_update_irq(s);
}
X
/* The procedure below performs the real encryption, after simulated processing time is expired */
static void wzab1_tick ( void *opaque )
{
X WzNic1State * s = opaque;
X //Encrypt the data
X {
X }
#ifdef DEBUG_wzab1
X printf ( "Data processed - request IRQ!\n" );
#endif
X
}
X
X
static void wz_nic1_map ( PCIDevice *pci_dev, int region_num,
X pcibus_t addr, pcibus_t size, int type )
{
X WzNic1State *s = DO_UPCAST ( WzNic1State, dev, pci_dev );
X
X ( void ) region_num;
X ( void ) size;
X ( void ) type;
X
X cpu_register_physical_memory ( addr,size,s->wz_nic1_mmio_io_addr );
}
X
X
/* We handle only 32-bit accesses! */
CPUReadMemoryFunc * const wz_nic1_mmio_read[3] =
{
X NULL,
X NULL,
X wz_nic1_mem_readl,
};
X
/* We handle only 32-bit accesses! */
CPUWriteMemoryFunc * const wz_nic1_mmio_write[3] =
{
X NULL,
X NULL,
X wz_nic1_mem_writel,
};
X
//Sorry, but the state description below is not complete!
//You are free to fix it!
static const VMStateDescription vmstate_wz_nic1 =
{
X .name = "wz_nic1",
X .version_id = 2,
X .minimum_version_id = 2,
X .minimum_version_id_old = 2,
X .fields = ( VMStateField [] )
X {
X VMSTATE_PCI_DEVICE ( dev, WzNic1State ),
X VMSTATE_TIMER ( timer,WzNic1State ),
X VMSTATE_END_OF_LIST()
X }
};
X
static void wz_nic1_on_reset ( void *opaque )
{
X WzNic1State *s = opaque;
X wz_nic1_reset ( s );
}
X
static int wz_nic1_initfn ( PCIDevice *dev )
{
X WzNic1State *s = DO_UPCAST ( WzNic1State, dev, dev );
X uint8_t *c = s->dev.config;
X s->Rx_Irq_Enabled=0;
X s->Tx_Irq_Enabled=0;
X s->Rx_Enabled=0;
X s->Rx_Head.offset=0;
X s->Rx_Head.page=0;
X s->Rx_Tail.offset=0;
X s->Rx_Tail.page=0;
X s->Tx_Head.offset=0;
X s->Tx_Head.page=0;
X s->Tx_Tail.offset=0;
X s->Tx_Tail.page=0;
X s->Error=0;
X s->TxCorruptedBuffer=0;
X //Set values in the configuration space
X pci_config_set_vendor_id ( c, PCI_VENDOR_ID_WZAB );
X pci_config_set_device_id ( c, PCI_DEVICE_ID_WZAB_WZNIC1 );
X pci_config_set_class ( c, PCI_CLASS_NETWORK_ETHERNET );
X
X /* TODO: RST# value should be 0. */
X c[PCI_INTERRUPT_PIN] = 1;
X //Register memory mapped registers
X s->wz_nic1_mmio_io_addr = cpu_register_io_memory ( wz_nic1_mmio_read, wz_nic1_mmio_write,
X s, DEVICE_LITTLE_ENDIAN );
X pci_register_bar ( &s->dev, 0, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY, wz_nic1_map );
X qemu_register_reset ( wz_nic1_on_reset, s );
X qemu_macaddr_default_if_unset(&s->conf.macaddr);
X s->nic = qemu_new_nic(&wz_nic1_nc_info, &s->conf,
X dev->qdev.info->name, dev->qdev.id, s);
X qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
X //Register timer used to simulate processing time
X s->timer = qemu_new_timer ( vm_clock, wzab1_tick, s );
X wz_nic1_reset ( s );
X return 0;
}
X
void wz_nic1_update_irq(WzNic1State * s)
{
X //Check Tx interrupt
X s->irq_pending = 0;
X qemu_mutex_lock_iothread();
X if ((s->Tx_Head.page==s->Tx_Tail.page) && (s->Tx_Head.offset==s->Tx_Tail.offset))
X s->tx_irq_pending = 1;
X else
X s->tx_irq_pending = 0;
X qemu_mutex_unlock_iothread();
X //Check Rx interrupt
X qemu_mutex_lock_iothread();
X if ((s->Rx_Head.page==s->Rx_Tail.page) && (s->Rx_Head.offset==s->Rx_Tail.offset))
X s->rx_irq_pending = 0;
X else
X s->rx_irq_pending = 1;
X qemu_mutex_unlock_iothread();
X if (s->Rx_Irq_Enabled && s->rx_irq_pending)
X s->irq_pending |= 1;
X if (s->Tx_Irq_Enabled && s->tx_irq_pending)
X s->irq_pending |= 1;
X if (s->irq_pending)
X qemu_irq_raise(s->dev.irq[0]);
X else
X qemu_irq_lower(s->dev.irq[0]);
}
X
static void wz_nic1_cleanup(VLANClientState *nc)
{
X struct WzNic1State *s = DO_UPCAST(NICState, nc, nc)->opaque;
X
X s->nic = NULL;
}
X
static NetClientInfo wz_nic1_nc_info = {
X .type = NET_CLIENT_TYPE_NIC,
X .size = sizeof(NICState),
X .can_receive = wz_nic1_can_receive,
X .receive = wz_nic1_receive,
X .cleanup = wz_nic1_cleanup,
};
X
X
int wz_nic1_init ( PCIBus *bus )
{
X pci_create_simple ( bus, -1, "WZNIC1" );
X return 0;
}
X
static PCIDeviceInfo wz_nic1_info =
{
X .qdev.name = "WZNIC1",
X .qdev.desc = "WZNIC1 - Model of network adapter card",
X .qdev.size = sizeof ( WzNic1State ),
X .qdev.vmsd = &vmstate_wz_nic1,
X .init = wz_nic1_initfn,
X .qdev.props = (Property[]) {
X DEFINE_NIC_PROPERTIES(WzNic1State, conf),
X DEFINE_PROP_END_OF_LIST(),
X }
};
X
X
static void wz_nic1_register ( void )
{
X pci_qdev_register ( &wz_nic1_info );
}
X
device_init ( wz_nic1_register );
X
SHAR_EOF
(set 20 12 04 07 01 04 49 'wzab_nic1.c'
eval "${shar_touch}") && \
chmod 0644 'wzab_nic1.c'
if test $? -ne 0
then ${echo} "restore of wzab_nic1.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wzab_nic1.c': 'MD5 check failed'
) << \SHAR_EOF
c99b6cde87428bd687959e943333d0ac wzab_nic1.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wzab_nic1.c'` -ne 22545 && \
${echo} "restoration warning: size of 'wzab_nic1.c' is not 22545"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0

wz...@ise.pw.edu.pl

unread,
Apr 6, 2012, 7:50:13 PM4/6/12
to
Below are the PUBLIC DOMAIN sources of the model of network adapter for qemu 0.14
The previous post contained incorrect header file: wzab_enc1.h instaed of wzab_nic1.h
The model should be integrated with qemu by copying into "hw" directory.

Additionally in thr Makefile.target youshould add the line:
# Hardware support
obj-i386-y += wzab_nic1.o #<= added line!!!
obj-i386-y += vga.o
obj-i386-y += mc146818rtc.o i8259.o pc.o

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.11).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh03917
# Made on 2012-04-07 01:41 CEST by <wzab@WZLap>.
# Source directory was `/home/wzab/tmp/wz_nic'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 22545 -rw-r--r-- wzab_nic1.c
# 1274 -rw-r--r-- wzab_nic1.h
# ============= wzab_nic1.h ==============
if test -n "${keep_file}" && test -f 'wzab_nic1.h'
then
${echo} "x - SKIPPING wzab_nic1.h (file already exists)"
else
${echo} "x - extracting wzab_nic1.h (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wzab_nic1.h' &&
//Definitions of 32-bit registers
#define WZNIC1_NOF_TX_PAGES 4
#define WZNIC1_NOF_RX_PAGES 4
typedef struct {
X uint32_t PhysAddr;
} WzNic1Page;
X
typedef struct {
X uint32_t MAC_L;
X uint32_t MAC_H;
X uint32_t Ctrl;
X uint32_t Status;
X uint32_t RxHead;
X uint32_t RxTail;
X uint32_t RxNumOfBytes;
X uint32_t TxHead;
X uint32_t TxTail;
X uint32_t TxNumOfBytes;
X WzNic1Page TxPages[WZNIC1_NOF_TX_PAGES];
X WzNic1Page RxPages[WZNIC1_NOF_RX_PAGES];
} WzNic1Regs;
X
#define WZNIC1_PKT_MAGIC_NUMBER (0xbcda1234)
typedef struct {
X uint32_t MagicNumber;
X uint32_t Length;
X uint32_t Flags;
} WzNic1_PktHeader;
//Commands
#define NIC1_CMD_ENA_TX_IRQ 1
#define NIC1_CMD_DIS_TX_IRQ 2
#define NIC1_CMD_ENA_RX_IRQ 3
#define NIC1_CMD_DIS_RX_IRQ 4
#define NIC1_CMD_ENA_RX 5
#define NIC1_CMD_DIS_RX 6
#define NIC1_CMD_SEND 7
#define NIC1_CMD_CLEAR 8
#define NIC1_CMD_ENA_PROMISCOUS 9
#define NIC1_CMD_DIS_PROMISCOUS 10
X
X
//Bit masks in the status registers
#define NIC1_ST_IRQ 0x8000
#define NIC1_ST_TX_IRQ 0x4000
#define NIC1_ST_TX_IRQ_ENA 0x2000
#define NIC1_ST_RX_IRQ 0x1000
#define NIC1_ST_RX_IRQ_ENA 0x0800
#define NIC1_ST_PROMISCOUS 0x0400
//
#define NIC1_ST_ENA_RX 0x0004
#define NIC1_ST_TX_COR_BUF 0x0002
#define NIC1_ST_ERROR 0x0001
//Errors
X
X
SHAR_EOF
(set 20 12 01 28 13 31 00 'wzab_nic1.h'
eval "${shar_touch}") && \
chmod 0644 'wzab_nic1.h'
if test $? -ne 0
then ${echo} "restore of wzab_nic1.h failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wzab_nic1.h': 'MD5 check failed'
) << \SHAR_EOF
2ffcca5ab9dc63379c64ed8ae2b61c02 wzab_nic1.h
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wzab_nic1.h'` -ne 1274 && \
${echo} "restoration warning: size of 'wzab_nic1.h' is not 1274"
0 new messages