- ported Intel(R) 82540EM Gigabit Ethernet adapter emulation from Qemu

- TODO: add save/restore support, use Bochs function for host to little endian
  data conversion, timers of networking modules 'vnet' and 'slirp' should use
  the device speed instead of fixed 10 MBit
This commit is contained in:
Volker Ruppert 2011-12-13 20:53:44 +00:00
parent 51cf9faa12
commit 5045a241e8
11 changed files with 1717 additions and 38 deletions

View File

@ -1449,7 +1449,7 @@ void bx_init_options()
bx_list_c *network = new bx_list_c(root_param, "network", "Network Configuration");
network->set_options(network->USE_TAB_WINDOW | network->SHOW_PARENT);
// ne2k & pnic options
// networking module choices
static const char *eth_module_list[] = {
"null",
#if BX_NETMOD_LINUX
@ -1568,6 +1568,45 @@ void bx_init_options()
"none", BX_PATHNAME_LEN);
path->set_ask_format("Enter new script name, or 'none': [%s] ");
enabled->set_dependent_list(menu->clone());
// e1000 options
menu = new bx_list_c(network, "e1000", "Intel(R) Gigabit Ethernet");
menu->set_options(menu->SHOW_PARENT);
menu->set_enabled(BX_SUPPORT_E1000);
enabled = new bx_param_bool_c(menu,
"enabled",
"Enable Intel(R) Gigabit Ethernet emulation",
"Enables the Intel(R) Gigabit Ethernet emulation",
0);
enabled->set_enabled(BX_SUPPORT_E1000);
macaddr = new bx_param_string_c(menu,
"macaddr",
"MAC Address",
"MAC address of the Intel(R) Gigabit Ethernet. Don't use an address of a machine on your net.",
"", 6);
macaddr->set_options(macaddr->RAW_BYTES);
macaddr->set_initial_val("\xfe\xfd\xde\xad\xbe\xef");
macaddr->set_separator(':');
ethmod = new bx_param_enum_c(menu,
"ethmod",
"Ethernet module",
"Module used for the connection to the real net.",
eth_module_list,
0,
0);
ethmod->set_by_name("null");
ethmod->set_ask_format("Choose ethernet module for the Intel(R) Gigabit Ethernet [%s]");
new bx_param_string_c(menu,
"ethdev",
"Ethernet device",
"Device used for the connection to the real net. This is only valid if an ethernet module other than 'null' is used.",
"xl0", BX_PATHNAME_LEN);
path = new bx_param_filename_c(menu,
"script",
"Device configuration script",
"Name of the script that is executed after Bochs initializes the network interface (optional).",
"none", BX_PATHNAME_LEN);
path->set_ask_format("Enter new script name, or 'none': [%s] ");
enabled->set_dependent_list(menu->clone());
// sound subtree
bx_list_c *sound = new bx_list_c(root_param, "sound", "Sound Configuration");
@ -1837,7 +1876,7 @@ void bx_reset_options()
// serial/parallel/usb
SIM->get_param("ports")->reset();
// ne2k & pnic
// ne2k, pnic & e1000
SIM->get_param("network")->reset();
// SB16 & ES1370
@ -3417,6 +3456,50 @@ static int parse_line_formatted(const char *context, int num_params, char *param
SIM->get_param_bool("enabled", base)->set(0);
}
}
} else if (!strcmp(params[0], "e1000")) {
int tmp[6];
char tmpchar[6];
int valid = 0;
int n;
base = (bx_list_c*) SIM->get_param(BXPN_E1000);
if (!SIM->get_param_bool("enabled", base)->get()) {
SIM->get_param_enum("ethmod", base)->set_by_name("null");
}
for (i=1; i<num_params; i++) {
if (!strncmp(params[i], "enabled=", 8)) {
if (atol(&params[i][8]) == 0) valid |= 0x80;
} else if (!strncmp(params[i], "mac=", 4)) {
n = sscanf(&params[i][4], "%x:%x:%x:%x:%x:%x",
&tmp[0],&tmp[1],&tmp[2],&tmp[3],&tmp[4],&tmp[5]);
if (n != 6) {
PARSE_ERR(("%s: e1000 mac address malformed.", context));
}
for (n=0;n<6;n++)
tmpchar[n] = (unsigned char)tmp[n];
SIM->get_param_string("macaddr", base)->set(tmpchar);
valid |= 0x07;
} else if (!strncmp(params[i], "ethmod=", 7)) {
if (!SIM->get_param_enum("ethmod", base)->set_by_name(&params[i][7]))
PARSE_ERR(("%s: ethernet module '%s' not available", context, &params[i][7]));
} else if (!strncmp(params[i], "ethdev=", 7)) {
SIM->get_param_string("ethdev", base)->set(&params[i][7]);
} else if (!strncmp(params[i], "script=", 7)) {
SIM->get_param_string("script", base)->set(&params[i][7]);
} else {
PARSE_WARN(("%s: unknown parameter '%s' for e1000 ignored.", context, params[i]));
}
}
if (!SIM->get_param_bool("enabled", base)->get()) {
if (valid == 0x07) {
SIM->get_param_bool("enabled", base)->set(1);
} else if (valid < 0x80) {
PARSE_ERR(("%s: e1000 directive incomplete (mac is required)", context));
}
} else {
if (valid & 0x80) {
SIM->get_param_bool("enabled", base)->set(0);
}
}
} else if (!strcmp(params[0], "load32bitOSImage")) {
if ((num_params!=4) && (num_params!=5)) {
PARSE_ERR(("%s: load32bitOSImage directive: wrong # args.", context));
@ -3679,9 +3762,9 @@ int bx_write_usb_options(FILE *fp, int maxports, bx_list_c *base)
return 0;
}
int bx_write_pnic_options(FILE *fp, bx_list_c *base)
int bx_write_pci_nic_options(FILE *fp, bx_list_c *base)
{
fprintf (fp, "pnic: enabled=%d", SIM->get_param_bool("enabled", base)->get());
fprintf (fp, "%s: enabled=%d", base->get_name(), SIM->get_param_bool("enabled", base)->get());
if (SIM->get_param_bool("enabled", base)->get()) {
char *ptr = SIM->get_param_string("macaddr", base)->getptr();
fprintf (fp, ", mac=%02x:%02x:%02x:%02x:%02x:%02x, ethmod=%s, ethdev=%s, script=%s",
@ -4076,7 +4159,8 @@ int bx_write_configuration(const char *rc, int overwrite)
#endif
bx_write_clock_cmos_options(fp);
bx_write_ne2k_options(fp, (bx_list_c*) SIM->get_param(BXPN_NE2K));
bx_write_pnic_options(fp, (bx_list_c*) SIM->get_param(BXPN_PNIC));
bx_write_pci_nic_options(fp, (bx_list_c*) SIM->get_param(BXPN_PNIC));
bx_write_pci_nic_options(fp, (bx_list_c*) SIM->get_param(BXPN_E1000));
bx_write_sound_options(fp, (bx_list_c*) SIM->get_param(BXPN_SOUND_SB16));
bx_write_sound_options(fp, (bx_list_c*) SIM->get_param(BXPN_SOUND_ES1370));
bx_write_loader_options(fp);

View File

@ -196,6 +196,7 @@
#define BX_USE_USB_OHCI_SMF 1 // USB OHCI hub
#define BX_USE_USB_XHCI_SMF 1 // USB xHCI hub
#define BX_USE_PCIPNIC_SMF 1 // PCI pseudo NIC
#define BX_USE_E1000_SMF 1 // Intel(R) Gigabit Ethernet
#define BX_USE_NE2K_SMF 1 // NE2K
#define BX_USE_EFI_SMF 1 // External FPU IRQ
#define BX_USE_GAMEPORT_SMF 1 // Gameport
@ -217,7 +218,7 @@
|| !BX_USE_USB_UHCI_SMF || !BX_USE_USB_OHCI_SMF || !BX_USE_USB_XHCI_SMF \
|| !BX_USE_PCIPNIC_SMF || !BX_USE_PIDE_SMF || !BX_USE_ACPI_SMF \
|| !BX_USE_NE2K_SMF || !BX_USE_EFI_SMF || !BX_USE_GAMEPORT_SMF \
|| !BX_USE_PCIDEV_SMF || !BX_USE_CIRRUS_SMF)
|| !BX_USE_E1000_SMF || !BX_USE_PCIDEV_SMF || !BX_USE_CIRRUS_SMF)
#error You must use SMF to have plugins
#endif
@ -807,6 +808,13 @@ typedef
#error To enable the PCI pseudo NIC, you must also enable PCI
#endif
// Intel(R) Gigabit Ethernet
#define BX_SUPPORT_E1000 0
#if (BX_SUPPORT_E1000 && !BX_SUPPORT_PCI)
#error To enable the E1000 NIC, you must also enable PCI
#endif
// this enables the lowlevel stuff below if one of the NICs is present
#define BX_NETWORKING 0

View File

@ -812,6 +812,24 @@ AC_ARG_ENABLE(pnic,
]
)
AC_MSG_CHECKING(for Intel(R) Gigabit Ethernet support)
AC_ARG_ENABLE(e1000,
[ --enable-e1000 enable Intel(R) Gigabit Ethernet support],
[if test "$enableval" = yes; then
AC_MSG_RESULT(yes)
AC_DEFINE(BX_SUPPORT_E1000, 1)
PCI_OBJ="$PCI_OBJ e1000.o"
networking=yes
else
AC_MSG_RESULT(no)
AC_DEFINE(BX_SUPPORT_E1000, 0)
fi],
[
AC_MSG_RESULT(no)
AC_DEFINE(BX_SUPPORT_E1000, 0)
]
)
NETLOW_OBJS=''
if test "$networking" = yes; then
NETLOW_OBJS='eth_null.o eth_vnet.o'

View File

@ -269,6 +269,11 @@ dma.o: dma.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../cpudb.h ../gui/paramtree.h ../memory/memory.h ../pc_system.h \
../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \
../ltdl.h ../param_names.h dma.h
e1000.o: e1000.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \
../cpudb.h ../gui/paramtree.h ../memory/memory.h ../pc_system.h \
../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \
../ltdl.h ../param_names.h pci.h netmod.h e1000.h
es1370.o: es1370.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \
../cpudb.h ../gui/paramtree.h ../memory/memory.h ../pc_system.h \
@ -603,6 +608,11 @@ dma.lo: dma.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../cpudb.h ../gui/paramtree.h ../memory/memory.h ../pc_system.h \
../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \
../ltdl.h ../param_names.h dma.h
e1000.lo: e1000.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \
../cpudb.h ../gui/paramtree.h ../memory/memory.h ../pc_system.h \
../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \
../ltdl.h ../param_names.h pci.h netmod.h e1000.h
es1370.lo: es1370.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \
../cpudb.h ../gui/paramtree.h ../memory/memory.h ../pc_system.h \

View File

@ -291,6 +291,11 @@ void bx_devices_c::init(BX_MEM_C *newmem)
if (SIM->get_param_bool(BXPN_PNIC_ENABLED)->get()) {
PLUG_load_plugin(pcipnic, PLUGTYPE_OPTIONAL);
}
#endif
#if BX_SUPPORT_E1000
if (SIM->get_param_bool(BXPN_E1000_ENABLED)->get()) {
PLUG_load_plugin(e1000, PLUGTYPE_OPTIONAL);
}
#endif
}
#endif

1390
bochs/iodev/e1000.cc Normal file

File diff suppressed because it is too large Load Diff

164
bochs/iodev/e1000.h Normal file
View File

@ -0,0 +1,164 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011 The Bochs Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_E1000_H
#define BX_IODEV_E1000_H
#if BX_USE_E1000_SMF
# define BX_E1000_SMF static
# define BX_E1000_THIS theE1000Device->
# define BX_E1000_THIS_PTR theE1000Device
#else
# define BX_E1000_SMF
# define BX_E1000_THIS this->
# define BX_E1000_THIS_PTR this
#endif
struct e1000_tx_desc {
Bit64u buffer_addr; // Address of the descriptor's data buffer
union {
Bit32u data;
struct {
Bit16u length; // Data buffer length
Bit8u cso; // Checksum offset
Bit8u cmd; // Descriptor control
} flags;
} lower;
union {
Bit32u data;
struct {
Bit8u status; // Descriptor status
Bit8u css; // Checksum start
Bit16u special;
} fields;
} upper;
};
typedef struct {
Bit8u header[256];
Bit8u vlan_header[4];
Bit8u *vlan;
Bit8u *data;
Bit16u size;
Bit8u sum_needed;
Bit8u vlan_needed;
Bit8u ipcss;
Bit8u ipcso;
Bit16u ipcse;
Bit8u tucss;
Bit8u tucso;
Bit16u tucse;
Bit8u hdr_len;
Bit16u mss;
Bit32u paylen;
Bit16u tso_frames;
Bit8s tse;
Bit8s ip;
Bit8s tcp;
Bit8s cptse; // current packet tse bit
Bit32u int_cause;
} e1000_tx;
typedef struct {
Bit8u macaddr[6];
Bit32u *mac_reg;
Bit16u phy_reg[0x20];
Bit16u eeprom_data[64];
Bit32u rxbuf_size;
Bit32u rxbuf_min_shift;
bx_bool check_rxov;
e1000_tx tx;
struct {
Bit32u val_in; // shifted in from guest driver
Bit16u bitnum_in;
Bit16u bitnum_out;
Bit16u reading;
Bit32u old_eecd;
} eecd_state;
int tx_timer_index;
Bit8u devfunc;
} bx_e1000_t;
class bx_e1000_c : public bx_devmodel_c, bx_pci_device_stub_c {
public:
bx_e1000_c();
virtual ~bx_e1000_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void register_state(void);
virtual void after_restore_state(void);
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
private:
bx_e1000_t s;
eth_pktmover_c *ethdev;
BX_E1000_SMF void set_irq_level(bx_bool level);
BX_E1000_SMF void set_interrupt_cause(Bit32u val);
BX_E1000_SMF void set_ics(Bit32u value);
BX_E1000_SMF int rxbufsize(Bit32u v);
BX_E1000_SMF void set_rx_control(Bit32u value);
BX_E1000_SMF void set_mdic(Bit32u value);
BX_E1000_SMF Bit32u get_eecd(void);
BX_E1000_SMF void set_eecd(Bit32u value);
BX_E1000_SMF Bit32u flash_eerd_read(void);
BX_E1000_SMF void putsum(Bit8u *data, Bit32u n, Bit32u sloc, Bit32u css, Bit32u cse);
BX_E1000_SMF bx_bool vlan_enabled(void);
BX_E1000_SMF bx_bool vlan_rx_filter_enabled(void);
BX_E1000_SMF bx_bool is_vlan_packet(const Bit8u *buf);
BX_E1000_SMF bx_bool is_vlan_txd(Bit32u txd_lower);
BX_E1000_SMF int fcs_len(void);
BX_E1000_SMF void xmit_seg(void);
BX_E1000_SMF void process_tx_desc(struct e1000_tx_desc *dp);
BX_E1000_SMF Bit32u txdesc_writeback(bx_phy_address base, struct e1000_tx_desc *dp);
BX_E1000_SMF Bit64u tx_desc_base(void);
BX_E1000_SMF void start_xmit(void);
static void tx_timer_handler(void *);
void tx_timer(void);
BX_E1000_SMF int receive_filter(const Bit8u *buf, int size);
BX_E1000_SMF bx_bool e1000_has_rxbufs(size_t total_size);
BX_E1000_SMF Bit64u rx_desc_base(void);
static void rx_handler(void *arg, const void *buf, unsigned len);
BX_E1000_SMF void rx_frame(const void *buf, unsigned io_len);
BX_E1000_SMF bx_bool mem_read_handler(bx_phy_address addr, unsigned len, void *data, void *param);
BX_E1000_SMF bx_bool mem_write_handler(bx_phy_address addr, unsigned len, void *data, void *param);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_E1000_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

View File

@ -246,34 +246,6 @@ void write_pktlog_txt(FILE *pktlog_txt, const Bit8u *buf, unsigned len, bx_bool
fflush(pktlog_txt);
}
Bit16u get_net2(const Bit8u *buf)
{
return (((Bit16u)*buf) << 8) |
((Bit16u)*(buf+1));
}
void put_net2(Bit8u *buf,Bit16u data)
{
*buf = (Bit8u)(data >> 8);
*(buf+1) = (Bit8u)(data & 0xff);
}
Bit32u get_net4(const Bit8u *buf)
{
return (((Bit32u)*buf) << 24) |
(((Bit32u)*(buf+1)) << 16) |
(((Bit32u)*(buf+2)) << 8) |
((Bit32u)*(buf+3));
}
void put_net4(Bit8u *buf,Bit32u data)
{
*buf = (Bit8u)((data >> 24) & 0xff);
*(buf+1) = (Bit8u)((data >> 16) & 0xff);
*(buf+2) = (Bit8u)((data >> 8) & 0xff);
*(buf+3) = (Bit8u)(data & 0xff);
}
Bit16u ip_checksum(const Bit8u *buf, unsigned buf_len)
{
Bit32u sum = 0;

View File

@ -53,10 +53,34 @@ static const Bit8u broadcast_macaddr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
int execute_script(bx_devmodel_c *netdev, const char *name, char* arg1);
void write_pktlog_txt(FILE *pktlog_txt, const Bit8u *buf, unsigned len, bx_bool host_to_guest);
Bit16u get_net2(const Bit8u *buf);
void put_net2(Bit8u *buf,Bit16u data);
Bit32u get_net4(const Bit8u *buf);
void put_net4(Bit8u *buf,Bit32u data);
BX_CPP_INLINE Bit16u get_net2(const Bit8u *buf)
{
return (((Bit16u)*buf) << 8) |
((Bit16u)*(buf+1));
}
BX_CPP_INLINE void put_net2(Bit8u *buf,Bit16u data)
{
*buf = (Bit8u)(data >> 8);
*(buf+1) = (Bit8u)(data & 0xff);
}
BX_CPP_INLINE Bit32u get_net4(const Bit8u *buf)
{
return (((Bit32u)*buf) << 24) |
(((Bit32u)*(buf+1)) << 16) |
(((Bit32u)*(buf+2)) << 8) |
((Bit32u)*(buf+3));
}
BX_CPP_INLINE void put_net4(Bit8u *buf,Bit32u data)
{
*buf = (Bit8u)((data >> 24) & 0xff);
*(buf+1) = (Bit8u)((data >> 16) & 0xff);
*(buf+2) = (Bit8u)((data >> 8) & 0xff);
*(buf+3) = (Bit8u)(data & 0xff);
}
Bit16u ip_checksum(const Bit8u *buf, unsigned buf_len);
int process_dhcp(bx_devmodel_c *netdev, const Bit8u *data, unsigned data_len, Bit8u *reply, dhcp_cfg_t *dhcp);

View File

@ -159,6 +159,8 @@
#define BXPN_NE2K_ENABLED "network.ne2k.enabled"
#define BXPN_PNIC "network.pnic"
#define BXPN_PNIC_ENABLED "network.pnic.enabled"
#define BXPN_E1000 "network.e1000"
#define BXPN_E1000_ENABLED "network.e1000.enabled"
#define BXPN_SOUND_SB16 "sound.sb16"
#define BXPN_SB16_ENABLED "sound.sb16.enabled"
#define BXPN_SB16_MIDIFILE "sound.sb16.midifile"

View File

@ -69,6 +69,7 @@ extern "C" {
#define BX_PLUGIN_USB_OHCI "usb_ohci"
#define BX_PLUGIN_USB_XHCI "usb_xhci"
#define BX_PLUGIN_PCIPNIC "pcipnic"
#define BX_PLUGIN_E1000 "e1000"
#define BX_PLUGIN_GAMEPORT "gameport"
#define BX_PLUGIN_SPEAKER "speaker"
#define BX_PLUGIN_ACPI "acpi"
@ -422,6 +423,7 @@ DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(es1370)
DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(netmod)
DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(ne2k)
DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pcipnic)
DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(e1000)
DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(extfpuirq)
DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(gameport)
DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(speaker)