debuggers.hg
changeset 16457:53dc1cf50506
merge with xen-unstable.hg (staging)
author | Alex Williamson <alex.williamson@hp.com> |
---|---|
date | Wed Nov 21 09:12:06 2007 -0700 (2007-11-21) |
parents | 9a9ddc04eea2 05cbf512b82b |
children | 980b8d1a5541 |
files | xen/include/asm-powerpc/smpboot.h xen/include/asm-x86/smpboot.h |
line diff
1.1 --- a/tools/ioemu/Makefile.target Tue Nov 20 11:53:44 2007 -0700 1.2 +++ b/tools/ioemu/Makefile.target Wed Nov 21 09:12:06 2007 -0700 1.3 @@ -399,7 +399,7 @@ VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a 1.4 VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o 1.5 1.6 # PCI network cards 1.7 -VL_OBJS+= ne2000.o rtl8139.o pcnet.o 1.8 +VL_OBJS+= ne2000.o rtl8139.o pcnet.o e100.o 1.9 1.10 ifeq ($(TARGET_BASE_ARCH), i386) 1.11 # Hardware support
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/tools/ioemu/hw/e100.c Wed Nov 21 09:12:06 2007 -0700 2.3 @@ -0,0 +1,2464 @@ 2.4 +/* 2.5 + * QEMU E100(i82557) ethernet card emulation 2.6 + * 2.7 + * This program is free software; you can redistribute it and/or modify 2.8 + * it under the terms of the GNU General Public License as published by 2.9 + * the Free Software Foundation; either version 2 of the License, or 2.10 + * (at your option) any later version. 2.11 + * 2.12 + * This program is distributed in the hope that it will be useful, 2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2.15 + * GNU General Public License for more details. 2.16 + * 2.17 + * You should have received a copy of the GNU General Public License 2.18 + * along with this program; if not, write to the Free Software 2.19 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 2.20 + * 2.21 + * Copyright (c) 2006-2007 Stefan Weil 2.22 + * Copyright (c) 2006-2007 Zhang Xin(xing.z.zhang@intel.com) 2.23 + * 2.24 + * Support OS: 2.25 + * x86 linux and windows 2.26 + * PAE linux and windows 2.27 + * x86_64 linux and windows 2.28 + * IA64 linux and windows 2.29 + * 2.30 + * Untested: 2.31 + * Big-endian machine 2.32 + * 2.33 + * References: 2.34 + * 2.35 + * Intel 8255x 10/100 Mbps Ethernet Controller Family 2.36 + * Open Source Software Developer Manual 2.37 + */ 2.38 + 2.39 +#include <assert.h> 2.40 +#include "vl.h" 2.41 + 2.42 +enum 2.43 +{ 2.44 + E100_PCI_VENDOR_ID = 0x00, /* 16 bits */ 2.45 + E100_PCI_DEVICE_ID = 0x02, /* 16 bits */ 2.46 + E100_PCI_COMMAND = 0x04, /* 16 bits */ 2.47 + E100_PCI_STATUS = 0x06, /* 16 bits */ 2.48 + E100_PCI_REVISION_ID = 0x08, /* 8 bits */ 2.49 + E100_PCI_CLASS_CODE = 0x0b, /* 8 bits */ 2.50 + E100_PCI_SUBCLASS_CODE = 0x0a, /* 8 bits */ 2.51 + E100_PCI_HEADER_TYPE = 0x0e, /* 8 bits */ 2.52 + E100_PCI_BASE_ADDRESS_0 = 0x10, /* 32 bits */ 2.53 + E100_PCI_BASE_ADDRESS_1 = 0x14, /* 32 bits */ 2.54 + E100_PCI_BASE_ADDRESS_2 = 0x18, /* 32 bits */ 2.55 + E100_PCI_BASE_ADDRESS_3 = 0x1c, /* 32 bits */ 2.56 + E100_PCI_BASE_ADDRESS_4 = 0x20, /* 32 bits */ 2.57 + E100_PCI_BASE_ADDRESS_5 = 0x24 /* 32 bits */ 2.58 +}PCI_CONFIGURE_SPACE; 2.59 + 2.60 +#define PCI_CONFIG_8(offset, value) \ 2.61 + (*(uint8_t *)&pci_conf[offset] = (value)) 2.62 +#define PCI_CONFIG_16(offset, value) \ 2.63 + (*(uint16_t *)&pci_conf[offset] = cpu_to_le16(value)) 2.64 +#define PCI_CONFIG_32(offset, value) \ 2.65 + (*(uint32_t *)&pci_conf[offset] = cpu_to_le32(value)) 2.66 + 2.67 +// Alias for Control/Status register read/write 2.68 +#define CSR_STATUS scb_status 2.69 +#define CSR_CMD scb_cmd 2.70 +#define CSR_POINTER scb_pointer 2.71 +#define CSR_PORT port 2.72 +#define CSR_EEPROM eeprom_ctrl 2.73 +#define CSR_MDI mdi_ctrl 2.74 +#define CSR_PM pm_reg 2.75 + 2.76 +#define CSR(class, field) \ 2.77 + (s->pci_mem.csr.class.u.field) 2.78 +#define CSR_VAL(class) \ 2.79 + (s->pci_mem.csr.class.val) 2.80 + 2.81 +#define CSR_READ(x, type) \ 2.82 + ({ \ 2.83 + type t; \ 2.84 + memcpy(&t, &s->pci_mem.mem[x], sizeof(type)); \ 2.85 + t; \ 2.86 + }) 2.87 + 2.88 +#define CSR_WRITE(x, val, type) \ 2.89 + ({ \ 2.90 + type t = val; \ 2.91 + memcpy(&s->pci_mem.mem[x], &t, sizeof(type)); \ 2.92 + }) 2.93 + 2.94 +#define SET_CU_STATE(val) \ 2.95 + (CSR(CSR_STATUS, cus) = val) 2.96 +#define GET_CU_STATE \ 2.97 + (CSR(CSR_STATUS, cus)) 2.98 + 2.99 +#define SET_RU_STATE(val) \ 2.100 + (CSR(CSR_STATUS, rus) = val) 2.101 +#define GET_RU_STATE \ 2.102 + (CSR(CSR_STATUS, rus)) 2.103 + 2.104 +#define KiB 1024 2.105 + 2.106 +#define EEPROM_SIZE 64 2.107 + 2.108 +#define BIT(n) (1U << (n)) 2.109 + 2.110 +/* debug E100 card */ 2.111 +//#define DEBUG_E100 2.112 + 2.113 +#ifdef DEBUG_E100 2.114 +#define logout(fmt, args...) fprintf(stderr, "EE100\t%-28s" fmt, __func__, ##args) 2.115 +#else 2.116 +#define logout(fmt, args...) ((void)0) 2.117 +#endif 2.118 + 2.119 +#define MAX_ETH_FRAME_SIZE 1514 2.120 + 2.121 +/* This driver supports several different devices which are declared here. */ 2.122 +#define i82551 0x82551 2.123 +#define i82557B 0x82557b 2.124 +#define i82557C 0x82557c 2.125 +#define i82558B 0x82558b 2.126 +#define i82559C 0x82559c 2.127 +#define i82559ER 0x82559e 2.128 +#define i82562 0x82562 2.129 + 2.130 +#define PCI_MEM_SIZE (4 * KiB) 2.131 +#define PCI_IO_SIZE (64) 2.132 +#define PCI_FLASH_SIZE (128 * KiB) 2.133 + 2.134 +enum 2.135 +{ 2.136 + OP_READ, 2.137 + OP_WRITE, 2.138 +} OPERTAION_DIRECTION; 2.139 + 2.140 +/* The SCB accepts the following controls for the Tx and Rx units: */ 2.141 +enum 2.142 +{ 2.143 + CU_NOP = 0x0000, /* No operation */ 2.144 + CU_START = 0x0010, /* CU start */ 2.145 + CU_RESUME = 0x0020, /* CU resume */ 2.146 + CU_STATSADDR = 0x0040, /* Load dump counters address */ 2.147 + CU_SHOWSTATS = 0x0050, /* Dump statistical counters */ 2.148 + CU_CMD_BASE = 0x0060, /* Load CU base address */ 2.149 + CU_DUMPSTATS = 0x0070, /* Dump and reset statistical counters */ 2.150 + CU_S_RESUME = 0x00a0 /* CU static resume */ 2.151 +}CONTROL_UNIT_COMMAND; 2.152 + 2.153 +enum 2.154 +{ 2.155 + RU_NOP = 0x0000, 2.156 + RU_START = 0x0001, 2.157 + RU_RESUME = 0x0002, 2.158 + RU_DMA_REDIRECT = 0x0003, 2.159 + RU_ABORT = 0x0004, 2.160 + RU_LOAD_HDS = 0x0005, 2.161 + RU_ADDR_LOAD = 0x0006, 2.162 + RU_RESUMENR = 0x0007, 2.163 +}RECEIVE_UNIT_COMMAND; 2.164 + 2.165 +/* SCB status word descriptions */ 2.166 +enum 2.167 +{ 2.168 + CU_IDLE = 0, 2.169 + CU_SUSPENDED = 1, 2.170 + CU_LPQ_ACTIVE = 2, 2.171 + CU_HQP_ACTIVE = 3 2.172 +} CONTROL_UINT_STATE; 2.173 + 2.174 +enum 2.175 +{ 2.176 + RU_IDLE = 0, 2.177 + RU_SUSPENDED = 1, 2.178 + RU_NO_RESOURCES =2, 2.179 + RU_READY = 4 2.180 +} RECEIVE_UNIT_STATE; 2.181 + 2.182 +enum 2.183 +{ 2.184 + PORT_SOFTWARE_RESET = 0, 2.185 + PORT_SELF_TEST = 1, 2.186 + PORT_SELECTIVE_RESET = 2, 2.187 + PORT_DUMP = 3, 2.188 + PORT_DUMP_WAKE_UP = 7, 2.189 +}SCB_PORT_SELECTION_FUNCTION; 2.190 + 2.191 +enum 2.192 +{ 2.193 + CBL_NOP = 0, 2.194 + CBL_IASETUP = 1, 2.195 + CBL_CONFIGURE = 2, 2.196 + CBL_MULTCAST_ADDR_SETUP = 3, 2.197 + CBL_TRANSMIT = 4, 2.198 + CBL_LOAD_MICROCODE = 5, 2.199 + CBL_DUMP = 6, 2.200 + CBL_DIAGNOSE = 7, 2.201 +}CBL_COMMAND; 2.202 + 2.203 +enum 2.204 +{ 2.205 + SCB_STATUS = 0, /* SCB base + 0x00h, RU states + CU states + STAT/ACK */ 2.206 + SCB_ACK = 1, /* SCB ack/stat */ 2.207 + SCB_CMD = 2, /* RU command + CU command + S bit + M bit */ 2.208 + SCB_INTERRUPT_MASK = 3, /* Interrupts mask bits */ 2.209 + SCB_POINTER = 4, /* SCB general pointer, depending on command type */ 2.210 + SCB_PORT = 8, /* SCB port register */ 2.211 + SCB_EEPROM = 0xe, /* SCB eeprom control register */ 2.212 + SCB_MDI =0x10, /* SCB MDI control register */ 2.213 +} CSR_OFFSETS; 2.214 + 2.215 +enum 2.216 +{ 2.217 + EEPROM_SK = 0x01, 2.218 + EEPROM_CS = 0x02, 2.219 + EEPROM_DI = 0x04, 2.220 + EEPROM_DO = 0x08, 2.221 +} EEPROM_CONTROL_REGISTER; 2.222 + 2.223 +enum 2.224 +{ 2.225 + EEPROM_READ = 0x2, 2.226 + EEPROM_WRITE = 0x1, 2.227 + EEPROM_ERASE = 0x3, 2.228 +} EEPROM_OPCODE; 2.229 + 2.230 +enum 2.231 +{ 2.232 + MDI_WRITE = 0x1, 2.233 + MDI_READ = 0x2, 2.234 +} MDI_OPCODE; 2.235 + 2.236 +enum 2.237 +{ 2.238 + INT_FCP = BIT(8), 2.239 + INT_SWI = BIT(10), 2.240 + INT_MDI = BIT(11), 2.241 + INT_RNR = BIT(12), 2.242 + INT_CNA = BIT(13), 2.243 + INT_FR = BIT(14), 2.244 + INT_CX_TNO = BIT(15), 2.245 +} E100_INTERRUPT; 2.246 + 2.247 +enum 2.248 +{ 2.249 + CSR_MEMORY_BASE, 2.250 + CSR_IO_BASE, 2.251 + FLASH_MEMORY_BASE, 2.252 + REGION_NUM 2.253 +}E100_PCI_MEMORY_REGION; 2.254 + 2.255 +typedef struct { 2.256 + uint32_t tx_good_frames, // Good frames transmitted 2.257 + tx_max_collisions, // Fatal frames -- had max collisions 2.258 + tx_late_collisions, // Fatal frames -- had a late coll. 2.259 + tx_underruns, // Transmit underruns (fatal or re-transmit) 2.260 + tx_lost_crs, // Frames transmitted without CRS 2.261 + tx_deferred, // Deferred transmits 2.262 + tx_single_collisions, // Transmits that had 1 and only 1 coll. 2.263 + tx_multiple_collisions,// Transmits that had multiple coll. 2.264 + tx_total_collisions, // Transmits that had 1+ collisions. 2.265 + 2.266 + rx_good_frames, // Good frames received 2.267 + rx_crc_errors, // Aligned frames that had a CRC error 2.268 + rx_alignment_errors, // Receives that had alignment errors 2.269 + rx_resource_errors, // Good frame dropped due to lack of resources 2.270 + rx_overrun_errors, // Overrun errors - bus was busy 2.271 + rx_cdt_errors, // Received frames that encountered coll. 2.272 + rx_short_frame_errors, // Received frames that were to short 2.273 + 2.274 + complete_word; // A005h indicates dump cmd completion, 2.275 + // A007h indicates dump and reset cmd completion. 2.276 + 2.277 +// TODO: Add specific field for i82558, i82559 2.278 +} __attribute__ ((packed)) e100_stats_t; 2.279 + 2.280 +#define EEPROM_I82557_ADDRBIT 6 2.281 +/* Below data is dumped from a real I82557 card */ 2.282 +static const uint16_t eeprom_i82557[] = 2.283 +{ 2.284 + 0x300, 0xe147, 0x2fa4, 0x203, 0x0, 0x201, 0x4701, 0x0, 0x7414, 0x6207, 2.285 + 0x4082, 0xb, 0x8086, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2.286 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2.287 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x128, 0x0, 0x0, 0x0, 0x0, 0x0, 2.288 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc374, 2.289 +}; 2.290 + 2.291 +static const uint8_t e100_pci_configure[] = 2.292 +{ 2.293 + 0x86, 0x80, 0x29, 0x12, 0x17, 0x00, 0x90, 0x02, 0x08, 0x00, 0x00, 0x02, 0x10, 0x20, 0x00, 0x00, 2.294 + 0x00, 0x00, 0x10, 0x50, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 2.295 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x80, 0x0b, 0x00, 2.296 + 0x00, 0x00, 0xf0, 0xff, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x08, 0x38, 2.297 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.298 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.299 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.300 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.301 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.302 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.303 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.304 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.305 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.306 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0xfe, 2.307 + 0x00, 0x40, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.308 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2.309 +}; 2.310 + 2.311 +typedef struct 2.312 +{ 2.313 +#define OPCODE 0xb 2.314 +#define ADDR 0xc 2.315 +#define DATA 0xd 2.316 +#define NOP 0xe 2.317 + 2.318 +#define EEPROM_RESET_ALL 0xfe 2.319 +#define EEPROM_SELECT_RESET 0xff 2.320 + uint8_t start_bit; 2.321 + uint8_t opcode; 2.322 + uint8_t address; 2.323 + uint16_t data; //This must be 16 bit represents a register in eeprom 2.324 + 2.325 + uint32_t val; 2.326 + uint32_t val_len; 2.327 + uint8_t val_type; // What data type is in DI. opcode?address?data? 2.328 + 2.329 + uint8_t cs; 2.330 + uint8_t sk; 2.331 + 2.332 + // This two fileds only be reset when device init 2.333 + uint16_t addr_len; 2.334 + uint16_t contents[256]; // 256 is enough to all device(i82557 ... i82559) 2.335 +} eeprom_t; 2.336 + 2.337 +// Control/Status register structure 2.338 +typedef struct 2.339 +{ 2.340 + /* SCB status word */ 2.341 + union 2.342 + { 2.343 + uint16_t val; 2.344 + struct 2.345 + { 2.346 + uint8_t rs1:2; // Reserved 2.347 + uint8_t rus:4; // RU status 2.348 + uint8_t cus:2; // CU status 2.349 + uint8_t stat_ack; // Stat/ACK 2.350 + }u; 2.351 + }scb_status; 2.352 + 2.353 + /* SCB command word */ 2.354 + union 2.355 + { 2.356 + uint16_t val; 2.357 + struct 2.358 + { 2.359 + uint8_t ru_cmd:3; // RU command 2.360 + uint8_t rs1:1; // Reserved 2.361 + uint8_t cu_cmd:4; // CU command 2.362 + uint8_t m:1; // Interrup mask bit(1:mask all interrupt) 2.363 + uint8_t si:1; // Use for software cause interrupt 2.364 + uint8_t simb:6; // Specific interrupt mask bit 2.365 + }u; 2.366 + }scb_cmd; 2.367 + 2.368 + /* SCB general pointer */ 2.369 + union 2.370 + { 2.371 + uint32_t val; 2.372 + struct 2.373 + { 2.374 + uint32_t scb_ptr; 2.375 + }u; 2.376 + }scb_pointer; 2.377 + 2.378 + /* Port interface */ 2.379 + union 2.380 + { 2.381 + uint32_t val; 2.382 + struct 2.383 + { 2.384 + uint8_t opcode:4; // Op code for function selection 2.385 + uint32_t ptr:28; // Result pointer 2.386 + }u; 2.387 + }port; 2.388 + 2.389 + uint16_t rs1; // Reserved 2.390 + 2.391 + /* EEPROM control register */ 2.392 + union 2.393 + { 2.394 + uint16_t val; 2.395 + struct 2.396 + { 2.397 + uint8_t eesk:1; // Serial clock 2.398 + uint8_t eecs:1; // Chip select 2.399 + uint8_t eedi:1; // Serial data in 2.400 + uint8_t eedo:1; // Serial data out 2.401 + uint8_t rs1:4; // Reserved 2.402 + uint8_t data; 2.403 + }u; 2.404 + }eeprom_ctrl; 2.405 + 2.406 + /* MDI control register */ 2.407 + union 2.408 + { 2.409 + uint32_t val; 2.410 + struct 2.411 + { 2.412 + uint16_t data; // Data 2.413 + uint8_t regaddr:5; // PHY register address 2.414 + uint8_t phyaddr:5; // PHY address 2.415 + uint8_t opcode:2; // Opcode 2.416 + uint8_t r:1; // Ready 2.417 + uint8_t ie:1; // Interrup enable 2.418 + uint8_t rs1:2; // Reserved 2.419 + }u; 2.420 + } mdi_ctrl; 2.421 + 2.422 + /* Receive byte counter register */ 2.423 + uint32_t rx_byte_counter; 2.424 + 2.425 + /* Early receive interrupt register */ 2.426 + uint8_t early_interrupt; 2.427 + 2.428 + /* Flow control register */ 2.429 + union 2.430 + { 2.431 + uint16_t val; 2.432 + }flow_ctrl; 2.433 + 2.434 + /* Power management driver register */ 2.435 + union 2.436 + { 2.437 + uint8_t val; 2.438 + struct 2.439 + { 2.440 + uint8_t pme_s:1; // PME status 2.441 + uint8_t tco_r:1; // TCO request 2.442 + uint8_t f_tco_i:1; // Force TCO indication 2.443 + uint8_t tco_re:1; // TCO ready 2.444 + uint8_t rs1:1; // Reserved 2.445 + uint8_t isp:1; // Intersting packet 2.446 + uint8_t mg:1; // Magic packet 2.447 + uint8_t lsci:1; // Link status change indication 2.448 + }u; 2.449 + }pm_reg; 2.450 + 2.451 + /* General control register */ 2.452 + uint8_t gen_ctrl; 2.453 + 2.454 + /* General status register */ 2.455 + uint8_t gen_status; 2.456 + 2.457 + /* These are reserved or we don't support register */ 2.458 + uint8_t others[30]; 2.459 +} __attribute__ ((packed)) csr_t; 2.460 + 2.461 +typedef struct 2.462 +{ 2.463 + uint8_t byte_count; 2.464 + uint8_t rx_fifo_limit:4; 2.465 + uint8_t tx_fifo_limit:4; 2.466 + uint8_t adpt_inf_spacing; 2.467 + uint8_t rs1; 2.468 + uint8_t rx_dma_max_bytes; 2.469 + uint8_t tx_dma_max_bytes:7; 2.470 + uint8_t dmbc_en:1; 2.471 + uint8_t late_scb:1, 2.472 + rs2:1, 2.473 + tno_intr:1, 2.474 + ci_intr:1, 2.475 + rs3:1, 2.476 + rs4:1, 2.477 + dis_overrun_rx:1, 2.478 + save_bad_frame:1; 2.479 + uint8_t dis_short_rx:1, 2.480 + underrun_retry:2, 2.481 + rs5:5; 2.482 + uint8_t mii:1, 2.483 + rs6:7; 2.484 + uint8_t rs7; 2.485 + uint8_t rs8:3, 2.486 + nsai:1, 2.487 + preamble_len:2, 2.488 + loopback:2; 2.489 + uint8_t linear_prio:3, 2.490 + rs9:5; 2.491 + uint8_t pri_mode:1, 2.492 + rs10:3, 2.493 + interframe_spacing:4; 2.494 + uint16_t rs11; 2.495 + uint8_t promiscuous:1, 2.496 + broadcast_dis:1, 2.497 + rs12:5, 2.498 + crs_cdt:1; 2.499 + uint16_t rs13; 2.500 + uint8_t strip:1, 2.501 + padding:1, 2.502 + rx_crc:1, 2.503 + rs14:5; 2.504 + uint8_t rs15:6, 2.505 + force_fdx:1, 2.506 + fdx_en:1; 2.507 + uint8_t rs16:6, 2.508 + mul_ia:2; 2.509 + uint8_t rs17:3, 2.510 + mul_all:1, 2.511 + rs18:4; 2.512 +} __attribute__ ((packed)) i82557_cfg_t; 2.513 + 2.514 +typedef struct { 2.515 + VLANClientState *vc; 2.516 + PCIDevice *pci_dev; 2.517 + int mmio_index; 2.518 + uint8_t scb_stat; /* SCB stat/ack byte */ 2.519 + uint32_t region_base_addr[REGION_NUM]; /* PCI region addresses */ 2.520 + uint8_t macaddr[6]; 2.521 + uint16_t mdimem[32]; 2.522 + eeprom_t eeprom; 2.523 + uint32_t device; /* device variant */ 2.524 + 2.525 + uint8_t mult_list[8]; /* Multicast address list */ 2.526 + int is_multcast_enable; 2.527 + 2.528 + /* (cu_base + cu_offset) address the next command block in the command block list. */ 2.529 + uint32_t cu_base; /* CU base address */ 2.530 + uint32_t cu_offset; /* CU address offset */ 2.531 + uint32_t cu_next; /* Point to next command when CU go to suspend */ 2.532 + 2.533 + /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */ 2.534 + uint32_t ru_base; /* RU base address */ 2.535 + uint32_t ru_offset; /* RU address offset */ 2.536 + 2.537 + uint32_t statsaddr; /* pointer to e100_stats_t */ 2.538 + 2.539 + e100_stats_t statistics; /* statistical counters */ 2.540 + 2.541 + /* Configuration bytes. */ 2.542 + i82557_cfg_t config; 2.543 + 2.544 + /* FIFO buffer of card. The packet that need to be sent buffered in it */ 2.545 + uint8_t pkt_buf[MAX_ETH_FRAME_SIZE+4]; 2.546 + /* Data length in FIFO buffer */ 2.547 + int pkt_buf_len; 2.548 + 2.549 + /* Data in mem is always in the byte order of the controller (le). */ 2.550 + union 2.551 + { 2.552 + csr_t csr; 2.553 + uint8_t mem[PCI_MEM_SIZE]; 2.554 + }pci_mem; 2.555 + 2.556 +} E100State; 2.557 + 2.558 +/* CB structure, filled by device driver 2.559 + * This is a common structure of CB. In some 2.560 + * special case such as TRANSMIT command, the 2.561 + * reserved field will be used. 2.562 + */ 2.563 +struct control_block 2.564 +{ 2.565 + uint16_t rs1:13; /* reserved */ 2.566 + uint8_t ok:1; /* 1:command executed without error, otherwise 0 */ 2.567 + uint8_t rs2:1; 2.568 + uint8_t c:1; /* execution status. set by device, clean by software */ 2.569 + uint8_t cmd:3; /* command */ 2.570 + uint16_t rs3:10; /* most time equal to 0 */ 2.571 + uint8_t i:1; /* whether trigger interrupt after execution. 1:yes; 0:no */ 2.572 + uint8_t s:1; /* suspend */ 2.573 + uint8_t el:1; /* end flag */ 2.574 + uint32_t link_addr; 2.575 +} __attribute__ ((packed)); 2.576 + 2.577 +typedef struct 2.578 +{ 2.579 + uint32_t tx_desc_addr; /* transmit buffer decsriptor array address. */ 2.580 + uint16_t tcb_bytes:14; /* transmit command block byte count (in lower 14 bits)*/ 2.581 + uint8_t rs1:1; 2.582 + uint8_t eof:1; 2.583 + uint8_t tx_threshold; /* transmit threshold */ 2.584 + uint8_t tbd_num; /* TBD number */ 2.585 +} __attribute__ ((packed)) tbd_t; 2.586 + 2.587 +/* Receive frame descriptore structure */ 2.588 +typedef struct 2.589 +{ 2.590 + uint16_t status:13; // Result of receive opration 2.591 + uint8_t ok:1; // 1:receive without error, otherwise 0 2.592 + uint8_t rs1:1; 2.593 + uint8_t c:1; // 1:receive complete 2.594 + uint8_t rs2:3; 2.595 + uint8_t sf:1; // 0:simplified mode 2.596 + uint8_t h:1; // 1:header RFD 2.597 + uint16_t rs3:9; 2.598 + uint8_t s:1; // 1:go to suspend 2.599 + uint8_t el:1; // 1:last RFD 2.600 + uint32_t link_addr; // Add on RU base point to next RFD 2.601 + uint32_t rs4; 2.602 + uint16_t count:14; // Number of bytes written into data area 2.603 + uint8_t f:1; // Set by device when count field update 2.604 + uint8_t eof:1; // Set by device when placing data into data area complete 2.605 + uint16_t size:14; // Buffer size (even number) 2.606 + uint8_t rs5:2; 2.607 +} __attribute__ ((packed)) rfd_t; 2.608 + 2.609 +enum 2.610 +{ 2.611 + RX_COLLISION = BIT(0), // 1:Receive collision detected 2.612 + RX_IA_MATCH = BIT(1), // 0:Receive frame match individual address 2.613 + RX_NO_MATCH = BIT(2), // 1:Receive frame match no address 2.614 + RX_ERR = BIT(4), // 1:Receive frame error 2.615 + RX_TYPE = BIT(5), // 1:Receive frame is a type frame 2.616 + RX_SHORT = BIT(7), // 1:Receive frame is too short 2.617 + RX_DMA_ERR = BIT(8), 2.618 + RX_LARGE = BIT(9), // 1:Receive frame is too large 2.619 + RX_CRC_ERR = BIT(10), 2.620 +} RFD_STATUS; 2.621 + 2.622 +typedef struct PCIE100State { 2.623 + PCIDevice dev; 2.624 + E100State e100; 2.625 +} PCIE100State; 2.626 + 2.627 +/* Default values for MDI (PHY) registers */ 2.628 +static const uint16_t e100_mdi_default[] = { 2.629 + /* MDI Registers 0 - 6, 7 */ 2.630 + 0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000, 2.631 + /* MDI Registers 8 - 15 */ 2.632 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 2.633 + /* MDI Registers 16 - 31 */ 2.634 + 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 2.635 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 2.636 +}; 2.637 + 2.638 +static const uint8_t broadcast_macaddr[6] = 2.639 + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 2.640 + 2.641 +/* Debugging codes */ 2.642 +#ifdef DEBUG_E100 2.643 + 2.644 +static void e100_dump(char *comment, uint8_t *info, int len) 2.645 +{ 2.646 + int i; 2.647 + 2.648 + if ( !comment || !info ) 2.649 + return; 2.650 + 2.651 + fprintf(stderr, "EE100\t%-24s%s", __func__, comment); 2.652 + for ( i=0; i<len; i++ ) 2.653 + fprintf(stderr, "%x ", info[i]); 2.654 + 2.655 + fprintf(stderr, "\n"); 2.656 +} 2.657 + 2.658 +static const char *regname[] = 2.659 +{ 2.660 + [0] = "SCB Status", [1] = "SCB Ack", 2.661 + [2] = "SCB Cmd", [3] = "SCB Interrupt Mask", 2.662 + [4] = "SCB Pointer", [8] = "SCB Port", 2.663 + [0xc] = "SCB Flash", [0xe] = "SCB Eeprom", 2.664 + [0x10] = "SCB Ctrl MDI", [0x14] = "SCB Early RX", 2.665 +}; 2.666 +#define SCBNAME(x) \ 2.667 + ( (x) < (sizeof(regname) / sizeof(regname[0])) ? regname[(x)] : "Unknown SCB Register" ) 2.668 + 2.669 +static const char *cb_cmd_name[] = 2.670 +{ 2.671 + [CBL_NOP] = "NOP", [CBL_IASETUP] = "Individual address setup", 2.672 + [CBL_CONFIGURE] = "Configure", [CBL_MULTCAST_ADDR_SETUP] = "Set Multcast address list", 2.673 + [CBL_TRANSMIT] = "Transmit", [CBL_LOAD_MICROCODE] = "Load microcode", 2.674 + [CBL_DUMP] = "Dump", [CBL_DIAGNOSE] = "Diagnose", 2.675 +}; 2.676 +#define CB_CMD_NAME(x) \ 2.677 + ( (x) < (sizeof(cb_cmd_name) / sizeof(cb_cmd_name[0])) ? cb_cmd_name[(x)] : "Unknown CB command" ) 2.678 + 2.679 +static const char *eeprom_opcode_name[] = 2.680 +{ 2.681 + [0] = "Unknow", [EEPROM_WRITE] = "Write", 2.682 + [EEPROM_READ] = "Read", [EEPROM_ERASE] = "Erase", 2.683 +}; 2.684 +#define EEPROM_OPCODE_NAME(x) \ 2.685 + ( (x) < (sizeof(eeprom_opcode_name) / sizeof(eeprom_opcode_name[0])) ? \ 2.686 + eeprom_opcode_name[(x)] : "Unknown" ) 2.687 + 2.688 +static struct eeprom_trace_data 2.689 +{ 2.690 + uint8_t eedo[256]; 2.691 + uint8_t di[256]; 2.692 + int op; 2.693 + int i; 2.694 + uint32_t data; 2.695 +}etd = {.op = NOP}; 2.696 + 2.697 +static void eeprom_trace(int eedo, int di, int dir, int next_op, int clr) 2.698 +{ 2.699 + int i; 2.700 + 2.701 + if ( clr ) 2.702 + { 2.703 + char *opname = NULL; 2.704 + 2.705 + switch ( etd.op ) 2.706 + { 2.707 + case NOP: 2.708 + break; 2.709 + case OPCODE: 2.710 + opname = "opcode"; 2.711 + break; 2.712 + case ADDR: 2.713 + opname = "address"; 2.714 + break; 2.715 + case DATA: 2.716 + opname = "data transfer"; 2.717 + break; 2.718 + default: 2.719 + opname = "Unknown"; 2.720 + } 2.721 + 2.722 + if ( opname ) 2.723 + { 2.724 + logout("EEPROM trace:\n"); 2.725 + fprintf(stderr, "\toperation: %s\n", opname); 2.726 + fprintf(stderr, "\tDI track:"); 2.727 + for ( i=0; i<etd.i; i++ ) 2.728 + fprintf(stderr, "%x ", etd.di[i]); 2.729 + fprintf(stderr, "\n\tDO track:"); 2.730 + for ( i=0; i<etd.i; i++ ) 2.731 + fprintf(stderr, "%x ", etd.eedo[i]); 2.732 + fprintf(stderr, "\n\tData:%#x\n", etd.data); 2.733 + } 2.734 + 2.735 + 2.736 + memset(&etd, 0x0, sizeof(etd)); 2.737 + etd.op = next_op; 2.738 + 2.739 + return; 2.740 + } 2.741 + 2.742 + etd.eedo[etd.i] = eedo; 2.743 + etd.di[etd.i] = di; 2.744 + etd.i ++; 2.745 + if ( dir == EEPROM_READ && etd.op == DATA ) 2.746 + etd.data = (etd.data << 1) | eedo; 2.747 + else 2.748 + etd.data = (etd.data << 1) | di; 2.749 +} 2.750 + 2.751 +#define INT_NAME(x) \ 2.752 + ({ \ 2.753 + char *name = NULL; \ 2.754 + switch (x) \ 2.755 + { \ 2.756 + case INT_FCP: \ 2.757 + name = "FCP"; \ 2.758 + break; \ 2.759 + case INT_SWI: \ 2.760 + name = "SWI"; \ 2.761 + break; \ 2.762 + case INT_MDI: \ 2.763 + name = "MDI"; \ 2.764 + break; \ 2.765 + case INT_RNR: \ 2.766 + name = "RNR"; \ 2.767 + break; \ 2.768 + case INT_CNA: \ 2.769 + name = "CNA"; \ 2.770 + break; \ 2.771 + case INT_FR: \ 2.772 + name = "FR"; \ 2.773 + break; \ 2.774 + case INT_CX_TNO: \ 2.775 + name ="CX/TNO"; \ 2.776 + break; \ 2.777 + default: \ 2.778 + name ="Unknown"; \ 2.779 + } \ 2.780 + name; \ 2.781 + }) 2.782 + 2.783 +#else 2.784 +static void e100_dump(char *comment, uint8_t *info, int len) {} 2.785 +static void eeprom_trace(int eedo, int di, int dir, int next_op, int clr) {} 2.786 +#endif 2.787 + 2.788 +static void pci_reset(E100State * s) 2.789 +{ 2.790 + uint8_t *pci_conf = s->pci_dev->config; 2.791 + 2.792 + memcpy(pci_conf, &e100_pci_configure[0], sizeof(e100_pci_configure)); 2.793 + logout("%p\n", s); 2.794 + 2.795 + /* I82557 */ 2.796 + PCI_CONFIG_8(E100_PCI_REVISION_ID, 0x01); 2.797 + 2.798 + PCI_CONFIG_8(0x3c, 0x0); 2.799 + 2.800 +} 2.801 + 2.802 +static void e100_selective_reset(E100State * s) 2.803 +{ 2.804 + 2.805 + memset(s->pci_mem.mem, 0x0, sizeof(s->pci_mem.mem)); 2.806 + // Set RU/CU to idle, maintain the register mentioned in spec, 2.807 + SET_CU_STATE(CU_IDLE); 2.808 + SET_RU_STATE(RU_IDLE); 2.809 + logout("CU and RU go to idle\n"); 2.810 + 2.811 + s->ru_offset = 0; 2.812 + s->cu_offset = 0; 2.813 + s->cu_next = 0; 2.814 + 2.815 + // For 82557, special interrupt bits are all 1 2.816 + CSR(CSR_CMD, simb) = 0x3f; 2.817 + // Set PHY to 1 2.818 + CSR_VAL(CSR_MDI) |= BIT(21); 2.819 + 2.820 + /* Initialize EEDO bit to 1. Due to driver would detect dummy 0 at 2.821 + * EEDO bit, so initialize it to 1 is safety a way. 2.822 + */ 2.823 + CSR(CSR_EEPROM, eedo) = 1; 2.824 + // no pending interrupts 2.825 + s->scb_stat = 0; 2.826 + 2.827 + return; 2.828 +} 2.829 + 2.830 +static void e100_software_reset(E100State *s) 2.831 +{ 2.832 + memset(s->pci_mem.mem, 0x0, sizeof(s->pci_mem.mem)); 2.833 + // Clear multicast list 2.834 + memset(s->mult_list, 0x0, sizeof(s->mult_list)); 2.835 + // Set MDI register to default value 2.836 + memcpy(&s->mdimem[0], &e100_mdi_default[0], sizeof(s->mdimem)); 2.837 + s->is_multcast_enable = 1; 2.838 + /* Clean FIFO buffer */ 2.839 + memset(s->pkt_buf, 0x0, sizeof(s->pkt_buf)); 2.840 + s->pkt_buf_len = 0; 2.841 + 2.842 + memset(&s->statistics, 0x0, sizeof(s->statistics)); 2.843 + e100_selective_reset(s); 2.844 + return; 2.845 +} 2.846 + 2.847 +static void e100_reset(void *opaque) 2.848 +{ 2.849 + E100State *s = (E100State *) opaque; 2.850 + logout("%p\n", s); 2.851 + e100_software_reset(s); 2.852 +} 2.853 + 2.854 + 2.855 +static void e100_save(QEMUFile * f, void *opaque) 2.856 +{ 2.857 + //TODO 2.858 + return; 2.859 +} 2.860 + 2.861 +static int e100_load(QEMUFile * f, void *opaque, int version_id) 2.862 +{ 2.863 + //TODO 2.864 + return 0; 2.865 +} 2.866 + 2.867 +/* Interrupt functions */ 2.868 +static void e100_interrupt(E100State *s, uint16_t int_type) 2.869 +{ 2.870 + 2.871 + //TODO: Add another i8255x card supported mask bit 2.872 + if ( !CSR(CSR_CMD,m) ) 2.873 + { 2.874 + //Set bit in stat/ack, so driver can no what interrupt happen 2.875 + CSR_VAL(CSR_STATUS) |= int_type; 2.876 + s->scb_stat = CSR(CSR_STATUS, stat_ack); 2.877 + 2.878 + /* SCB maske and SCB Bit M do not disable interrupt. */ 2.879 + logout("Trigger an interrupt(type = %s(%#x), SCB Status = %#x)\n", 2.880 + INT_NAME(int_type), int_type, CSR_VAL(CSR_STATUS)); 2.881 + pci_set_irq(s->pci_dev, 0, 1); 2.882 + } 2.883 +} 2.884 + 2.885 +static void e100_interrupt_ack(E100State * s, uint8_t ack) 2.886 +{ 2.887 + 2.888 + /* Ignore acknowledege if driver write 0 to ack or 2.889 + * according interrupt bit is not set 2.890 + */ 2.891 + if ( !ack || !(s->scb_stat & ack) ) 2.892 + { 2.893 + logout("Illegal interrupt ack(ack=%#x, SCB Stat/Ack=%#x), ignore it\n", 2.894 + ack, s->scb_stat); 2.895 + // Due to we do write operation before e100_execute(), so 2.896 + // we must restore value of ack field here 2.897 + CSR(CSR_STATUS, stat_ack) = s->scb_stat; 2.898 + return; 2.899 + } 2.900 + 2.901 + s->scb_stat &= ~ack; 2.902 + CSR(CSR_STATUS, stat_ack) = s->scb_stat; 2.903 + 2.904 + logout("Interrupt ack(name=%s,val=%#x)\n", INT_NAME(({uint16_t bit = ack<<8;bit;})),ack); 2.905 + if ( !s->scb_stat ) 2.906 + { 2.907 + logout("All interrupts are acknowledeged, de-assert interrupt line\n"); 2.908 + pci_set_irq(s->pci_dev, 0, 0); 2.909 + } 2.910 +} 2.911 + 2.912 +static void e100_self_test(uint32_t res_addr) 2.913 +{ 2.914 + struct 2.915 + { 2.916 + uint32_t st_sign; /* Self Test Signature */ 2.917 + uint32_t st_result; /* Self Test Results */ 2.918 + } test_res; 2.919 + 2.920 + test_res.st_sign = (uint32_t)-1; 2.921 + test_res.st_result = 0; // Our self test always success 2.922 + cpu_physical_memory_write(res_addr, (uint8_t *)&test_res, sizeof(test_res)); 2.923 + 2.924 + logout("Write self test result to %#x\n", res_addr); 2.925 +} 2.926 + 2.927 +static void scb_port_func(E100State *s, uint32_t val, int dir) 2.928 +{ 2.929 +#define PORT_SELECTION_MASK 0xfU 2.930 + 2.931 + uint32_t sel = val & PORT_SELECTION_MASK; 2.932 + 2.933 + switch ( sel ) 2.934 + { 2.935 + case PORT_SOFTWARE_RESET: 2.936 + logout("do PORT_SOFTWARE_RESET!\n"); 2.937 + e100_software_reset(s); 2.938 + break; 2.939 + case PORT_SELF_TEST: 2.940 + e100_self_test(val & ~PORT_SELECTION_MASK); 2.941 + logout("do PORT_SELF_TEST!\n"); 2.942 + break; 2.943 + case PORT_SELECTIVE_RESET: 2.944 + logout("do PORT_SELECTIVE_RESET!\n"); 2.945 + e100_selective_reset(s); 2.946 + break; 2.947 + case PORT_DUMP: 2.948 + logout("do PORT_SOFTWARE_RESET!\n"); 2.949 + break; 2.950 + case PORT_DUMP_WAKE_UP: 2.951 + logout("do PORT_SOFTWARE_RESET!\n"); 2.952 + break; 2.953 + default: 2.954 + logout("Unkonw SCB port command(selection function = %#x)\n", sel); 2.955 + } 2.956 +} 2.957 + 2.958 +static void e100_write_mdi(E100State *s, uint32_t val) 2.959 +{ 2.960 + uint32_t ie = (val & 0x20000000) >> 29; 2.961 + uint32_t opcode = (val & 0x0c000000) >> 26; 2.962 + uint32_t phyaddr = (val & 0x03e00000) >> 21; 2.963 + uint32_t regaddr = (val & 0x001f0000) >> 16; 2.964 + uint32_t data = val & 0x0000ffff; 2.965 + 2.966 + logout("Write MDI:\n" 2.967 + "\topcode:%#x\n" 2.968 + "\tphy address:%#x\n" 2.969 + "\treg address:%#x\n" 2.970 + "\tie:%#x\n" 2.971 + "\tdata:%#x\n", 2.972 + opcode, phyaddr, regaddr, ie, data); 2.973 + 2.974 + /* We use default value --- PHY1 2.975 + * If driver operate on other PHYs, do nothing and 2.976 + * deceive it that the operation is finished 2.977 + */ 2.978 + if ( phyaddr != 1 ) 2.979 + { 2.980 + logout("Unsupport PHY address(phy = %#x)\n", phyaddr); 2.981 + goto done; 2.982 + } 2.983 + 2.984 + // 1: MDI write 2.985 + // 2: MDI read 2.986 + if ( opcode != MDI_WRITE && opcode != MDI_READ ) 2.987 + { 2.988 + logout("Invalid Opcode(opcode = %#x)\n", opcode); 2.989 + return; 2.990 + } 2.991 + 2.992 + // Current only support MDI generic registers. 2.993 + if ( regaddr > 6 ) 2.994 + { 2.995 + logout("Invalid phy register index( phy register addr = %#x)\n", regaddr); 2.996 + } 2.997 + 2.998 + if ( opcode == MDI_WRITE ) 2.999 + { 2.1000 + // MDI write 2.1001 + switch ( regaddr ) 2.1002 + { 2.1003 + case 0: // Control Register 2.1004 + if ( data & 0x8000 ) // Reset 2.1005 + { 2.1006 + /* Reset status and control registers to default. */ 2.1007 + s->mdimem[0] = e100_mdi_default[0]; 2.1008 + s->mdimem[1] = e100_mdi_default[1]; 2.1009 + data = s->mdimem[regaddr]; 2.1010 + } 2.1011 + else 2.1012 + { 2.1013 + /* Restart Auto Configuration = Normal Operation */ 2.1014 + data &= ~0x0200; 2.1015 + } 2.1016 + break; 2.1017 + case 1: // Status Register 2.1018 + logout("Invalid write on readonly register(opcode = %#x)\n", opcode); 2.1019 + data = s->mdimem[regaddr]; 2.1020 + break; 2.1021 + case 2: 2.1022 + case 3: 2.1023 + case 4: 2.1024 + case 5: 2.1025 + case 6: 2.1026 + break; 2.1027 + } 2.1028 + s->mdimem[regaddr] = data; 2.1029 + logout("MDI WRITE: reg = %#x, data = %#x\n", regaddr, data); 2.1030 + } 2.1031 + else if ( opcode == MDI_READ ) 2.1032 + { 2.1033 + // MDI read 2.1034 + switch ( regaddr ) 2.1035 + { 2.1036 + case 0: // Control Register 2.1037 + if ( data & 0x8000 ) // Reset 2.1038 + { 2.1039 + /* Reset status and control registers to default. */ 2.1040 + s->mdimem[0] = e100_mdi_default[0]; 2.1041 + s->mdimem[1] = e100_mdi_default[1]; 2.1042 + } 2.1043 + break; 2.1044 + case 1: // Status Register 2.1045 + // Auto Negotiation complete, set sticky bit to 1 2.1046 + s->mdimem[regaddr] |= 0x0026; 2.1047 + break; 2.1048 + case 2: // PHY Identification Register (Word 1) 2.1049 + case 3: // PHY Identification Register (Word 2) 2.1050 + break; 2.1051 + case 5: // Auto-Negotiation Link Partner Ability Register 2.1052 + s->mdimem[regaddr] = 0x41fe; 2.1053 + break; 2.1054 + case 6: // Auto-Negotiation Expansion Register 2.1055 + s->mdimem[regaddr] = 0x0001; 2.1056 + break; 2.1057 + } 2.1058 + data = s->mdimem[regaddr]; 2.1059 + logout("MDI READ: reg = %#x, data = %#x\n", regaddr, data); 2.1060 + } 2.1061 + 2.1062 + /* Emulation takes no time to finish MDI transaction. 2.1063 + * Set MDI bit in SCB status register. */ 2.1064 +done: 2.1065 + val |= BIT(28); 2.1066 + val = (val & 0xffff0000) + data; 2.1067 + CSR_WRITE(SCB_MDI, val, uint32_t); 2.1068 + 2.1069 + if ( ie ) 2.1070 + e100_interrupt(s, (uint16_t)INT_MDI); 2.1071 +} 2.1072 + 2.1073 +static void scb_mdi_func(E100State *s, uint32_t val, int dir) 2.1074 +{ 2.1075 + if ( dir == OP_READ ) 2.1076 + // Do nothing, just tell driver we are ready 2.1077 + CSR_VAL(CSR_MDI) |= BIT(28); 2.1078 + else if ( dir == OP_WRITE ) 2.1079 + e100_write_mdi(s, val); 2.1080 + else 2.1081 + logout("Invalid operation direction(dir=%x)\n", dir); 2.1082 + 2.1083 +} 2.1084 + 2.1085 +static void eeprom_reset(E100State *s, int type) 2.1086 +{ 2.1087 + eeprom_t *e = &s->eeprom; 2.1088 + 2.1089 + if ( type == EEPROM_RESET_ALL ) 2.1090 + { 2.1091 + memset(e, 0x0, sizeof(eeprom_t)); 2.1092 + e->val_type = NOP; 2.1093 + logout("EEPROM reset all\n"); 2.1094 + return; 2.1095 + } 2.1096 + 2.1097 + CSR(CSR_EEPROM, eedo) = 1; 2.1098 + e->start_bit = 0; 2.1099 + e->opcode = 0; 2.1100 + e->address = 0; 2.1101 + e->data = 0; 2.1102 + 2.1103 + e->val = 0; 2.1104 + e->val_len = 0; 2.1105 + e->val_type = NOP; 2.1106 + 2.1107 + e->cs = 0; 2.1108 + e->sk = 0; 2.1109 + logout("EEPROM select reset\n"); 2.1110 +} 2.1111 + 2.1112 +static void do_eeprom_op(E100State *s, eeprom_t *e, int cs, int sk, int di, int dir) 2.1113 +{ 2.1114 + int assert_cs = (cs == 1 && e->cs == 0); 2.1115 + int de_assert_cs = (cs == 0 && e->cs == 1); 2.1116 + int de_assert_sk = (sk == 0 && e->sk == 1); 2.1117 + 2.1118 + // Chip select is not be enabled 2.1119 + if ( cs == 0 && e->cs == 0 ) 2.1120 + { 2.1121 + logout("Invalid EECS signal\n"); 2.1122 + return; 2.1123 + } 2.1124 + 2.1125 + // update state 2.1126 + e->cs = cs; 2.1127 + e->sk = sk; 2.1128 + 2.1129 + // Do nothing 2.1130 + if ( assert_cs ) 2.1131 + { 2.1132 + logout("EECS assert\n"); 2.1133 + return; 2.1134 + } 2.1135 + 2.1136 + // Complete one command 2.1137 + if ( de_assert_cs ) 2.1138 + { 2.1139 + if ( e->val_type == DATA && e->opcode == EEPROM_WRITE ) 2.1140 + { 2.1141 + e->data = e->val; 2.1142 + memcpy((void *)((unsigned long)e->contents + e->address), 2.1143 + &e->data, sizeof(e->data)); 2.1144 + logout("EEPROM write complete(data=%#x)\n", e->data); 2.1145 + } 2.1146 + eeprom_trace(0,0,0,NOP,1); 2.1147 + eeprom_reset(s, EEPROM_SELECT_RESET); 2.1148 + logout("EECS de-asserted\n"); 2.1149 + return; 2.1150 + } 2.1151 + 2.1152 + // Chip is selected and serial clock is change, so the operation is vaild 2.1153 + if ( cs == 1 && de_assert_sk == 1) 2.1154 + { 2.1155 + // Set start bit 2.1156 + if ( e->start_bit == 0 && di == 1 ) 2.1157 + { 2.1158 + e->start_bit = di; 2.1159 + e->val_len = 0; 2.1160 + e->val = 0; 2.1161 + e->val_type = OPCODE; 2.1162 + 2.1163 + eeprom_trace(0,0,0,OPCODE,1); 2.1164 + logout("EEPROM start bit set\n"); 2.1165 + return; 2.1166 + } 2.1167 + // Data in DI is vaild 2.1168 + else if ( e->start_bit == 1 ) 2.1169 + { 2.1170 + // If current operation is eeprom read, ignore DI 2.1171 + if ( !(e->val_type == DATA && e->opcode == EEPROM_READ) ) 2.1172 + { 2.1173 + e->val = (e->val << 1) | di; 2.1174 + e->val_len ++; 2.1175 + } 2.1176 + 2.1177 + switch ( e->val_type ) 2.1178 + { 2.1179 + // Get the opcode. 2.1180 + case OPCODE: 2.1181 + eeprom_trace(CSR(CSR_EEPROM, eedo), di, e->opcode, 0, 0); 2.1182 + if ( e->val_len == 2 ) 2.1183 + { 2.1184 + e->opcode = e->val; 2.1185 + e->val = 0; 2.1186 + e->val_len = 0; 2.1187 + e->val_type = ADDR; 2.1188 + 2.1189 + eeprom_trace(0,0,0,ADDR,1); 2.1190 + logout("EEPROM get opcode(opcode name=%s,opcode=%#x )\n", 2.1191 + EEPROM_OPCODE_NAME(e->opcode), e->opcode); 2.1192 + } 2.1193 + break; 2.1194 + // Get address 2.1195 + case ADDR: 2.1196 + eeprom_trace(CSR(CSR_EEPROM, eedo), di, e->opcode, 0, 0); 2.1197 + if ( e->val_len == e->addr_len ) 2.1198 + { 2.1199 + e->address = e->val; 2.1200 + e->val = 0; 2.1201 + e->val_len = 0; 2.1202 + e->val_type = DATA; 2.1203 + 2.1204 + // We prepare data eary for later read operation 2.1205 + if ( e->opcode == EEPROM_READ ) 2.1206 + { 2.1207 + memcpy(&e->data, (void *)(e->contents + e->address), 2.1208 + sizeof(e->data)); 2.1209 + logout("EEPROM prepare data to read(addr=%#x,data=%#x)\n", 2.1210 + e->address, e->data); 2.1211 + } 2.1212 + 2.1213 + // Write dummy 0 to response to driver the address is written complete 2.1214 + CSR(CSR_EEPROM, eedo) = 0; 2.1215 + eeprom_trace(0,0,0,DATA,1); 2.1216 + logout("EEPROM get address(addr=%#x)\n", e->address); 2.1217 + } 2.1218 + break; 2.1219 + // Only do data out operation 2.1220 + case DATA: 2.1221 + if ( e->opcode == EEPROM_READ ) 2.1222 + { 2.1223 + // Start from the most significant bit 2.1224 + //uint16_t t = ((e->data & (1<<(sizeof(e->data)*8 - e->val_len - 1))) != 0); 2.1225 + uint16_t t = !!(e->data & (0x8000U >> e->val_len)); 2.1226 + 2.1227 + CSR(CSR_EEPROM, eedo) = t; 2.1228 + 2.1229 + logout("EEPROM read(reg address=%#x, reg val=%#x, do=%#x, len=%#x)\n", 2.1230 + e->address, e->data, t, e->val_len); 2.1231 + 2.1232 + if ( e->val_len > sizeof(e->data)*8 ) 2.1233 + { 2.1234 + /* Driver may do more write op to de-assert EESK, 2.1235 + * So we let EEPROM go to idle after a register be 2.1236 + * read complete 2.1237 + */ 2.1238 + e->val_type = NOP; 2.1239 + logout("Read complete\n"); 2.1240 + 2.1241 + break; 2.1242 + } 2.1243 + 2.1244 + e->val_len ++; 2.1245 + } 2.1246 + eeprom_trace(CSR(CSR_EEPROM, eedo), di, e->opcode, 0, 0); 2.1247 + // Do eerpom write when CS de-assert 2.1248 + break; 2.1249 + default: 2.1250 + break; 2.1251 + } 2.1252 + } 2.1253 + } 2.1254 + 2.1255 + return; 2.1256 +} 2.1257 + 2.1258 + 2.1259 +static void scb_eeprom_func(E100State *s, uint32_t val, int dir) 2.1260 +{ 2.1261 + int eecs = ((val & EEPROM_CS) != 0); 2.1262 + int eesk = ((val & EEPROM_SK) != 0); 2.1263 + int eedi = ((val & EEPROM_DI) != 0); 2.1264 + 2.1265 + logout("EEPROM: Old(cs=%#x, sk=%#x), New(cs=%#x, sk=%#x, di=%#x)\n", 2.1266 + s->eeprom.cs, s->eeprom.sk, eecs, eesk, eedi); 2.1267 + 2.1268 + do_eeprom_op(s, &s->eeprom, eecs, eesk, eedi, dir); 2.1269 + 2.1270 + return; 2.1271 +} 2.1272 + 2.1273 +static void e100_ru_command(E100State *s, uint8_t val) 2.1274 +{ 2.1275 + switch ( val ) 2.1276 + { 2.1277 + case RU_NOP: 2.1278 + /* Will not be here */ 2.1279 + break; 2.1280 + case RU_START: 2.1281 + /* RU start */ 2.1282 + 2.1283 + SET_RU_STATE(RU_READY); 2.1284 + logout("RU is set to ready\n"); 2.1285 + s->ru_offset = CSR_VAL(CSR_POINTER); 2.1286 + logout("RFD offset is at %#x\n", s->ru_offset); 2.1287 + break; 2.1288 + case RU_RESUME: 2.1289 + /* RU Resume */ 2.1290 + if ( GET_RU_STATE == RU_SUSPENDED ) 2.1291 + SET_RU_STATE(RU_READY); 2.1292 + logout("RU resume to ready\n"); 2.1293 + break; 2.1294 + case RU_ADDR_LOAD: 2.1295 + /* Load RU base */ 2.1296 + s->ru_base = CSR_VAL(CSR_POINTER); 2.1297 + logout("Load RU base address at %#x\n", s->ru_base); 2.1298 + break; 2.1299 + case RU_DMA_REDIRECT: 2.1300 + logout("RU DMA redirect not implemented\n"); 2.1301 + break; 2.1302 + case RU_ABORT: 2.1303 + e100_interrupt(s, INT_RNR); 2.1304 + SET_RU_STATE(RU_IDLE); 2.1305 + logout("RU abort, go to idle\n"); 2.1306 + break; 2.1307 + case RU_LOAD_HDS: 2.1308 + logout("RU load header data size(HDS) not implemented\n"); 2.1309 + default: 2.1310 + break; 2.1311 + } 2.1312 +} 2.1313 + 2.1314 +// This function will change CU's state, so CU start and 2.1315 +// CU resume must set CU's state before it 2.1316 +static void e100_execute_cb_list(E100State *s, int is_resume) 2.1317 +{ 2.1318 + 2.1319 + struct control_block cb = {0}; 2.1320 + uint32_t cb_addr; 2.1321 + 2.1322 + if ( !is_resume ) 2.1323 + s->cu_offset = CSR_VAL(CSR_POINTER); 2.1324 + 2.1325 + /* If call from CU resume, cu_offset has been set */ 2.1326 + 2.1327 + while (1) 2.1328 + { 2.1329 + cb_addr = s->cu_base + s->cu_offset; 2.1330 + cpu_physical_memory_read(cb_addr, (uint8_t *)&cb, sizeof(cb)); 2.1331 + 2.1332 + 2.1333 + switch ( cb.cmd ) 2.1334 + { 2.1335 + case CBL_NOP: 2.1336 + /* Do nothing */ 2.1337 + break; 2.1338 + case CBL_IASETUP: 2.1339 + cpu_physical_memory_read(cb_addr + 8, &s->macaddr[0], sizeof(s->macaddr)); 2.1340 + e100_dump("Setup Individual Address:", &s->macaddr[0], 6); 2.1341 + break; 2.1342 + case CBL_CONFIGURE: 2.1343 + { 2.1344 + i82557_cfg_t *cfg = &s->config; 2.1345 + 2.1346 + assert(sizeof(s->config) == 22); 2.1347 + cpu_physical_memory_read(cb_addr + 8, (uint8_t *)cfg, sizeof(s->config)); 2.1348 + logout("Setup card configuration:" 2.1349 + "\tbyte count:%d\n" 2.1350 + "\tRx FIFO limit:%d\n" 2.1351 + "\tTx FIFO limit:%d\n" 2.1352 + "\tAdaptive interframe spacing:%d\n" 2.1353 + "\tRx DMA max:%d\n" 2.1354 + "\tTX DMA max:%d\n" 2.1355 + "\tDMBC enable:%d\n" 2.1356 + "\tLate SCB:%d\n" 2.1357 + "\tTNO:%d\n" 2.1358 + "\tCI:%d\n" 2.1359 + "\tDiscard overrun RX:%d\n" 2.1360 + "\tSave bad frame:%d\n" 2.1361 + "\tDiscard short RX:%d\n" 2.1362 + "\tunderrun retry:%d\n" 2.1363 + "\tMII:%d\n" 2.1364 + "\tNSAI:%d\n" 2.1365 + "\tPreamble len:%d\n" 2.1366 + "\tloopback:%d\n" 2.1367 + "\tliner pro:%d\n" 2.1368 + "\tPRI mode:%d\n" 2.1369 + "\tinterframe spacing:%d\n" 2.1370 + "\tpromiscuous:%d\n" 2.1371 + "\tbroadcast dis:%d\n" 2.1372 + "\tCRS CDT:%d\n" 2.1373 + "\tstripping:%d\n" 2.1374 + "\tpadding:%d\n" 2.1375 + "\tRX crc:%d\n" 2.1376 + "\tforce fdx:%d\n" 2.1377 + "\tfdx enable:%d\n" 2.1378 + "\tmultiple IA:%d\n" 2.1379 + "\tmulticast all:%d\n", 2.1380 + cfg->byte_count, cfg->rx_fifo_limit, cfg->tx_fifo_limit, 2.1381 + cfg->adpt_inf_spacing, cfg->rx_dma_max_bytes, cfg->tx_dma_max_bytes, 2.1382 + cfg->dmbc_en, cfg->late_scb, cfg->tno_intr, cfg->ci_intr, 2.1383 + cfg->dis_overrun_rx, cfg->save_bad_frame, cfg->dis_short_rx, 2.1384 + cfg->underrun_retry, cfg->mii, cfg->nsai, cfg->preamble_len, 2.1385 + cfg->loopback, cfg->linear_prio, cfg->pri_mode, cfg->interframe_spacing, 2.1386 + cfg->promiscuous, cfg->broadcast_dis, cfg->crs_cdt, cfg->strip, 2.1387 + cfg->padding, cfg->rx_crc, cfg->force_fdx, cfg->fdx_en, 2.1388 + cfg->mul_ia, cfg->mul_all); 2.1389 + } 2.1390 + break; 2.1391 + case CBL_MULTCAST_ADDR_SETUP: 2.1392 + { 2.1393 + uint16_t mult_list_count = 0; 2.1394 + uint16_t size = 0; 2.1395 + 2.1396 + cpu_physical_memory_read(cb_addr + 8, (uint8_t *)&mult_list_count, 2); 2.1397 + mult_list_count = (mult_list_count << 2) >> 2; 2.1398 + 2.1399 + if ( !mult_list_count ) 2.1400 + { 2.1401 + logout("Multcast disabled(multicast count=0)\n"); 2.1402 + s->is_multcast_enable = 0; 2.1403 + memset(s->mult_list, 0x0, sizeof(s->mult_list)); 2.1404 + break; 2.1405 + } 2.1406 + size = mult_list_count > sizeof(s->mult_list) ? 2.1407 + sizeof(s->mult_list) : mult_list_count; 2.1408 + cpu_physical_memory_read(cb_addr + 12, &s->mult_list[0], size); 2.1409 + 2.1410 + e100_dump("Setup Multicast list: ", &s->mult_list[0], size); 2.1411 + break; 2.1412 + } 2.1413 + case CBL_TRANSMIT: 2.1414 + { 2.1415 + struct 2.1416 + { 2.1417 + struct control_block cb; 2.1418 + tbd_t tbd; 2.1419 + } __attribute__ ((packed)) tx; 2.1420 + 2.1421 + struct 2.1422 + { 2.1423 + uint32_t addr; 2.1424 + uint16_t size; 2.1425 + uint16_t is_el_set; 2.1426 + } tx_buf = {0}; 2.1427 + 2.1428 + uint32_t tbd_array; 2.1429 + uint16_t tcb_bytes; 2.1430 + uint8_t sf; 2.1431 + int len = s->pkt_buf_len; 2.1432 + 2.1433 + assert( len < sizeof(s->pkt_buf)); 2.1434 + 2.1435 + cpu_physical_memory_read(cb_addr, (uint8_t *)&tx, sizeof(tx)); 2.1436 + tbd_array = le32_to_cpu(tx.tbd.tx_desc_addr); 2.1437 + tcb_bytes = le16_to_cpu(tx.tbd.tcb_bytes); 2.1438 + // Indicate use what mode to transmit(simple or flexible) 2.1439 + sf = tx.cb.rs3 & 0x1; 2.1440 + 2.1441 + logout("Get a TBD:\n" 2.1442 + "\tTBD array address:%#x\n" 2.1443 + "\tTCB byte count:%#x\n" 2.1444 + "\tEOF:%#x\n" 2.1445 + "\tTransmit Threshold:%#x\n" 2.1446 + "\tTBD number:%#x\n" 2.1447 + "\tUse %s mode to send frame\n", 2.1448 + tbd_array, tcb_bytes, tx.tbd.eof, 2.1449 + tx.tbd.tx_threshold, tx.tbd.tbd_num, 2.1450 + sf ? "Flexible" : "Simple"); 2.1451 + 2.1452 + if ( !sf || tbd_array == (uint32_t)-1 ) 2.1453 + { 2.1454 + /* Simple mode */ 2.1455 + 2.1456 + /* For simple mode, TCB bytes should not be zero. 2.1457 + * But we still check here for safety 2.1458 + */ 2.1459 + if ( !tcb_bytes || tcb_bytes > sizeof(s->pkt_buf) ) 2.1460 + break; 2.1461 + 2.1462 + cpu_physical_memory_read(cb_addr+16, &s->pkt_buf[0], tcb_bytes); 2.1463 + len = tcb_bytes; 2.1464 + logout("simple mode(size=%d)\n", len); 2.1465 + 2.1466 + } 2.1467 + else 2.1468 + { 2.1469 + /* Flexible mode */ 2.1470 + 2.1471 + /* For flexible mode, TBD num should not be zero. 2.1472 + * But we still check here for safety 2.1473 + */ 2.1474 + if ( !tx.tbd.tbd_num ) 2.1475 + break; 2.1476 + 2.1477 + // I82557 don't support extend TCB 2.1478 + if ( s->device == i82557C || s->device == i82557B ) 2.1479 + { 2.1480 + /* Standard TCB mode */ 2.1481 + 2.1482 + int i; 2.1483 + 2.1484 + for ( i=0; i<tx.tbd.tbd_num; i++ ) 2.1485 + { 2.1486 + 2.1487 + cpu_physical_memory_read(tbd_array, (uint8_t *)&tx_buf, 2.1488 + sizeof(tx_buf)); 2.1489 + tx_buf.is_el_set &= 0x1; 2.1490 + tx_buf.size &= 0x7fff; 2.1491 + tbd_array += 8; 2.1492 + 2.1493 + if ( tx_buf.size > sizeof(s->pkt_buf) - len ) 2.1494 + { 2.1495 + logout("Warning: Get a too big TBD, ignore it" 2.1496 + "(buf addr %#x, size %d, el:%#x)\n", 2.1497 + tx_buf.addr, tx_buf.size, tx_buf.is_el_set); 2.1498 + continue; 2.1499 + } 2.1500 + 2.1501 + cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len], 2.1502 + tx_buf.size); 2.1503 + 2.1504 + logout("TBD (standard mode): buf addr %#x, size %d, el:%#x\n", 2.1505 + tx_buf.addr, tx_buf.size, tx_buf.is_el_set); 2.1506 + len += tx_buf.size; 2.1507 + 2.1508 + if ( tx_buf.is_el_set ) 2.1509 + break; 2.1510 + } 2.1511 + 2.1512 + } 2.1513 + //FIXME: Extend mode is not be tested 2.1514 + else 2.1515 + { 2.1516 + /* Extend TCB mode */ 2.1517 + 2.1518 + /* A strandard TCB followed by two TBDs */ 2.1519 + uint32_t tbd_addr = cb_addr+16; 2.1520 + int i = 0; 2.1521 + 2.1522 + 2.1523 + for ( ; i<2 && i<tx.tbd.tbd_num; i++ ) 2.1524 + { 2.1525 + 2.1526 + cpu_physical_memory_read(tbd_array, (uint8_t *)&tx_buf, 2.1527 + sizeof(tx_buf)); 2.1528 + tx_buf.is_el_set &= 0x1; 2.1529 + tbd_addr += 8; 2.1530 + 2.1531 + /* From Intel's spec, size of TBD equal to zero 2.1532 + * has same effect with EL bit set 2.1533 + */ 2.1534 + if ( tx_buf.size == 0 ) 2.1535 + { 2.1536 + tx_buf.is_el_set = 1; 2.1537 + break; 2.1538 + } 2.1539 + 2.1540 + if ( tx_buf.size + len > sizeof(s->pkt_buf) ) 2.1541 + { 2.1542 + logout("TX frame is too large, discarding it" 2.1543 + "(buf addr=%#x, size=%#x)\n", tx_buf.addr, 2.1544 + tx_buf.size); 2.1545 + //continue; 2.1546 + break; 2.1547 + } 2.1548 + 2.1549 + logout("TBD (extended mode): buf addr %#08x, size %#04x, el:%#x\n", 2.1550 + tx_buf.addr, tx_buf.size, tx_buf.is_el_set); 2.1551 + cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len], 2.1552 + tx_buf.size); 2.1553 + 2.1554 + len += tx_buf.size; 2.1555 + 2.1556 + if ( tx_buf.is_el_set ) 2.1557 + break; 2.1558 + } 2.1559 + 2.1560 + /* In extend TCB mode, TDB array point to the thrid TBD 2.1561 + * if it is not NULL(0xffffffff) and EL bit of before 2.1562 + * two TBDs is not set 2.1563 + */ 2.1564 + if ( tbd_array != (uint32_t)-1 && !tx_buf.is_el_set ) 2.1565 + { 2.1566 + tbd_addr = tbd_array; 2.1567 + 2.1568 + /* TBD number includes first two TBDs, so don't 2.1569 + * initialize i here 2.1570 + */ 2.1571 + for ( ; i<tx.tbd.tbd_num; i++ ) 2.1572 + { 2.1573 + cpu_physical_memory_read(tbd_addr, (uint8_t *)&tx_buf, 2.1574 + sizeof(tx_buf)); 2.1575 + tx_buf.is_el_set &= 0x1; 2.1576 + tbd_addr += 8; 2.1577 + 2.1578 + cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len], 2.1579 + tx_buf.size); 2.1580 + logout("TBD (extended mode): buf addr 0x%#08x, size 0x%#04x\n", 2.1581 + tx_buf.addr, tx_buf.size); 2.1582 + 2.1583 + len += tx_buf.size; 2.1584 + 2.1585 + if ( tx_buf.is_el_set ) 2.1586 + break; 2.1587 + } 2.1588 + } 2.1589 + } 2.1590 + } 2.1591 + 2.1592 + 2.1593 + s->pkt_buf_len = len; 2.1594 + 2.1595 +/* Below codes are used for Threshold. But with these logic, network of guest 2.1596 + * getting bad performance. So I comment it and leave codes here to hope anyone 2.1597 + * fix it 2.1598 + */ 2.1599 +#if 0 2.1600 + /* If threshold is set, only send packet when threshold 2.1601 + * bytes are read 2.1602 + */ 2.1603 + if ( tx.tbd.tx_threshold && s->pkt_buf_len < tx.tbd.tx_threshold * 8 ) 2.1604 + { 2.1605 + logout("Current data length in FIFO buffer:%d\n", s->pkt_buf_len); 2.1606 + break; 2.1607 + } 2.1608 +#endif 2.1609 + 2.1610 + if ( s->pkt_buf_len ) 2.1611 + { 2.1612 + qemu_send_packet(s->vc, s->pkt_buf, s->pkt_buf_len); 2.1613 + s->statistics.tx_good_frames ++; 2.1614 + logout("Send out frame successful(size=%d," 2.1615 + "already sent %d frames)\n", s->pkt_buf_len, 2.1616 + s->statistics.tx_good_frames); 2.1617 + s->pkt_buf_len = 0; 2.1618 + } 2.1619 + 2.1620 + e100_dump("Dest addr:", (uint8_t *)s->pkt_buf, 6); 2.1621 + e100_dump("Src addr:", (uint8_t *)(s->pkt_buf+6), 6); 2.1622 + e100_dump("type:", (uint8_t *)(s->pkt_buf+8), 2); 2.1623 + 2.1624 + break; 2.1625 + } 2.1626 + case CBL_LOAD_MICROCODE: 2.1627 +#ifdef DEBUG_E100 2.1628 + { 2.1629 + /* Don't support load marco code, just dump it */ 2.1630 + #define MICRO_CODE_LEN 256 2.1631 + uint8_t micro_code[MICRO_CODE_LEN] = {0}; 2.1632 + cpu_physical_memory_read(cb_addr+8, micro_code, MICRO_CODE_LEN); 2.1633 + e100_dump("Load micro code:", micro_code, MICRO_CODE_LEN); 2.1634 + } 2.1635 +#endif 2.1636 + break; 2.1637 + case CBL_DUMP: 2.1638 + logout("Control block dump\n"); 2.1639 + break; 2.1640 + case CBL_DIAGNOSE: 2.1641 + logout("Control block diagnose\n"); 2.1642 + break; 2.1643 + default: 2.1644 + logout("Unknown Control block command(val=%#x)\n", cb.cmd); 2.1645 + break; 2.1646 + } 2.1647 + 2.1648 + /* Now, we finished executing a command, update status of CB. 2.1649 + * We always success 2.1650 + */ 2.1651 + cb.c = 1; 2.1652 + cb.ok = 1; 2.1653 + // Only update C bit and OK bit field in TCB 2.1654 + cpu_physical_memory_write(cb_addr, (uint8_t *)&cb, 2); 2.1655 + 2.1656 + logout("Finished a command from CB list:\n" 2.1657 + "\tok:%d\n" 2.1658 + "\tc:%d\n" 2.1659 + "\tcommand name:%s(cmd=%#x)\n" 2.1660 + "\ti:%d\n" 2.1661 + "\ts:%d\n" 2.1662 + "\tel:%d\n" 2.1663 + "\tlink address:%#x\n", 2.1664 + cb.ok, cb.c, CB_CMD_NAME(cb.cmd), cb.cmd, 2.1665 + cb.i, cb.s, cb.el, cb.link_addr); 2.1666 + 2.1667 + if ( cb.i ) 2.1668 + e100_interrupt(s, (uint16_t)INT_CX_TNO); 2.1669 + 2.1670 + // Suspend CU 2.1671 + if ( cb.s ) 2.1672 + { 2.1673 + logout("CU go to suspend\n"); 2.1674 + SET_CU_STATE(CU_SUSPENDED); 2.1675 + s->cu_next = cb.link_addr; // Save it for go on executing when resume 2.1676 + 2.1677 + // Trigger CNA interrupt only when CNA mode is configured 2.1678 + if ( !(s->config.ci_intr) && cb.i ) 2.1679 + e100_interrupt(s, (uint16_t)INT_CNA); 2.1680 + 2.1681 + return; 2.1682 + } 2.1683 + 2.1684 + // This is last command in CB list, CU go back to IDLE 2.1685 + if ( cb.el ) 2.1686 + { 2.1687 + logout("Command block list is empty, CU go to idle\n"); 2.1688 + SET_CU_STATE(CU_IDLE); 2.1689 + /* Either in CNA mode or CI mode, interrupt need be triggered 2.1690 + * when CU go to idle. 2.1691 + */ 2.1692 + if ( cb.i ) 2.1693 + e100_interrupt(s, (uint16_t)INT_CNA); 2.1694 + 2.1695 + return; 2.1696 + } 2.1697 + 2.1698 + s->cu_offset = le32_to_cpu(cb.link_addr); // get next CB offset 2.1699 + } 2.1700 +} 2.1701 + 2.1702 +static void dump_statistics(E100State * s, uint32_t complete_word) 2.1703 +{ 2.1704 + /* Dump statistical data. Most data is never changed by the emulation 2.1705 + * and always 0. 2.1706 + */ 2.1707 + s->statistics.complete_word = complete_word; 2.1708 + cpu_physical_memory_write(s->statsaddr, (uint8_t *)&s->statistics, sizeof(s->statistics)); 2.1709 + 2.1710 +} 2.1711 + 2.1712 +static void e100_cu_command(E100State *s, uint8_t val) 2.1713 +{ 2.1714 + 2.1715 + switch ( val ) 2.1716 + { 2.1717 + case CU_NOP: 2.1718 + /* Will not be here */ 2.1719 + break; 2.1720 + case CU_START: 2.1721 + /* This strictly follow Intel's spec */ 2.1722 + if ( GET_CU_STATE != CU_IDLE && GET_CU_STATE != CU_SUSPENDED ) 2.1723 + { 2.1724 + logout("Illegal CU start command. Device is not idle or suspend\n"); 2.1725 + return; 2.1726 + } 2.1727 + 2.1728 + SET_CU_STATE(CU_LPQ_ACTIVE); 2.1729 + logout("CU start\n"); 2.1730 + 2.1731 + e100_execute_cb_list(s, 0); 2.1732 + break; 2.1733 + case CU_RESUME: 2.1734 + { 2.1735 + uint32_t previous_cb = s->cu_base + s->cu_offset; 2.1736 + struct control_block cb; 2.1737 + 2.1738 + /* Resume from suspend */ 2.1739 + 2.1740 + /* FIXME:From Intel's spec, CU resume from idle is 2.1741 + * forbidden, but e100 drive in linux 2.1742 + * indeed do this. 2.1743 + */ 2.1744 + if ( GET_CU_STATE == CU_IDLE ) 2.1745 + { 2.1746 + logout("Illegal resume form IDLE\n"); 2.1747 + } 2.1748 + 2.1749 + cpu_physical_memory_read(previous_cb, (uint8_t *)&cb, 2.1750 + sizeof(cb)); 2.1751 + 2.1752 + //FIXME: Need any speical handle when CU is active ? 2.1753 + 2.1754 + /* Driver must clean S bit in previous CB when 2.1755 + * it issue CU resume command 2.1756 + */ 2.1757 + if ( cb.s ) 2.1758 + { 2.1759 + logout("CU still in suspend\n"); 2.1760 + break; 2.1761 + } 2.1762 + 2.1763 + SET_CU_STATE(CU_LPQ_ACTIVE); 2.1764 + if ( cb.el ) 2.1765 + { 2.1766 + logout("CB list is empty, CU just go to active\n"); 2.1767 + break; 2.1768 + } 2.1769 + 2.1770 + // Continue next command 2.1771 + s->cu_offset = s->cu_next; 2.1772 + 2.1773 + e100_execute_cb_list(s, 1); 2.1774 + 2.1775 + logout("CU resume\n"); 2.1776 + } 2.1777 + break; 2.1778 + case CU_STATSADDR: 2.1779 + /* Load dump counters address */ 2.1780 + s->statsaddr = CSR_VAL(CSR_POINTER); 2.1781 + logout("Load Stats address at %#x\n", s->statsaddr); 2.1782 + break; 2.1783 + case CU_SHOWSTATS: 2.1784 + /* Dump statistical counters */ 2.1785 + dump_statistics(s, 0xa005); 2.1786 + logout("Execute dump statistics\n"); 2.1787 + break; 2.1788 + case CU_CMD_BASE: 2.1789 + /* Load CU base */ 2.1790 + s->cu_base = CSR_VAL(CSR_POINTER); 2.1791 + logout("Load CU base at %x\n", s->cu_base); 2.1792 + break; 2.1793 + case CU_DUMPSTATS: 2.1794 + /* Dump statistical counters and reset counters. */ 2.1795 + dump_statistics(s, 0xa007); 2.1796 + memset(&s->statistics, 0x0, sizeof(s->statistics)); 2.1797 + logout("Execute dump and reset statistics\n"); 2.1798 + break; 2.1799 + case CU_S_RESUME: 2.1800 + /* CU static resume */ 2.1801 + logout("CU static resume is not implemented\n"); 2.1802 + break; 2.1803 + default: 2.1804 + logout("Unknown CU command(val=%#x)\n", val); 2.1805 + break; 2.1806 + } 2.1807 + 2.1808 +} 2.1809 + 2.1810 +static void scb_cmd_func(E100State *s, uint16_t val, int dir) 2.1811 +{ 2.1812 + /* ignore NOP operation */ 2.1813 + if ( val & 0x0f ) 2.1814 + { 2.1815 + e100_ru_command(s, val & 0x0f); 2.1816 + CSR(CSR_CMD, ru_cmd) = 0; 2.1817 + } 2.1818 + else if ( val & 0xf0 ) 2.1819 + { 2.1820 + e100_cu_command(s, val & 0xf0); 2.1821 + CSR(CSR_CMD, cu_cmd) = 0; 2.1822 + } 2.1823 + 2.1824 +} 2.1825 + 2.1826 +enum 2.1827 +{ 2.1828 + WRITEB, 2.1829 + WRITEW, 2.1830 + WRITEL, 2.1831 + OP_IS_READ, 2.1832 +} WRITE_BYTES; 2.1833 + 2.1834 +/* Driver may issue a command by writting one 32bit-entry, 2.1835 + * two 16bit-entries or four 8bit-entries. In late two case, we 2.1836 + * must wait until driver finish writting to the highest byte. The parameter 2.1837 + * 'bytes' means write action of driver(writeb, wirtew, wirtel) 2.1838 + */ 2.1839 +static void e100_execute(E100State *s, uint32_t addr_offset, 2.1840 + uint32_t val, int dir, int bytes) 2.1841 +{ 2.1842 + 2.1843 + switch ( addr_offset ) 2.1844 + { 2.1845 + case SCB_STATUS: 2.1846 + if ( bytes == WRITEB ) 2.1847 + break; 2.1848 + case SCB_ACK: 2.1849 + if ( dir == OP_WRITE ) 2.1850 + { 2.1851 + uint8_t _val = 0; 2.1852 + if ( bytes == WRITEB ) 2.1853 + _val = (uint8_t)val; 2.1854 + else if ( bytes == WRITEW ) 2.1855 + _val = ((uint16_t)val) >> 8; 2.1856 + else if ( bytes == WRITEL) 2.1857 + { 2.1858 + // This should not be happen 2.1859 + _val = ((uint16_t)val) >> 8; 2.1860 + logout("WARNNING: Drvier write 4 bytes to CSR register at offset %d," 2.1861 + "emulator may do things wrong!!!\n", addr_offset); 2.1862 + } 2.1863 + 2.1864 + e100_interrupt_ack(s, _val); 2.1865 + } 2.1866 + break; 2.1867 + case SCB_CMD: 2.1868 + if ( dir == OP_WRITE ) 2.1869 + scb_cmd_func(s, val, dir); 2.1870 + 2.1871 +/* I don't know whether there is any driver writes command words and 2.1872 + * interrupt mask at same time by two bytes. This is not a regular operation. 2.1873 + * but if we meet the case, below codes could copy with it. As far 2.1874 + * as I know. windows's and linux's driver don't do this thing. 2.1875 + */ 2.1876 +#if 0 2.1877 + if ( bytes == WRITEW && (val&0xff00) != 0 ) 2.1878 + ; 2.1879 + else 2.1880 + break; 2.1881 +#endif 2.1882 + break; 2.1883 + case SCB_INTERRUPT_MASK: 2.1884 + if ( dir == OP_WRITE ) 2.1885 + { 2.1886 + uint8_t _val = 0; 2.1887 + if ( bytes == WRITEB ) 2.1888 + _val = (uint8_t)val; 2.1889 + else if ( bytes == WRITEW ) 2.1890 + _val = (val & 0xff00) >> 8; 2.1891 + else 2.1892 + logout("WARNNING: Drvier write 4 bytes to CSR register at offset %d," 2.1893 + "emulator may do things wrong!!!\n", addr_offset); 2.1894 + 2.1895 + // Driver generates a software interrupt 2.1896 + if ( _val & BIT(1) ) 2.1897 + e100_interrupt(s, INT_SWI); 2.1898 + } 2.1899 + break; 2.1900 + case SCB_PORT ... SCB_PORT + 3: 2.1901 + if ( dir == OP_WRITE ) 2.1902 + { 2.1903 + // Waitting for driver write to the highest byte 2.1904 + if ( (bytes == WRITEB && addr_offset != SCB_PORT + 3) || 2.1905 + (bytes == WRITEW && addr_offset != SCB_PORT + 2) ) 2.1906 + break; 2.1907 + 2.1908 + scb_port_func(s, CSR_VAL(CSR_PORT), dir); 2.1909 + } 2.1910 + break; 2.1911 + case SCB_MDI ... SCB_MDI + 3: 2.1912 + if ( dir == OP_WRITE ) 2.1913 + { 2.1914 + // Waitting for driver write to the highest byte 2.1915 + if ( (bytes == WRITEB && addr_offset != SCB_MDI + 3) || 2.1916 + (bytes == WRITEW && addr_offset != SCB_MDI + 2) ) 2.1917 + break; 2.1918 + } 2.1919 + 2.1920 + scb_mdi_func(s, CSR_VAL(CSR_MDI), dir); 2.1921 + break; 2.1922 + case SCB_EEPROM: 2.1923 + if ( dir == OP_WRITE ) 2.1924 + scb_eeprom_func(s, val, dir); 2.1925 + // Nothing need do when driver read EEPROM registers of CSR 2.1926 + break; 2.1927 + case SCB_POINTER: 2.1928 + break; 2.1929 + default: 2.1930 + logout("Driver operate on CSR reg(offset=%#x,dir=%s,val=%#x)\n", 2.1931 + addr_offset, dir==OP_WRITE?"write":"read", val); 2.1932 + } 2.1933 + 2.1934 +} 2.1935 + 2.1936 +/* MMIO access functions */ 2.1937 +static uint8_t e100_read1(E100State * s, uint32_t addr_offset) 2.1938 +{ 2.1939 + uint8_t val = -1; 2.1940 + 2.1941 + if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) ) 2.1942 + { 2.1943 + logout("Invaild read, beyond memory boundary(addr:%#x)\n", addr_offset 2.1944 + + s->region_base_addr[CSR_MEMORY_BASE]); 2.1945 + return val; 2.1946 + } 2.1947 + 2.1948 + 2.1949 + e100_execute(s, addr_offset, val, OP_READ, OP_IS_READ); 2.1950 + val = CSR_READ(addr_offset, uint8_t); 2.1951 + logout("READ1: Register name = %s, addr_offset = %#x, val=%#x\n", SCBNAME(addr_offset), addr_offset, val); 2.1952 + 2.1953 + return val; 2.1954 +} 2.1955 + 2.1956 +static uint16_t e100_read2(E100State * s, uint32_t addr_offset) 2.1957 +{ 2.1958 + uint16_t val = -1; 2.1959 + 2.1960 + if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) ) 2.1961 + { 2.1962 + logout("Invaild read, beyond memory boundary(addr:%#x)\n", addr_offset 2.1963 + + s->region_base_addr[CSR_MEMORY_BASE]); 2.1964 + return val; 2.1965 + } 2.1966 + 2.1967 + e100_execute(s, addr_offset, val, OP_READ, OP_IS_READ); 2.1968 + val = CSR_READ(addr_offset, uint16_t); 2.1969 + logout("READ2: Register name = %s, addr_offset = %#x, val=%#x\n", SCBNAME(addr_offset), addr_offset, val); 2.1970 + 2.1971 + return val; 2.1972 + 2.1973 +} 2.1974 + 2.1975 +static uint32_t e100_read4(E100State * s, uint32_t addr_offset) 2.1976 +{ 2.1977 + uint32_t val = -1; 2.1978 + 2.1979 + if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) ) 2.1980 + { 2.1981 + logout("Invaild read, beyond memory boundary(addr:%#x)\n", addr_offset 2.1982 + + s->region_base_addr[CSR_MEMORY_BASE]); 2.1983 + return val; 2.1984 + } 2.1985 + 2.1986 + e100_execute(s, addr_offset, val, OP_READ, OP_IS_READ); 2.1987 + val = CSR_READ(addr_offset, uint32_t); 2.1988 + logout("READ4: Register name = %s, addr_offset = %#x, val=%#x\n", SCBNAME(addr_offset), addr_offset, val); 2.1989 + 2.1990 + return val; 2.1991 + 2.1992 +} 2.1993 + 2.1994 +static uint32_t pci_mmio_readb(void *opaque, target_phys_addr_t addr) 2.1995 +{ 2.1996 + E100State *s = opaque; 2.1997 + addr -= s->region_base_addr[CSR_MEMORY_BASE]; 2.1998 + return e100_read1(s, addr); 2.1999 +} 2.2000 + 2.2001 +static uint32_t pci_mmio_readw(void *opaque, target_phys_addr_t addr) 2.2002 +{ 2.2003 + E100State *s = opaque; 2.2004 + addr -= s->region_base_addr[CSR_MEMORY_BASE]; 2.2005 + return e100_read2(s, addr); 2.2006 +} 2.2007 + 2.2008 +static uint32_t pci_mmio_readl(void *opaque, target_phys_addr_t addr) 2.2009 +{ 2.2010 + E100State *s = opaque; 2.2011 + addr -= s->region_base_addr[CSR_MEMORY_BASE]; 2.2012 + return e100_read4(s, addr); 2.2013 +} 2.2014 + 2.2015 +static CPUReadMemoryFunc *pci_mmio_read[] = { 2.2016 + pci_mmio_readb, 2.2017 + pci_mmio_readw, 2.2018 + pci_mmio_readl 2.2019 +}; 2.2020 + 2.2021 +static void e100_write1(E100State * s, uint32_t addr_offset, uint8_t val) 2.2022 +{ 2.2023 + if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) ) 2.2024 + { 2.2025 + logout("Invaild write, beyond memory boundary(addr = %#x, val = %#x\n", addr_offset 2.2026 + + s->region_base_addr[CSR_MEMORY_BASE], val); 2.2027 + return; 2.2028 + } 2.2029 + 2.2030 + // SCB stauts is read-only word, can not be directly write 2.2031 + if ( addr_offset == SCB_STATUS ) 2.2032 + { 2.2033 + return; 2.2034 + } 2.2035 + // EEDO bit of eeprom register is read-only, can not be written; 2.2036 + else if ( addr_offset == SCB_EEPROM ) 2.2037 + { 2.2038 + int eedo = BIT(3) & CSR_VAL(CSR_EEPROM); 2.2039 + CSR_WRITE(addr_offset, val, uint8_t); 2.2040 + CSR(CSR_EEPROM, eedo) = !!(eedo & EEPROM_DO); 2.2041 + 2.2042 + logout("WRITE1: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, (uint8_t)CSR_VAL(CSR_EEPROM)); 2.2043 + return; 2.2044 + } 2.2045 + else 2.2046 + { 2.2047 + CSR_WRITE(addr_offset, val, uint8_t); 2.2048 + } 2.2049 + 2.2050 + logout("WRITE1: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, val); 2.2051 + return; 2.2052 +} 2.2053 + 2.2054 +static void e100_write2(E100State * s, uint32_t addr_offset, uint16_t val) 2.2055 +{ 2.2056 + if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) ) 2.2057 + { 2.2058 + logout("Invaild write, beyond memory boundary(addr = %#x, val = %#x\n", addr_offset 2.2059 + + s->region_base_addr[CSR_MEMORY_BASE], val); 2.2060 + return; 2.2061 + } 2.2062 + 2.2063 + // SCB stauts is readonly word, can not be directly write 2.2064 + if ( addr_offset == SCB_STATUS ) 2.2065 + { 2.2066 + uint8_t __val = val >> 8; 2.2067 + CSR_WRITE(addr_offset+1, __val, uint8_t); 2.2068 + } 2.2069 + // EEDO bit of eeprom register is read-only, can not be written; 2.2070 + else if ( addr_offset == SCB_EEPROM ) 2.2071 + { 2.2072 + int eedo = BIT(3) & CSR_VAL(CSR_EEPROM); 2.2073 + CSR_WRITE(addr_offset, val, uint16_t); 2.2074 + CSR(CSR_EEPROM, eedo) = !!(eedo & EEPROM_DO); 2.2075 + 2.2076 + logout("WRITE1: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, CSR_VAL(CSR_EEPROM)); 2.2077 + return; 2.2078 + } 2.2079 + else 2.2080 + { 2.2081 + CSR_WRITE(addr_offset, val, uint16_t); 2.2082 + } 2.2083 + 2.2084 + logout("WRITE2: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, val); 2.2085 + return; 2.2086 +} 2.2087 + 2.2088 +static void e100_write4(E100State * s, uint32_t addr_offset, uint32_t val) 2.2089 +{ 2.2090 + if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) ) 2.2091 + { 2.2092 + logout("Invaild write, beyond memory boundary(addr = %#x, val = %#x\n", addr_offset 2.2093 + + s->region_base_addr[CSR_MEMORY_BASE], val); 2.2094 + return; 2.2095 + } 2.2096 + 2.2097 + // SCB stauts is readonly word, can not be directly write 2.2098 + if ( addr_offset == SCB_STATUS ) 2.2099 + { 2.2100 + uint8_t __val[4] = {0}; 2.2101 + 2.2102 + //FIXME: any un-aligned reference ? 2.2103 + *(uint32_t *)&__val = val; 2.2104 + 2.2105 + CSR_WRITE(addr_offset+1, __val[1], uint8_t); 2.2106 + CSR_WRITE(addr_offset+2, __val[2], uint8_t); 2.2107 + CSR_WRITE(addr_offset+3, __val[3], uint8_t); 2.2108 + } 2.2109 + /* No write4 opertaion on EEPROM register */ 2.2110 + else 2.2111 + { 2.2112 + CSR_WRITE(addr_offset, val, uint32_t); 2.2113 + } 2.2114 + 2.2115 + logout("WRITE4: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, val); 2.2116 + return; 2.2117 +} 2.2118 + 2.2119 +static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) 2.2120 +{ 2.2121 + E100State *s = opaque; 2.2122 + addr -= s->region_base_addr[CSR_MEMORY_BASE]; 2.2123 + e100_write1(s, addr, val); 2.2124 + e100_execute(s, addr, val, OP_WRITE, WRITEB); 2.2125 +} 2.2126 + 2.2127 +static void pci_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) 2.2128 +{ 2.2129 + E100State *s = opaque; 2.2130 + addr -= s->region_base_addr[CSR_MEMORY_BASE]; 2.2131 + e100_write2(s, addr, val); 2.2132 + e100_execute(s, addr, val, OP_WRITE, WRITEW); 2.2133 +} 2.2134 + 2.2135 +static void pci_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) 2.2136 +{ 2.2137 + E100State *s = opaque; 2.2138 + addr -= s->region_base_addr[CSR_MEMORY_BASE]; 2.2139 + e100_write4(s, addr, val); 2.2140 + (void)e100_execute(s, addr, val, OP_WRITE, WRITEL); 2.2141 +} 2.2142 + 2.2143 +static CPUWriteMemoryFunc *pci_mmio_write[] = { 2.2144 + pci_mmio_writeb, 2.2145 + pci_mmio_writew, 2.2146 + pci_mmio_writel 2.2147 +}; 2.2148 + 2.2149 +static void pci_mmio_map(PCIDevice * pci_dev, int region_num, 2.2150 + uint32_t addr, uint32_t size, int type) 2.2151 +{ 2.2152 + PCIE100State *d = (PCIE100State *) pci_dev; 2.2153 + 2.2154 + logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n", 2.2155 + region_num, addr, size, type); 2.2156 + 2.2157 + if ( region_num == CSR_MEMORY_BASE ) { 2.2158 + /* Map control / status registers. */ 2.2159 + cpu_register_physical_memory(addr, size, d->e100.mmio_index); 2.2160 + d->e100.region_base_addr[region_num] = addr; 2.2161 + } 2.2162 +} 2.2163 + 2.2164 +/* IO access functions */ 2.2165 +static void ioport_write1(void *opaque, uint32_t addr, uint32_t val) 2.2166 +{ 2.2167 + E100State *s = opaque; 2.2168 + addr -= s->region_base_addr[CSR_IO_BASE]; 2.2169 + e100_write1(s, addr, val); 2.2170 + (void)e100_execute(s, addr, (uint32_t)val, OP_WRITE, WRITEB); 2.2171 +} 2.2172 + 2.2173 +static void ioport_write2(void *opaque, uint32_t addr, uint32_t val) 2.2174 +{ 2.2175 + E100State *s = opaque; 2.2176 + addr -= s->region_base_addr[CSR_IO_BASE]; 2.2177 + e100_write2(s, addr, val); 2.2178 + (void)e100_execute(s, addr, (uint32_t)val, OP_WRITE, WRITEW); 2.2179 +} 2.2180 + 2.2181 +static void ioport_write4(void *opaque, uint32_t addr, uint32_t val) 2.2182 +{ 2.2183 + E100State *s = opaque; 2.2184 + addr -= s->region_base_addr[CSR_IO_BASE]; 2.2185 + e100_write4(s, addr, val); 2.2186 + (void)e100_execute(s, addr, (uint32_t)val, OP_WRITE, WRITEL); 2.2187 +} 2.2188 + 2.2189 +static uint32_t ioport_read1(void *opaque, uint32_t addr) 2.2190 +{ 2.2191 + E100State *s = opaque; 2.2192 + addr -= s->region_base_addr[CSR_IO_BASE]; 2.2193 + return e100_read1(s, addr); 2.2194 +} 2.2195 + 2.2196 +static uint32_t ioport_read2(void *opaque, uint32_t addr) 2.2197 +{ 2.2198 + E100State *s = opaque; 2.2199 + addr -= s->region_base_addr[CSR_IO_BASE]; 2.2200 + return e100_read2(s, addr); 2.2201 +} 2.2202 + 2.2203 +static uint32_t ioport_read4(void *opaque, uint32_t addr) 2.2204 +{ 2.2205 + E100State *s = opaque; 2.2206 + addr -= s->region_base_addr[CSR_IO_BASE]; 2.2207 + return e100_read4(s, addr); 2.2208 +} 2.2209 + 2.2210 +static void pci_ioport_map(PCIDevice * pci_dev, int region_num, 2.2211 + uint32_t addr, uint32_t size, int type) 2.2212 +{ 2.2213 + PCIE100State *d = (PCIE100State *) pci_dev; 2.2214 + E100State *s = &d->e100; 2.2215 + 2.2216 + logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n", 2.2217 + region_num, addr, size, type); 2.2218 + 2.2219 + if ( region_num != 1 ) 2.2220 + { 2.2221 + logout("Invaid region number!\n"); 2.2222 + return; 2.2223 + } 2.2224 + 2.2225 + register_ioport_write(addr, size, 1, ioport_write1, s); 2.2226 + register_ioport_read(addr, size, 1, ioport_read1, s); 2.2227 + register_ioport_write(addr, size, 2, ioport_write2, s); 2.2228 + register_ioport_read(addr, size, 2, ioport_read2, s); 2.2229 + register_ioport_write(addr, size, 4, ioport_write4, s); 2.2230 + register_ioport_read(addr, size, 4, ioport_read4, s); 2.2231 + 2.2232 + s->region_base_addr[region_num] = addr; 2.2233 +} 2.2234 + 2.2235 +/* From FreeBSD */ 2.2236 +#define POLYNOMIAL 0x04c11db6 2.2237 +static int compute_mcast_idx(const uint8_t *ep) 2.2238 +{ 2.2239 + uint32_t crc; 2.2240 + int carry, i, j; 2.2241 + uint8_t b; 2.2242 + 2.2243 + crc = 0xffffffff; 2.2244 + for (i = 0; i < 6; i++) { 2.2245 + b = *ep++; 2.2246 + for (j = 0; j < 8; j++) { 2.2247 + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); 2.2248 + crc <<= 1; 2.2249 + b >>= 1; 2.2250 + if (carry) 2.2251 + crc = ((crc ^ POLYNOMIAL) | carry); 2.2252 + } 2.2253 + } 2.2254 + return (crc >> 26); 2.2255 +} 2.2256 + 2.2257 +/* Eerpro100 receive functions */ 2.2258 +static int e100_can_receive(void *opaque) 2.2259 +{ 2.2260 + E100State *s = opaque; 2.2261 + 2.2262 + int is_ready = (GET_RU_STATE == RU_READY); 2.2263 + logout("%s\n", is_ready ? "EEPro100 receiver is ready" 2.2264 + : "EEPro100 receiver is not ready"); 2.2265 + return is_ready; 2.2266 +} 2.2267 + 2.2268 +static void e100_receive(void *opaque, const uint8_t * buf, int size) 2.2269 +{ 2.2270 + E100State *s = opaque; 2.2271 + uint32_t rfd_addr = 0; 2.2272 + rfd_t rfd = {0}; 2.2273 + 2.2274 + 2.2275 + if ( GET_RU_STATE != RU_READY ) 2.2276 + { 2.2277 + //logout("RU is not ready. Begin discarding frame(state=%x)\n", GET_RU_STATE); 2.2278 + return; 2.2279 + } 2.2280 + 2.2281 + rfd_addr = s->ru_base + s->ru_offset; 2.2282 + cpu_physical_memory_read(rfd_addr, (uint8_t *)&rfd, sizeof(rfd_t)); 2.2283 + 2.2284 + if ( (size > MAX_ETH_FRAME_SIZE+4) ) 2.2285 + { 2.2286 + /* Long frame and configuration byte 18/3 (long receive ok) not set: 2.2287 + * Long frames are discarded. */ 2.2288 + logout("Discard long frame(size=%d)\n", size); 2.2289 + 2.2290 + return; 2.2291 + } 2.2292 + else if ( !memcmp(buf, s->macaddr, sizeof(s->macaddr)) ) 2.2293 + { 2.2294 + /* The frame is for me */ 2.2295 + logout("Receive a frame for me(size=%d)\n", size); 2.2296 + e100_dump("FRAME:", (uint8_t *)buf, size); 2.2297 + } 2.2298 + else if ( !memcmp(buf, broadcast_macaddr, sizeof(broadcast_macaddr)) ) 2.2299 + { 2.2300 + if ( s->config.broadcast_dis && !s->config.promiscuous ) 2.2301 + { 2.2302 + logout("Discard a broadcast frame\n"); 2.2303 + return; 2.2304 + } 2.2305 + 2.2306 + /* Broadcast frame */ 2.2307 + rfd.status |= RX_IA_MATCH; 2.2308 + logout("Receive a broadcast frame(size=%d)\n", size); 2.2309 + } 2.2310 + else if ( s->is_multcast_enable && buf[0] & 0x1 ) 2.2311 + { 2.2312 + int mcast_idx = compute_mcast_idx(buf); 2.2313 + if ( !(s->mult_list[mcast_idx >> 3] & (1 << (mcast_idx & 7))) ) 2.2314 + { 2.2315 + logout("Multicast address mismatch, discard\n"); 2.2316 + return; 2.2317 + } 2.2318 + logout("Receive a multicast frame(size=%d)\n", size); 2.2319 + } 2.2320 + else if ( size < 64 && (s->config.dis_short_rx) ) 2.2321 + { 2.2322 + /* From Intel's spec, short frame should be discarded 2.2323 + * when configuration byte 7/0 (discard short receive) set. 2.2324 + * But this will cause frame lossing such as ICMP frame, ARP frame. 2.2325 + * So we check is the frame for me before discarding short frame 2.2326 + */ 2.2327 + 2.2328 + /* Save Bad Frame bit */ 2.2329 + if ( s->config.save_bad_frame ) 2.2330 + { 2.2331 + rfd.status |= RX_SHORT; 2.2332 + s->statistics.rx_short_frame_errors ++; 2.2333 + } 2.2334 + logout("Receive a short frame(size=%d), discard it\n", size); 2.2335 + return; 2.2336 + } 2.2337 + else if ( s->config.promiscuous ) 2.2338 + { 2.2339 + /* Promiscuous: receive all. No address match */ 2.2340 + logout("Received frame in promiscuous mode(size=%d)\n", size); 2.2341 + rfd.status |= RX_NO_MATCH; 2.2342 + } 2.2343 + else 2.2344 + { 2.2345 + e100_dump("Unknown frame, MAC = ", (uint8_t *)buf, 6); 2.2346 + return; 2.2347 + } 2.2348 + e100_dump("Get frame, MAC = ", (uint8_t *)buf, 6); 2.2349 + 2.2350 + rfd.c = 1; 2.2351 + rfd.ok = 1; 2.2352 + rfd.f = 1; 2.2353 + rfd.eof = 1; 2.2354 + rfd.status &= ~RX_COLLISION; 2.2355 + rfd.count = size; 2.2356 + 2.2357 + logout("Get a RFD configure:\n" 2.2358 + "\tstatus:%#x\n" 2.2359 + "\tok:%#x\n" "\tc:%#x\n" "\tsf:%#x\n" 2.2360 + "\th:%#x\n" "\ts:%#x\n" "\tel:%#x\n" 2.2361 + "\tlink add:%#x\n" "\tactual count:%#x\n" 2.2362 + "\tf:%#x\n" "\teof:%#x\n" "\tsize:%#x\n", 2.2363 + rfd.status, rfd.ok, rfd.c, rfd.sf, rfd.h, 2.2364 + rfd.s, rfd.el, rfd.link_addr, rfd.count, 2.2365 + rfd.f, rfd.eof, rfd.size); 2.2366 + 2.2367 + cpu_physical_memory_write(rfd_addr, (uint8_t *)&rfd, sizeof(rfd)); 2.2368 + cpu_physical_memory_write(rfd_addr + sizeof(rfd_t), buf, size); 2.2369 + s->statistics.rx_good_frames ++; 2.2370 + s->ru_offset = le32_to_cpu(rfd.link_addr); 2.2371 + 2.2372 + e100_interrupt(s, INT_FR); 2.2373 + 2.2374 + if ( rfd.el || rfd.s ) 2.2375 + { 2.2376 + /* Go to suspend */ 2.2377 + SET_RU_STATE(RU_SUSPENDED); 2.2378 + e100_interrupt(s, INT_RNR); 2.2379 + logout("RFD met S or EL bit set, RU go to suspend\n"); 2.2380 + return; 2.2381 + } 2.2382 + 2.2383 + logout("Complete a frame receive(size = %d)\n", size); 2.2384 + return; 2.2385 +} 2.2386 + 2.2387 +static void eeprom_init(E100State *s) 2.2388 +{ 2.2389 + int i; 2.2390 + int chksum = 0; 2.2391 + /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM, 2.2392 + * i82559 and later support 64 or 256 word EEPROM. */ 2.2393 + eeprom_reset(s, EEPROM_RESET_ALL); 2.2394 + s->eeprom.addr_len = EEPROM_I82557_ADDRBIT; 2.2395 + memcpy(s->eeprom.contents, eeprom_i82557, sizeof(eeprom_i82557)); 2.2396 + /* Dirver is going to get MAC from eeprom*/ 2.2397 + memcpy((uint8_t *)s->eeprom.contents, s->macaddr, sizeof(s->macaddr)); 2.2398 + 2.2399 + /* The last word in eeprom saving checksum value. 2.2400 + * After we update MAC in eeprom, the checksum need be re-calculate 2.2401 + * and saved at the end of eeprom 2.2402 + */ 2.2403 + for ( i=0; i<(1<<s->eeprom.addr_len)-1; i++ ) 2.2404 + chksum += s->eeprom.contents[i]; 2.2405 + s->eeprom.contents[i] = 0xBABA - chksum; 2.2406 + 2.2407 +} 2.2408 + 2.2409 +static void e100_init(PCIBus * bus, NICInfo * nd, 2.2410 + const char *name, uint32_t device) 2.2411 +{ 2.2412 + PCIE100State *d; 2.2413 + E100State *s; 2.2414 + 2.2415 + logout("\n"); 2.2416 + 2.2417 + d = (PCIE100State *) pci_register_device(bus, name, 2.2418 + sizeof(PCIE100State), -1, 2.2419 + NULL, NULL); 2.2420 + 2.2421 + s = &d->e100; 2.2422 + s->device = device; 2.2423 + s->pci_dev = &d->dev; 2.2424 + 2.2425 + pci_reset(s); 2.2426 + 2.2427 + 2.2428 + /* Handler for memory-mapped I/O */ 2.2429 + d->e100.mmio_index = 2.2430 + cpu_register_io_memory(0, pci_mmio_read, pci_mmio_write, s); 2.2431 + 2.2432 + //CSR Memory mapped base 2.2433 + pci_register_io_region(&d->dev, 0, PCI_MEM_SIZE, 2.2434 + PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_MEM_PREFETCH, 2.2435 + pci_mmio_map); 2.2436 + //CSR I/O mapped base 2.2437 + pci_register_io_region(&d->dev, 1, PCI_IO_SIZE, PCI_ADDRESS_SPACE_IO, 2.2438 + pci_ioport_map); 2.2439 + //Flash memory mapped base 2.2440 + pci_register_io_region(&d->dev, 2, PCI_FLASH_SIZE, PCI_ADDRESS_SPACE_MEM, 2.2441 + pci_mmio_map); 2.2442 + 2.2443 + memcpy(s->macaddr, nd->macaddr, 6); 2.2444 + e100_dump("MAC ADDR", (uint8_t *)&s->macaddr[0], 6); 2.2445 + 2.2446 + eeprom_init(s); 2.2447 + 2.2448 + e100_reset(s); 2.2449 + 2.2450 + s->vc = qemu_new_vlan_client(nd->vlan, e100_receive, e100_can_receive, s); 2.2451 + 2.2452 + snprintf(s->vc->info_str, sizeof(s->vc->info_str), 2.2453 + "e100 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", 2.2454 + s->macaddr[0], 2.2455 + s->macaddr[1], 2.2456 + s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]); 2.2457 + 2.2458 + qemu_register_reset(e100_reset, s); 2.2459 + 2.2460 + register_savevm(name, 0, 3, e100_save, e100_load, s); 2.2461 +} 2.2462 + 2.2463 +void pci_e100_init(PCIBus * bus, NICInfo * nd) 2.2464 +{ 2.2465 + e100_init(bus, nd, "e100", i82557C); 2.2466 +} 2.2467 +
3.1 --- a/tools/ioemu/hw/pci.c Tue Nov 20 11:53:44 2007 -0700 3.2 +++ b/tools/ioemu/hw/pci.c Wed Nov 21 09:12:06 2007 -0700 3.3 @@ -565,6 +565,8 @@ void pci_nic_init(PCIBus *bus, NICInfo * 3.4 pci_rtl8139_init(bus, nd, devfn); 3.5 } else if (strcmp(nd->model, "pcnet") == 0) { 3.6 pci_pcnet_init(bus, nd, devfn); 3.7 + } else if (strcmp(nd->model, "e100") == 0) { 3.8 + pci_e100_init(bus, nd); 3.9 } else { 3.10 fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); 3.11 exit (1);
4.1 --- a/xen/arch/x86/hvm/hpet.c Tue Nov 20 11:53:44 2007 -0700 4.2 +++ b/xen/arch/x86/hvm/hpet.c Wed Nov 21 09:12:06 2007 -0700 4.3 @@ -127,9 +127,13 @@ static inline int hpet_check_access_leng 4.4 { 4.5 if ( (addr & (len - 1)) || (len > 8) ) 4.6 { 4.7 - gdprintk(XENLOG_ERR, "HPET: access across register boundary: " 4.8 + /* 4.9 + * According to ICH9 specification, unaligned accesses may result 4.10 + * in unexpected behaviour or master abort, but should not crash/hang. 4.11 + * Hence we read all-ones, drop writes, and log a warning. 4.12 + */ 4.13 + gdprintk(XENLOG_WARNING, "HPET: access across register boundary: " 4.14 "%lx %lx\n", addr, len); 4.15 - domain_crash(current->domain); 4.16 return -EINVAL; 4.17 } 4.18
5.1 --- a/xen/arch/x86/irq.c Tue Nov 20 11:53:44 2007 -0700 5.2 +++ b/xen/arch/x86/irq.c Wed Nov 21 09:12:06 2007 -0700 5.3 @@ -15,7 +15,6 @@ 5.4 #include <xen/keyhandler.h> 5.5 #include <xen/compat.h> 5.6 #include <asm/current.h> 5.7 -#include <asm/smpboot.h> 5.8 #include <asm/iommu.h> 5.9 5.10 /* opt_noirqbalance: If true, software IRQ balancing/affinity is disabled. */
6.1 --- a/xen/arch/x86/mm.c Tue Nov 20 11:53:44 2007 -0700 6.2 +++ b/xen/arch/x86/mm.c Wed Nov 21 09:12:06 2007 -0700 6.3 @@ -3007,7 +3007,8 @@ long set_gdt(struct vcpu *v, 6.4 return -EINVAL; 6.5 6.6 /* Check the pages in the new GDT. */ 6.7 - for ( i = 0; i < nr_pages; i++ ) { 6.8 + for ( i = 0; i < nr_pages; i++ ) 6.9 + { 6.10 mfn = frames[i] = gmfn_to_mfn(d, frames[i]); 6.11 if ( !mfn_valid(mfn) || 6.12 !get_page_and_type(mfn_to_page(mfn), d, PGT_gdt_page) ) 6.13 @@ -3073,23 +3074,15 @@ long do_update_descriptor(u64 pa, u64 de 6.14 6.15 *(u64 *)&d = desc; 6.16 6.17 - LOCK_BIGLOCK(dom); 6.18 - 6.19 mfn = gmfn_to_mfn(dom, gmfn); 6.20 if ( (((unsigned int)pa % sizeof(struct desc_struct)) != 0) || 6.21 !mfn_valid(mfn) || 6.22 !check_descriptor(dom, &d) ) 6.23 - { 6.24 - UNLOCK_BIGLOCK(dom); 6.25 return -EINVAL; 6.26 - } 6.27 6.28 page = mfn_to_page(mfn); 6.29 if ( unlikely(!get_page(page, dom)) ) 6.30 - { 6.31 - UNLOCK_BIGLOCK(dom); 6.32 return -EINVAL; 6.33 - } 6.34 6.35 /* Check if the given frame is in use in an unsafe context. */ 6.36 switch ( page->u.inuse.type_info & PGT_type_mask ) 6.37 @@ -3112,7 +3105,7 @@ long do_update_descriptor(u64 pa, u64 de 6.38 6.39 /* All is good so make the update. */ 6.40 gdt_pent = map_domain_page(mfn); 6.41 - memcpy(&gdt_pent[offset], &d, 8); 6.42 + atomic_write64((uint64_t *)&gdt_pent[offset], *(uint64_t *)&d); 6.43 unmap_domain_page(gdt_pent); 6.44 6.45 put_page_type(page); 6.46 @@ -3122,8 +3115,6 @@ long do_update_descriptor(u64 pa, u64 de 6.47 out: 6.48 put_page(page); 6.49 6.50 - UNLOCK_BIGLOCK(dom); 6.51 - 6.52 return ret; 6.53 } 6.54
7.1 --- a/xen/arch/x86/physdev.c Tue Nov 20 11:53:44 2007 -0700 7.2 +++ b/xen/arch/x86/physdev.c Wed Nov 21 09:12:06 2007 -0700 7.3 @@ -8,7 +8,6 @@ 7.4 #include <xen/event.h> 7.5 #include <xen/guest_access.h> 7.6 #include <asm/current.h> 7.7 -#include <asm/smpboot.h> 7.8 #include <asm/hypercall.h> 7.9 #include <public/xen.h> 7.10 #include <public/physdev.h>
8.1 --- a/xen/arch/x86/smp.c Tue Nov 20 11:53:44 2007 -0700 8.2 +++ b/xen/arch/x86/smp.c Wed Nov 21 09:12:06 2007 -0700 8.3 @@ -18,7 +18,6 @@ 8.4 #include <asm/smp.h> 8.5 #include <asm/mc146818rtc.h> 8.6 #include <asm/flushtlb.h> 8.7 -#include <asm/smpboot.h> 8.8 #include <asm/hardirq.h> 8.9 #include <asm/ipi.h> 8.10 #include <asm/hvm/support.h>
9.1 --- a/xen/arch/x86/traps.c Tue Nov 20 11:53:44 2007 -0700 9.2 +++ b/xen/arch/x86/traps.c Wed Nov 21 09:12:06 2007 -0700 9.3 @@ -2583,7 +2583,10 @@ void set_system_gate(unsigned int n, voi 9.4 9.5 void set_task_gate(unsigned int n, unsigned int sel) 9.6 { 9.7 + idt_table[n].b = 0; 9.8 + wmb(); /* disable gate /then/ rewrite */ 9.9 idt_table[n].a = sel << 16; 9.10 + wmb(); /* rewrite /then/ enable gate */ 9.11 idt_table[n].b = 0x8500; 9.12 } 9.13
10.1 --- a/xen/arch/x86/x86_32/seg_fixup.c Tue Nov 20 11:53:44 2007 -0700 10.2 +++ b/xen/arch/x86/x86_32/seg_fixup.c Wed Nov 21 09:12:06 2007 -0700 10.3 @@ -42,7 +42,7 @@ 10.4 #define O OPCODE_BYTE 10.5 #define M HAS_MODRM 10.6 10.7 -static unsigned char insn_decode[256] = { 10.8 +static const unsigned char insn_decode[256] = { 10.9 /* 0x00 - 0x0F */ 10.10 O|M, O|M, O|M, O|M, X, X, X, X, 10.11 O|M, O|M, O|M, O|M, X, X, X, X, 10.12 @@ -69,7 +69,7 @@ static unsigned char insn_decode[256] = 10.13 X, X, X, X, X, X, X, X, 10.14 /* 0x80 - 0x8F */ 10.15 O|M|1, O|M|4, O|M|1, O|M|1, O|M, O|M, O|M, O|M, 10.16 - O|M, O|M, O|M, O|M, O|M, O|M, O|M, X, 10.17 + O|M, O|M, O|M, O|M, O|M, X|M, O|M, O|M, 10.18 /* 0x90 - 0x9F */ 10.19 X, X, X, X, X, X, X, X, 10.20 X, X, X, X, X, X, X, X, 10.21 @@ -89,17 +89,17 @@ static unsigned char insn_decode[256] = 10.22 X, X, X, X, X, X, X, X, 10.23 X, X, X, X, X, X, X, X, 10.24 /* 0xF0 - 0xFF */ 10.25 - X, X, X, X, X, X, X, X, 10.26 + X, X, X, X, X, X, O|M, O|M, 10.27 X, X, X, X, X, X, O|M, O|M 10.28 }; 10.29 10.30 -static unsigned char twobyte_decode[256] = { 10.31 +static const unsigned char twobyte_decode[256] = { 10.32 /* 0x00 - 0x0F */ 10.33 X, X, X, X, X, X, X, X, 10.34 X, X, X, X, X, X, X, X, 10.35 /* 0x10 - 0x1F */ 10.36 X, X, X, X, X, X, X, X, 10.37 - X, X, X, X, X, X, X, X, 10.38 + O|M, X, X, X, X, X, X, X, 10.39 /* 0x20 - 0x2F */ 10.40 X, X, X, X, X, X, X, X, 10.41 X, X, X, X, X, X, X, X, 10.42 @@ -122,16 +122,16 @@ static unsigned char twobyte_decode[256] 10.43 X, X, X, X, X, X, X, X, 10.44 X, X, X, X, X, X, X, X, 10.45 /* 0x90 - 0x9F */ 10.46 - X, X, X, X, X, X, X, X, 10.47 - X, X, X, X, X, X, X, X, 10.48 + O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M, 10.49 + O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M, 10.50 /* 0xA0 - 0xAF */ 10.51 - X, X, X, X, X, X, X, X, 10.52 - X, X, X, X, X, X, X, X, 10.53 + X, X, X, O|M, O|M|1, O|M, O|M, X, 10.54 + X, X, X, O|M, O|M|1, O|M, X, O|M, 10.55 /* 0xB0 - 0xBF */ 10.56 - X, X, X, X, X, X, X, X, 10.57 - X, X, X, X, X, X, X, X, 10.58 + X, X, X, O|M, X, X, O|M, O|M, 10.59 + X, X, O|M|1, O|M, O|M, O|M, O|M, O|M, 10.60 /* 0xC0 - 0xCF */ 10.61 - X, X, X, X, X, X, X, X, 10.62 + O|M, O|M, X, O|M, X, X, X, O|M, 10.63 X, X, X, X, X, X, X, X, 10.64 /* 0xD0 - 0xDF */ 10.65 X, X, X, X, X, X, X, X, 10.66 @@ -153,24 +153,24 @@ static unsigned char twobyte_decode[256] 10.67 * @base (OUT): Decoded linear base address. 10.68 * @limit (OUT): Decoded segment limit, in bytes. 0 == unlimited (4GB). 10.69 */ 10.70 -int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit) 10.71 +static int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit) 10.72 { 10.73 - struct vcpu *d = current; 10.74 - unsigned long *table, a, b; 10.75 - int ldt = !!(seg & 4); 10.76 - int idx = (seg >> 3) & 8191; 10.77 + struct vcpu *curr = current; 10.78 + uint32_t *table, a, b; 10.79 + int ldt = !!(seg & 4); 10.80 + int idx = (seg >> 3) & 8191; 10.81 10.82 /* Get base and check limit. */ 10.83 if ( ldt ) 10.84 { 10.85 - table = (unsigned long *)LDT_VIRT_START(d); 10.86 - if ( idx >= d->arch.guest_context.ldt_ents ) 10.87 + table = (uint32_t *)LDT_VIRT_START(curr); 10.88 + if ( idx >= curr->arch.guest_context.ldt_ents ) 10.89 goto fail; 10.90 } 10.91 else /* gdt */ 10.92 { 10.93 - table = (unsigned long *)GDT_VIRT_START(d); 10.94 - if ( idx >= d->arch.guest_context.gdt_ents ) 10.95 + table = (uint32_t *)GDT_VIRT_START(curr); 10.96 + if ( idx >= curr->arch.guest_context.gdt_ents ) 10.97 goto fail; 10.98 } 10.99 10.100 @@ -204,7 +204,7 @@ int get_baselimit(u16 seg, unsigned long 10.101 } 10.102 10.103 /* Turn a segment+offset into a linear address. */ 10.104 -int linearise_address(u16 seg, unsigned long off, unsigned long *linear) 10.105 +static int linearise_address(u16 seg, unsigned long off, unsigned long *linear) 10.106 { 10.107 unsigned long base, limit; 10.108 10.109 @@ -219,31 +219,31 @@ int linearise_address(u16 seg, unsigned 10.110 return 1; 10.111 } 10.112 10.113 -int fixup_seg(u16 seg, unsigned long offset) 10.114 +static int fixup_seg(u16 seg, unsigned long offset) 10.115 { 10.116 - struct vcpu *d = current; 10.117 - unsigned long *table, a, b, base, limit; 10.118 - int ldt = !!(seg & 4); 10.119 - int idx = (seg >> 3) & 8191; 10.120 + struct vcpu *curr = current; 10.121 + uint32_t *table, a, b, base, limit; 10.122 + int ldt = !!(seg & 4); 10.123 + int idx = (seg >> 3) & 8191; 10.124 10.125 /* Get base and check limit. */ 10.126 if ( ldt ) 10.127 { 10.128 - table = (unsigned long *)LDT_VIRT_START(d); 10.129 - if ( idx >= d->arch.guest_context.ldt_ents ) 10.130 + table = (uint32_t *)LDT_VIRT_START(curr); 10.131 + if ( idx >= curr->arch.guest_context.ldt_ents ) 10.132 { 10.133 dprintk(XENLOG_DEBUG, "Segment %04x out of LDT range (%ld)\n", 10.134 - seg, d->arch.guest_context.ldt_ents); 10.135 + seg, curr->arch.guest_context.ldt_ents); 10.136 goto fail; 10.137 } 10.138 } 10.139 else /* gdt */ 10.140 { 10.141 - table = (unsigned long *)GDT_VIRT_START(d); 10.142 - if ( idx >= d->arch.guest_context.gdt_ents ) 10.143 + table = (uint32_t *)GDT_VIRT_START(curr); 10.144 + if ( idx >= curr->arch.guest_context.gdt_ents ) 10.145 { 10.146 dprintk(XENLOG_DEBUG, "Segment %04x out of GDT range (%ld)\n", 10.147 - seg, d->arch.guest_context.gdt_ents); 10.148 + seg, curr->arch.guest_context.gdt_ents); 10.149 goto fail; 10.150 } 10.151 } 10.152 @@ -261,7 +261,7 @@ int fixup_seg(u16 seg, unsigned long off 10.153 _SEGMENT_G|_SEGMENT_CODE|_SEGMENT_DPL)) != 10.154 (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|_SEGMENT_G|_SEGMENT_DPL) ) 10.155 { 10.156 - dprintk(XENLOG_DEBUG, "Bad segment %08lx:%08lx\n", a, b); 10.157 + dprintk(XENLOG_DEBUG, "Bad segment %08x:%08x\n", a, b); 10.158 goto fail; 10.159 } 10.160 10.161 @@ -291,8 +291,7 @@ int fixup_seg(u16 seg, unsigned long off 10.162 } 10.163 } 10.164 10.165 - dprintk(XENLOG_DEBUG, "None of the above! " 10.166 - "(%08lx:%08lx, %08lx, %08lx, %08lx)\n", 10.167 + dprintk(XENLOG_DEBUG, "None of the above! (%08x:%08x, %08x, %08x, %08x)\n", 10.168 a, b, base, limit, base+limit); 10.169 10.170 fail: 10.171 @@ -303,9 +302,8 @@ int fixup_seg(u16 seg, unsigned long off 10.172 a &= ~0x0ffff; a |= limit & 0x0ffff; 10.173 b &= ~0xf0000; b |= limit & 0xf0000; 10.174 b ^= _SEGMENT_EC; /* grows-up <-> grows-down */ 10.175 - /* NB. These can't fault. Checked readable above; must also be writable. */ 10.176 - table[2*idx+0] = a; 10.177 - table[2*idx+1] = b; 10.178 + /* NB. This can't fault. Checked readable above; must also be writable. */ 10.179 + atomic_write64((uint64_t *)&table[2*idx], ((uint64_t)b<<32) | a); 10.180 return 1; 10.181 } 10.182 10.183 @@ -315,18 +313,15 @@ int fixup_seg(u16 seg, unsigned long off 10.184 */ 10.185 int gpf_emulate_4gb(struct cpu_user_regs *regs) 10.186 { 10.187 - struct vcpu *d = current; 10.188 - struct trap_info *ti; 10.189 - struct trap_bounce *tb; 10.190 - u8 modrm, mod, reg, rm, decode; 10.191 - void *memreg; 10.192 - unsigned long offset; 10.193 - u8 disp8; 10.194 - u32 disp32 = 0; 10.195 + struct vcpu *curr = current; 10.196 + u8 modrm, mod, rm, decode; 10.197 + const u32 *base, *index = NULL; 10.198 + unsigned long offset; 10.199 + s8 disp8; 10.200 + s32 disp32 = 0; 10.201 u8 *eip; /* ptr to instruction start */ 10.202 u8 *pb, b; /* ptr into instr. / current instr. byte */ 10.203 - int gs_override = 0; 10.204 - int twobyte = 0; 10.205 + int gs_override = 0, scale = 0, twobyte = 0; 10.206 10.207 /* WARNING: We only work for ring-3 segments. */ 10.208 if ( unlikely(vm86_mode(regs)) || unlikely(!ring_3(regs)) ) 10.209 @@ -357,6 +352,9 @@ int gpf_emulate_4gb(struct cpu_user_regs 10.210 goto fail; 10.211 } 10.212 10.213 + if ( twobyte ) 10.214 + break; 10.215 + 10.216 switch ( b ) 10.217 { 10.218 case 0x67: /* Address-size override */ 10.219 @@ -375,6 +373,9 @@ int gpf_emulate_4gb(struct cpu_user_regs 10.220 case 0x65: /* GS override */ 10.221 gs_override = 1; 10.222 break; 10.223 + case 0x0f: /* Not really a prefix byte */ 10.224 + twobyte = 1; 10.225 + break; 10.226 default: /* Not a prefix byte */ 10.227 goto done_prefix; 10.228 } 10.229 @@ -387,32 +388,10 @@ int gpf_emulate_4gb(struct cpu_user_regs 10.230 goto fail; 10.231 } 10.232 10.233 - decode = insn_decode[b]; /* opcode byte */ 10.234 + decode = (!twobyte ? insn_decode : twobyte_decode)[b]; 10.235 pb++; 10.236 - if ( decode == 0 && b == 0x0f ) 10.237 - { 10.238 - twobyte = 1; 10.239 10.240 - if ( get_user(b, pb) ) 10.241 - { 10.242 - dprintk(XENLOG_DEBUG, 10.243 - "Fault while accessing byte %ld of instruction\n", 10.244 - (long)(pb-eip)); 10.245 - goto page_fault; 10.246 - } 10.247 - 10.248 - if ( (pb - eip) >= 15 ) 10.249 - { 10.250 - dprintk(XENLOG_DEBUG, "Too many opcode bytes for a " 10.251 - "legal instruction\n"); 10.252 - goto fail; 10.253 - } 10.254 - 10.255 - decode = twobyte_decode[b]; 10.256 - pb++; 10.257 - } 10.258 - 10.259 - if ( decode == 0 ) 10.260 + if ( !(decode & OPCODE_BYTE) ) 10.261 { 10.262 dprintk(XENLOG_DEBUG, "Unsupported %sopcode %02x\n", 10.263 twobyte ? "two byte " : "", b); 10.264 @@ -422,12 +401,12 @@ int gpf_emulate_4gb(struct cpu_user_regs 10.265 if ( !(decode & HAS_MODRM) ) 10.266 { 10.267 /* Must be a <disp32>, or bail. */ 10.268 - if ( (decode & 7) != 4 ) 10.269 + if ( (decode & INSN_SUFFIX_BYTES) != 4 ) 10.270 goto fail; 10.271 10.272 if ( get_user(offset, (u32 *)pb) ) 10.273 { 10.274 - dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n"); 10.275 + dprintk(XENLOG_DEBUG, "Fault while extracting <moffs32>.\n"); 10.276 goto page_fault; 10.277 } 10.278 pb += 4; 10.279 @@ -448,29 +427,39 @@ int gpf_emulate_4gb(struct cpu_user_regs 10.280 pb++; 10.281 10.282 mod = (modrm >> 6) & 3; 10.283 - reg = (modrm >> 3) & 7; 10.284 rm = (modrm >> 0) & 7; 10.285 10.286 if ( rm == 4 ) 10.287 { 10.288 - dprintk(XENLOG_DEBUG, "FIXME: Add decoding for the SIB byte.\n"); 10.289 - goto fixme; 10.290 + u8 sib; 10.291 + 10.292 + if ( get_user(sib, pb) ) 10.293 + { 10.294 + dprintk(XENLOG_DEBUG, "Fault while extracting sib byte\n"); 10.295 + goto page_fault; 10.296 + } 10.297 + 10.298 + pb++; 10.299 + 10.300 + rm = sib & 7; 10.301 + if ( (sib & 0x38) != 0x20 ) 10.302 + index = decode_register((sib >> 3) & 7, regs, 0); 10.303 + scale = sib >> 6; 10.304 } 10.305 10.306 /* Decode R/M field. */ 10.307 - memreg = decode_register(rm, regs, 0); 10.308 + base = decode_register(rm, regs, 0); 10.309 10.310 /* Decode Mod field. */ 10.311 - switch ( modrm >> 6 ) 10.312 + switch ( mod ) 10.313 { 10.314 case 0: 10.315 - disp32 = 0; 10.316 if ( rm == 5 ) /* disp32 rather than (EBP) */ 10.317 { 10.318 - memreg = NULL; 10.319 + base = NULL; 10.320 if ( get_user(disp32, (u32 *)pb) ) 10.321 { 10.322 - dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n"); 10.323 + dprintk(XENLOG_DEBUG, "Fault while extracting <base32>.\n"); 10.324 goto page_fault; 10.325 } 10.326 pb += 4; 10.327 @@ -484,13 +473,13 @@ int gpf_emulate_4gb(struct cpu_user_regs 10.328 goto page_fault; 10.329 } 10.330 pb++; 10.331 - disp32 = (disp8 & 0x80) ? (disp8 | ~0xff) : disp8;; 10.332 + disp32 = disp8; 10.333 break; 10.334 10.335 case 2: 10.336 if ( get_user(disp32, (u32 *)pb) ) 10.337 { 10.338 - dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n"); 10.339 + dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n"); 10.340 goto page_fault; 10.341 } 10.342 pb += 4; 10.343 @@ -502,8 +491,10 @@ int gpf_emulate_4gb(struct cpu_user_regs 10.344 } 10.345 10.346 offset = disp32; 10.347 - if ( memreg != NULL ) 10.348 - offset += *(u32 *)memreg; 10.349 + if ( base != NULL ) 10.350 + offset += *base; 10.351 + if ( index != NULL ) 10.352 + offset += *index << scale; 10.353 10.354 skip_modrm: 10.355 if ( !fixup_seg((u16)regs->gs, offset) ) 10.356 @@ -513,10 +504,11 @@ int gpf_emulate_4gb(struct cpu_user_regs 10.357 perfc_incr(seg_fixups); 10.358 10.359 /* If requested, give a callback on otherwise unused vector 15. */ 10.360 - if ( VM_ASSIST(d->domain, VMASST_TYPE_4gb_segments_notify) ) 10.361 + if ( VM_ASSIST(curr->domain, VMASST_TYPE_4gb_segments_notify) ) 10.362 { 10.363 - ti = &d->arch.guest_context.trap_ctxt[15]; 10.364 - tb = &d->arch.trap_bounce; 10.365 + struct trap_info *ti = &curr->arch.guest_context.trap_ctxt[15]; 10.366 + struct trap_bounce *tb = &curr->arch.trap_bounce; 10.367 + 10.368 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE; 10.369 tb->error_code = pb - eip; 10.370 tb->cs = ti->cs; 10.371 @@ -527,13 +519,6 @@ int gpf_emulate_4gb(struct cpu_user_regs 10.372 10.373 return EXCRET_fault_fixed; 10.374 10.375 - fixme: 10.376 - dprintk(XENLOG_DEBUG, "Undecodable instruction " 10.377 - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " 10.378 - "caused GPF(0) at %04x:%08x\n", 10.379 - eip[0], eip[1], eip[2], eip[3], 10.380 - eip[4], eip[5], eip[6], eip[7], 10.381 - regs->cs, regs->eip); 10.382 fail: 10.383 return 0; 10.384
11.1 --- a/xen/include/asm-powerpc/smpboot.h Tue Nov 20 11:53:44 2007 -0700 11.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 11.3 @@ -1,21 +0,0 @@ 11.4 -/* 11.5 - * This program is free software; you can redistribute it and/or modify 11.6 - * it under the terms of the GNU General Public License as published by 11.7 - * the Free Software Foundation; either version 2 of the License, or 11.8 - * (at your option) any later version. 11.9 - * 11.10 - * This program is distributed in the hope that it will be useful, 11.11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 11.12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11.13 - * GNU General Public License for more details. 11.14 - * 11.15 - * You should have received a copy of the GNU General Public License 11.16 - * along with this program; if not, write to the Free Software 11.17 - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 11.18 - * 11.19 - * Copyright (C) IBM Corp. 2005 11.20 - * 11.21 - * Authors: Jimi Xenidis <jimix@watson.ibm.com> 11.22 - */ 11.23 - 11.24 -#include "../asm-x86/smpboot.h"
12.1 --- a/xen/include/asm-x86/desc.h Tue Nov 20 11:53:44 2007 -0700 12.2 +++ b/xen/include/asm-x86/desc.h Wed Nov 21 09:12:06 2007 -0700 12.3 @@ -143,6 +143,11 @@ typedef struct { 12.4 12.5 #define _set_gate(gate_addr,type,dpl,addr) \ 12.6 do { \ 12.7 + (gate_addr)->a = 0; \ 12.8 + wmb(); /* disable gate /then/ rewrite */ \ 12.9 + (gate_addr)->b = \ 12.10 + ((unsigned long)(addr) >> 32); \ 12.11 + wmb(); /* rewrite /then/ enable gate */ \ 12.12 (gate_addr)->a = \ 12.13 (((unsigned long)(addr) & 0xFFFF0000UL) << 32) | \ 12.14 ((unsigned long)(dpl) << 45) | \ 12.15 @@ -150,49 +155,53 @@ do { 12.16 ((unsigned long)(addr) & 0xFFFFUL) | \ 12.17 ((unsigned long)__HYPERVISOR_CS64 << 16) | \ 12.18 (1UL << 47); \ 12.19 - (gate_addr)->b = \ 12.20 - ((unsigned long)(addr) >> 32); \ 12.21 } while (0) 12.22 12.23 #define _set_tssldt_desc(desc,addr,limit,type) \ 12.24 do { \ 12.25 + (desc)[0].b = (desc)[1].b = 0; \ 12.26 + wmb(); /* disable entry /then/ rewrite */ \ 12.27 (desc)[0].a = \ 12.28 ((u32)(addr) << 16) | ((u32)(limit) & 0xFFFF); \ 12.29 + (desc)[1].a = (u32)(((unsigned long)(addr)) >> 32); \ 12.30 + wmb(); /* rewrite /then/ enable entry */ \ 12.31 (desc)[0].b = \ 12.32 ((u32)(addr) & 0xFF000000U) | \ 12.33 ((u32)(type) << 8) | 0x8000U | \ 12.34 (((u32)(addr) & 0x00FF0000U) >> 16); \ 12.35 - (desc)[1].a = (u32)(((unsigned long)(addr)) >> 32); \ 12.36 - (desc)[1].b = 0; \ 12.37 } while (0) 12.38 12.39 #elif defined(__i386__) 12.40 12.41 typedef struct desc_struct idt_entry_t; 12.42 12.43 -#define _set_gate(gate_addr,type,dpl,addr) \ 12.44 -do { \ 12.45 - int __d0, __d1; \ 12.46 - __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ 12.47 - "movw %4,%%dx\n\t" \ 12.48 - "movl %%eax,%0\n\t" \ 12.49 - "movl %%edx,%1" \ 12.50 - :"=m" (*((long *) (gate_addr))), \ 12.51 - "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ 12.52 - :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ 12.53 - "3" ((char *) (addr)),"2" (__HYPERVISOR_CS << 16)); \ 12.54 +#define _set_gate(gate_addr,type,dpl,addr) \ 12.55 +do { \ 12.56 + (gate_addr)->b = 0; \ 12.57 + wmb(); /* disable gate /then/ rewrite */ \ 12.58 + (gate_addr)->a = \ 12.59 + ((unsigned long)(addr) & 0xFFFFUL) | \ 12.60 + ((unsigned long)__HYPERVISOR_CS << 16); \ 12.61 + wmb(); /* rewrite /then/ enable gate */ \ 12.62 + (gate_addr)->b = \ 12.63 + ((unsigned long)(addr) & 0xFFFF0000UL) | \ 12.64 + ((unsigned long)(dpl) << 13) | \ 12.65 + ((unsigned long)(type) << 8) | \ 12.66 + (1UL << 15); \ 12.67 } while (0) 12.68 12.69 -#define _set_tssldt_desc(n,addr,limit,type) \ 12.70 -__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ 12.71 - "movw %%ax,2(%2)\n\t" \ 12.72 - "rorl $16,%%eax\n\t" \ 12.73 - "movb %%al,4(%2)\n\t" \ 12.74 - "movb %4,5(%2)\n\t" \ 12.75 - "movb $0,6(%2)\n\t" \ 12.76 - "movb %%ah,7(%2)\n\t" \ 12.77 - "rorl $16,%%eax" \ 12.78 - : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type|0x80)) 12.79 +#define _set_tssldt_desc(desc,addr,limit,type) \ 12.80 +do { \ 12.81 + (desc)->b = 0; \ 12.82 + wmb(); /* disable entry /then/ rewrite */ \ 12.83 + (desc)->a = \ 12.84 + ((u32)(addr) << 16) | ((u32)(limit) & 0xFFFF); \ 12.85 + wmb(); /* rewrite /then/ enable entry */ \ 12.86 + (desc)->b = \ 12.87 + ((u32)(addr) & 0xFF000000U) | \ 12.88 + ((u32)(type) << 8) | 0x8000U | \ 12.89 + (((u32)(addr) & 0x00FF0000U) >> 16); \ 12.90 +} while (0) 12.91 12.92 #endif 12.93
13.1 --- a/xen/include/asm-x86/smpboot.h Tue Nov 20 11:53:44 2007 -0700 13.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 13.3 @@ -1,16 +0,0 @@ 13.4 -#ifndef __ASM_SMPBOOT_H 13.5 -#define __ASM_SMPBOOT_H 13.6 - 13.7 -static inline unsigned long apicid_to_phys_cpu_present(int apicid) 13.8 -{ 13.9 - return 1UL << apicid; 13.10 -} 13.11 - 13.12 -extern volatile int logical_apicid_2_cpu[]; 13.13 -extern volatile int cpu_2_logical_apicid[]; 13.14 -extern volatile int physical_apicid_2_cpu[]; 13.15 -extern volatile int cpu_2_physical_apicid[]; 13.16 - 13.17 -#define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid] 13.18 - 13.19 -#endif
14.1 --- a/xen/include/asm-x86/system.h Tue Nov 20 11:53:44 2007 -0700 14.2 +++ b/xen/include/asm-x86/system.h Wed Nov 21 09:12:06 2007 -0700 14.3 @@ -5,69 +5,78 @@ 14.4 #include <xen/types.h> 14.5 #include <asm/bitops.h> 14.6 14.7 -#define read_segment_register(name) \ 14.8 -({ u16 __sel; \ 14.9 - __asm__ __volatile__ ( "movw %%" STR(name) ",%0" : "=r" (__sel) ); \ 14.10 - __sel; \ 14.11 +#define read_segment_register(name) \ 14.12 +({ u16 __sel; \ 14.13 + asm volatile ( "movw %%" STR(name) ",%0" : "=r" (__sel) ); \ 14.14 + __sel; \ 14.15 }) 14.16 14.17 #define wbinvd() \ 14.18 - __asm__ __volatile__ ("wbinvd": : :"memory"); 14.19 + asm volatile ( "wbinvd" : : : "memory" ) 14.20 14.21 #define clflush(a) \ 14.22 - __asm__ __volatile__ ("clflush (%0)": :"r"(a)); 14.23 + asm volatile ( "clflush (%0)" : : "r"(a) ) 14.24 14.25 -#define nop() __asm__ __volatile__ ("nop") 14.26 +#define nop() \ 14.27 + asm volatile ( "nop" ) 14.28 14.29 -#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr)))) 14.30 +#define xchg(ptr,v) \ 14.31 + ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr)))) 14.32 14.33 struct __xchg_dummy { unsigned long a[100]; }; 14.34 #define __xg(x) ((volatile struct __xchg_dummy *)(x)) 14.35 14.36 +#if defined(__i386__) 14.37 +# include <asm/x86_32/system.h> 14.38 +#elif defined(__x86_64__) 14.39 +# include <asm/x86_64/system.h> 14.40 +#endif 14.41 14.42 /* 14.43 * Note: no "lock" prefix even on SMP: xchg always implies lock anyway 14.44 * Note 2: xchg has side effect, so that attribute volatile is necessary, 14.45 * but generally the primitive is invalid, *ptr is output argument. --ANK 14.46 */ 14.47 -static always_inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) 14.48 +static always_inline unsigned long __xchg( 14.49 + unsigned long x, volatile void *ptr, int size) 14.50 { 14.51 - switch (size) { 14.52 - case 1: 14.53 - __asm__ __volatile__("xchgb %b0,%1" 14.54 - :"=q" (x) 14.55 - :"m" (*__xg((volatile void *)ptr)), "0" (x) 14.56 - :"memory"); 14.57 - break; 14.58 - case 2: 14.59 - __asm__ __volatile__("xchgw %w0,%1" 14.60 - :"=r" (x) 14.61 - :"m" (*__xg((volatile void *)ptr)), "0" (x) 14.62 - :"memory"); 14.63 - break; 14.64 + switch ( size ) 14.65 + { 14.66 + case 1: 14.67 + asm volatile ( "xchgb %b0,%1" 14.68 + : "=q" (x) 14.69 + : "m" (*__xg((volatile void *)ptr)), "0" (x) 14.70 + : "memory" ); 14.71 + break; 14.72 + case 2: 14.73 + asm volatile ( "xchgw %w0,%1" 14.74 + : "=r" (x) 14.75 + : "m" (*__xg((volatile void *)ptr)), "0" (x) 14.76 + : "memory" ); 14.77 + break; 14.78 #if defined(__i386__) 14.79 - case 4: 14.80 - __asm__ __volatile__("xchgl %0,%1" 14.81 - :"=r" (x) 14.82 - :"m" (*__xg((volatile void *)ptr)), "0" (x) 14.83 - :"memory"); 14.84 - break; 14.85 + case 4: 14.86 + asm volatile ( "xchgl %0,%1" 14.87 + : "=r" (x) 14.88 + : "m" (*__xg((volatile void *)ptr)), "0" (x) 14.89 + : "memory" ); 14.90 + break; 14.91 #elif defined(__x86_64__) 14.92 - case 4: 14.93 - __asm__ __volatile__("xchgl %k0,%1" 14.94 - :"=r" (x) 14.95 - :"m" (*__xg((volatile void *)ptr)), "0" (x) 14.96 - :"memory"); 14.97 - break; 14.98 - case 8: 14.99 - __asm__ __volatile__("xchgq %0,%1" 14.100 - :"=r" (x) 14.101 - :"m" (*__xg((volatile void *)ptr)), "0" (x) 14.102 - :"memory"); 14.103 - break; 14.104 + case 4: 14.105 + asm volatile ( "xchgl %k0,%1" 14.106 + : "=r" (x) 14.107 + : "m" (*__xg((volatile void *)ptr)), "0" (x) 14.108 + : "memory" ); 14.109 + break; 14.110 + case 8: 14.111 + asm volatile ( "xchgq %0,%1" 14.112 + : "=r" (x) 14.113 + : "m" (*__xg((volatile void *)ptr)), "0" (x) 14.114 + : "memory" ); 14.115 + break; 14.116 #endif 14.117 - } 14.118 - return x; 14.119 + } 14.120 + return x; 14.121 } 14.122 14.123 /* 14.124 @@ -79,230 +88,88 @@ static always_inline unsigned long __xch 14.125 static always_inline unsigned long __cmpxchg( 14.126 volatile void *ptr, unsigned long old, unsigned long new, int size) 14.127 { 14.128 - unsigned long prev; 14.129 - switch (size) { 14.130 - case 1: 14.131 - __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" 14.132 - : "=a"(prev) 14.133 - : "q"(new), "m"(*__xg((volatile void *)ptr)), "0"(old) 14.134 - : "memory"); 14.135 - return prev; 14.136 - case 2: 14.137 - __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" 14.138 - : "=a"(prev) 14.139 - : "r"(new), "m"(*__xg((volatile void *)ptr)), "0"(old) 14.140 - : "memory"); 14.141 - return prev; 14.142 + unsigned long prev; 14.143 + switch ( size ) 14.144 + { 14.145 + case 1: 14.146 + asm volatile ( LOCK_PREFIX "cmpxchgb %b1,%2" 14.147 + : "=a" (prev) 14.148 + : "q" (new), "m" (*__xg((volatile void *)ptr)), 14.149 + "0" (old) 14.150 + : "memory" ); 14.151 + return prev; 14.152 + case 2: 14.153 + asm volatile ( LOCK_PREFIX "cmpxchgw %w1,%2" 14.154 + : "=a" (prev) 14.155 + : "r" (new), "m" (*__xg((volatile void *)ptr)), 14.156 + "0" (old) 14.157 + : "memory" ); 14.158 + return prev; 14.159 #if defined(__i386__) 14.160 - case 4: 14.161 - __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" 14.162 - : "=a"(prev) 14.163 - : "r"(new), "m"(*__xg((volatile void *)ptr)), "0"(old) 14.164 - : "memory"); 14.165 - return prev; 14.166 + case 4: 14.167 + asm volatile ( LOCK_PREFIX "cmpxchgl %1,%2" 14.168 + : "=a" (prev) 14.169 + : "r" (new), "m" (*__xg((volatile void *)ptr)), 14.170 + "0" (old) 14.171 + : "memory" ); 14.172 + return prev; 14.173 #elif defined(__x86_64__) 14.174 - case 4: 14.175 - __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2" 14.176 - : "=a"(prev) 14.177 - : "r"(new), "m"(*__xg((volatile void *)ptr)), "0"(old) 14.178 - : "memory"); 14.179 - return prev; 14.180 - case 8: 14.181 - __asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2" 14.182 - : "=a"(prev) 14.183 - : "r"(new), "m"(*__xg((volatile void *)ptr)), "0"(old) 14.184 - : "memory"); 14.185 - return prev; 14.186 + case 4: 14.187 + asm volatile ( LOCK_PREFIX "cmpxchgl %k1,%2" 14.188 + : "=a" (prev) 14.189 + : "r" (new), "m" (*__xg((volatile void *)ptr)), 14.190 + "0" (old) 14.191 + : "memory" ); 14.192 + return prev; 14.193 + case 8: 14.194 + asm volatile ( LOCK_PREFIX "cmpxchgq %1,%2" 14.195 + : "=a" (prev) 14.196 + : "r" (new), "m" (*__xg((volatile void *)ptr)), 14.197 + "0" (old) 14.198 + : "memory" ); 14.199 + return prev; 14.200 #endif 14.201 - } 14.202 - return old; 14.203 + } 14.204 + return old; 14.205 } 14.206 14.207 #define __HAVE_ARCH_CMPXCHG 14.208 14.209 -#if BITS_PER_LONG == 64 14.210 - 14.211 -#define cmpxchg(ptr,o,n) \ 14.212 - ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \ 14.213 - (unsigned long)(n),sizeof(*(ptr)))) 14.214 -#else 14.215 - 14.216 -static always_inline unsigned long long __cmpxchg8b( 14.217 - volatile void *ptr, unsigned long long old, unsigned long long new) 14.218 -{ 14.219 - unsigned long long prev; 14.220 - __asm__ __volatile__ ( 14.221 - LOCK_PREFIX "cmpxchg8b %3" 14.222 - : "=A" (prev) 14.223 - : "c" ((u32)(new>>32)), "b" ((u32)new), 14.224 - "m" (*__xg((volatile void *)ptr)), "0" (old) 14.225 - : "memory" ); 14.226 - return prev; 14.227 -} 14.228 - 14.229 -#define cmpxchg(ptr,o,n) \ 14.230 -({ \ 14.231 - __typeof__(*(ptr)) __prev; \ 14.232 - switch ( sizeof(*(ptr)) ) { \ 14.233 - case 8: \ 14.234 - __prev = ((__typeof__(*(ptr)))__cmpxchg8b( \ 14.235 - (ptr), \ 14.236 - (unsigned long long)(o), \ 14.237 - (unsigned long long)(n))); \ 14.238 - break; \ 14.239 - default: \ 14.240 - __prev = ((__typeof__(*(ptr)))__cmpxchg( \ 14.241 - (ptr), \ 14.242 - (unsigned long)(o), \ 14.243 - (unsigned long)(n), \ 14.244 - sizeof(*(ptr)))); \ 14.245 - break; \ 14.246 - } \ 14.247 - __prev; \ 14.248 -}) 14.249 - 14.250 -#endif 14.251 - 14.252 - 14.253 /* 14.254 - * This function causes value _o to be changed to _n at location _p. 14.255 - * If this access causes a fault then we return 1, otherwise we return 0. 14.256 - * If no fault occurs then _o is updated to the value we saw at _p. If this 14.257 - * is the same as the initial value of _o then _n is written to location _p. 14.258 + * Both Intel and AMD agree that, from a programmer's viewpoint: 14.259 + * Loads cannot be reordered relative to other loads. 14.260 + * Stores cannot be reordered relative to other stores. 14.261 + * 14.262 + * Intel64 Architecture Memory Ordering White Paper 14.263 + * <http://developer.intel.com/products/processor/manuals/318147.pdf> 14.264 + * 14.265 + * AMD64 Architecture Programmer's Manual, Volume 2: System Programming 14.266 + * <http://www.amd.com/us-en/assets/content_type/\ 14.267 + * white_papers_and_tech_docs/24593.pdf> 14.268 */ 14.269 -#ifdef __i386__ 14.270 -#define __cmpxchg_user(_p,_o,_n,_isuff,_oppre,_regtype) \ 14.271 - __asm__ __volatile__ ( \ 14.272 - "1: " LOCK_PREFIX "cmpxchg"_isuff" %"_oppre"2,%3\n" \ 14.273 - "2:\n" \ 14.274 - ".section .fixup,\"ax\"\n" \ 14.275 - "3: movl $1,%1\n" \ 14.276 - " jmp 2b\n" \ 14.277 - ".previous\n" \ 14.278 - ".section __ex_table,\"a\"\n" \ 14.279 - " .align 4\n" \ 14.280 - " .long 1b,3b\n" \ 14.281 - ".previous" \ 14.282 - : "=a" (_o), "=r" (_rc) \ 14.283 - : _regtype (_n), "m" (*__xg((volatile void *)_p)), "0" (_o), "1" (0) \ 14.284 - : "memory"); 14.285 -#define cmpxchg_user(_p,_o,_n) \ 14.286 -({ \ 14.287 - int _rc; \ 14.288 - switch ( sizeof(*(_p)) ) { \ 14.289 - case 1: \ 14.290 - __cmpxchg_user(_p,_o,_n,"b","b","q"); \ 14.291 - break; \ 14.292 - case 2: \ 14.293 - __cmpxchg_user(_p,_o,_n,"w","w","r"); \ 14.294 - break; \ 14.295 - case 4: \ 14.296 - __cmpxchg_user(_p,_o,_n,"l","","r"); \ 14.297 - break; \ 14.298 - case 8: \ 14.299 - __asm__ __volatile__ ( \ 14.300 - "1: " LOCK_PREFIX "cmpxchg8b %4\n" \ 14.301 - "2:\n" \ 14.302 - ".section .fixup,\"ax\"\n" \ 14.303 - "3: movl $1,%1\n" \ 14.304 - " jmp 2b\n" \ 14.305 - ".previous\n" \ 14.306 - ".section __ex_table,\"a\"\n" \ 14.307 - " .align 4\n" \ 14.308 - " .long 1b,3b\n" \ 14.309 - ".previous" \ 14.310 - : "=A" (_o), "=r" (_rc) \ 14.311 - : "c" ((u32)((u64)(_n)>>32)), "b" ((u32)(_n)), \ 14.312 - "m" (*__xg((volatile void *)(_p))), "0" (_o), "1" (0) \ 14.313 - : "memory"); \ 14.314 - break; \ 14.315 - } \ 14.316 - _rc; \ 14.317 -}) 14.318 -#else 14.319 -#define __cmpxchg_user(_p,_o,_n,_isuff,_oppre,_regtype) \ 14.320 - __asm__ __volatile__ ( \ 14.321 - "1: " LOCK_PREFIX "cmpxchg"_isuff" %"_oppre"2,%3\n" \ 14.322 - "2:\n" \ 14.323 - ".section .fixup,\"ax\"\n" \ 14.324 - "3: movl $1,%1\n" \ 14.325 - " jmp 2b\n" \ 14.326 - ".previous\n" \ 14.327 - ".section __ex_table,\"a\"\n" \ 14.328 - " .align 8\n" \ 14.329 - " .quad 1b,3b\n" \ 14.330 - ".previous" \ 14.331 - : "=a" (_o), "=r" (_rc) \ 14.332 - : _regtype (_n), "m" (*__xg((volatile void *)_p)), "0" (_o), "1" (0) \ 14.333 - : "memory"); 14.334 -#define cmpxchg_user(_p,_o,_n) \ 14.335 -({ \ 14.336 - int _rc; \ 14.337 - switch ( sizeof(*(_p)) ) { \ 14.338 - case 1: \ 14.339 - __cmpxchg_user(_p,_o,_n,"b","b","q"); \ 14.340 - break; \ 14.341 - case 2: \ 14.342 - __cmpxchg_user(_p,_o,_n,"w","w","r"); \ 14.343 - break; \ 14.344 - case 4: \ 14.345 - __cmpxchg_user(_p,_o,_n,"l","k","r"); \ 14.346 - break; \ 14.347 - case 8: \ 14.348 - __cmpxchg_user(_p,_o,_n,"q","","r"); \ 14.349 - break; \ 14.350 - } \ 14.351 - _rc; \ 14.352 -}) 14.353 -#endif 14.354 - 14.355 -#if defined(__i386__) 14.356 -#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") 14.357 -#define rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") 14.358 -#elif defined(__x86_64__) 14.359 -#define mb() __asm__ __volatile__ ("mfence":::"memory") 14.360 -#define rmb() __asm__ __volatile__ ("lfence":::"memory") 14.361 -#endif 14.362 -#define wmb() __asm__ __volatile__ ("": : :"memory") 14.363 +#define rmb() barrier() 14.364 +#define wmb() barrier() 14.365 14.366 #ifdef CONFIG_SMP 14.367 -#define smp_mb() mb() 14.368 -#define smp_rmb() rmb() 14.369 -#define smp_wmb() wmb() 14.370 +#define smp_mb() mb() 14.371 +#define smp_rmb() rmb() 14.372 +#define smp_wmb() wmb() 14.373 #else 14.374 -#define smp_mb() barrier() 14.375 -#define smp_rmb() barrier() 14.376 -#define smp_wmb() barrier() 14.377 +#define smp_mb() barrier() 14.378 +#define smp_rmb() barrier() 14.379 +#define smp_wmb() barrier() 14.380 #endif 14.381 14.382 #define set_mb(var, value) do { xchg(&var, value); } while (0) 14.383 #define set_wmb(var, value) do { var = value; wmb(); } while (0) 14.384 14.385 -/* interrupt control.. */ 14.386 -#if defined(__i386__) 14.387 -#define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) 14.388 -#define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") 14.389 -#elif defined(__x86_64__) 14.390 -#define __save_flags(x) do { __asm__ __volatile__("# save_flags \n\t pushfq ; popq %q0":"=g" (x): /* no input */ :"memory"); } while (0) 14.391 -#define __restore_flags(x) __asm__ __volatile__("# restore_flags \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory", "cc") 14.392 -#endif 14.393 -#define __cli() __asm__ __volatile__("cli": : :"memory") 14.394 -#define __sti() __asm__ __volatile__("sti": : :"memory") 14.395 +#define local_irq_disable() asm volatile ( "cli" : : : "memory" ) 14.396 +#define local_irq_enable() asm volatile ( "sti" : : : "memory" ) 14.397 + 14.398 /* used in the idle loop; sti takes one instruction cycle to complete */ 14.399 -#define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory") 14.400 +#define safe_halt() asm volatile ( "sti; hlt" : : : "memory" ) 14.401 /* used when interrupts are already enabled or to shutdown the processor */ 14.402 -#define halt() __asm__ __volatile__("hlt": : :"memory") 14.403 - 14.404 -/* For spinlocks etc */ 14.405 -#if defined(__i386__) 14.406 -#define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") 14.407 -#define local_irq_restore(x) __restore_flags(x) 14.408 -#elif defined(__x86_64__) 14.409 -#define local_irq_save(x) do { __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0) 14.410 -#define local_irq_restore(x) __asm__ __volatile__("# local_irq_restore \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory") 14.411 -#endif 14.412 -#define local_irq_disable() __cli() 14.413 -#define local_irq_enable() __sti() 14.414 +#define halt() asm volatile ( "hlt" : : : "memory" ) 14.415 14.416 static inline int local_irq_is_enabled(void) 14.417 { 14.418 @@ -311,8 +178,8 @@ static inline int local_irq_is_enabled(v 14.419 return !!(flags & (1<<9)); /* EFLAGS_IF */ 14.420 } 14.421 14.422 -#define BROKEN_ACPI_Sx 0x0001 14.423 -#define BROKEN_INIT_AFTER_S1 0x0002 14.424 +#define BROKEN_ACPI_Sx 0x0001 14.425 +#define BROKEN_INIT_AFTER_S1 0x0002 14.426 14.427 void trap_init(void); 14.428 void percpu_traps_init(void);
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/xen/include/asm-x86/x86_32/system.h Wed Nov 21 09:12:06 2007 -0700 15.3 @@ -0,0 +1,114 @@ 15.4 +#ifndef __X86_32_SYSTEM_H__ 15.5 +#define __X86_32_SYSTEM_H__ 15.6 + 15.7 +static always_inline unsigned long long __cmpxchg8b( 15.8 + volatile void *ptr, unsigned long long old, unsigned long long new) 15.9 +{ 15.10 + unsigned long long prev; 15.11 + asm volatile ( 15.12 + LOCK_PREFIX "cmpxchg8b %3" 15.13 + : "=A" (prev) 15.14 + : "c" ((u32)(new>>32)), "b" ((u32)new), 15.15 + "m" (*__xg((volatile void *)ptr)), "0" (old) 15.16 + : "memory" ); 15.17 + return prev; 15.18 +} 15.19 + 15.20 +#define cmpxchg(ptr,o,n) \ 15.21 +({ \ 15.22 + __typeof__(*(ptr)) __prev; \ 15.23 + switch ( sizeof(*(ptr)) ) { \ 15.24 + case 8: \ 15.25 + __prev = ((__typeof__(*(ptr)))__cmpxchg8b( \ 15.26 + (ptr), \ 15.27 + (unsigned long long)(o), \ 15.28 + (unsigned long long)(n))); \ 15.29 + break; \ 15.30 + default: \ 15.31 + __prev = ((__typeof__(*(ptr)))__cmpxchg( \ 15.32 + (ptr), \ 15.33 + (unsigned long)(o), \ 15.34 + (unsigned long)(n), \ 15.35 + sizeof(*(ptr)))); \ 15.36 + break; \ 15.37 + } \ 15.38 + __prev; \ 15.39 +}) 15.40 + 15.41 +/* 15.42 + * This function causes value _o to be changed to _n at location _p. 15.43 + * If this access causes a fault then we return 1, otherwise we return 0. 15.44 + * If no fault occurs then _o is updated to the value we saw at _p. If this 15.45 + * is the same as the initial value of _o then _n is written to location _p. 15.46 + */ 15.47 +#define __cmpxchg_user(_p,_o,_n,_isuff,_oppre,_regtype) \ 15.48 + asm volatile ( \ 15.49 + "1: " LOCK_PREFIX "cmpxchg"_isuff" %"_oppre"2,%3\n" \ 15.50 + "2:\n" \ 15.51 + ".section .fixup,\"ax\"\n" \ 15.52 + "3: movl $1,%1\n" \ 15.53 + " jmp 2b\n" \ 15.54 + ".previous\n" \ 15.55 + ".section __ex_table,\"a\"\n" \ 15.56 + " .align 4\n" \ 15.57 + " .long 1b,3b\n" \ 15.58 + ".previous" \ 15.59 + : "=a" (_o), "=r" (_rc) \ 15.60 + : _regtype (_n), "m" (*__xg((volatile void *)_p)), "0" (_o), "1" (0) \ 15.61 + : "memory"); 15.62 + 15.63 +#define cmpxchg_user(_p,_o,_n) \ 15.64 +({ \ 15.65 + int _rc; \ 15.66 + switch ( sizeof(*(_p)) ) { \ 15.67 + case 1: \ 15.68 + __cmpxchg_user(_p,_o,_n,"b","b","q"); \ 15.69 + break; \ 15.70 + case 2: \ 15.71 + __cmpxchg_user(_p,_o,_n,"w","w","r"); \ 15.72 + break; \ 15.73 + case 4: \ 15.74 + __cmpxchg_user(_p,_o,_n,"l","","r"); \ 15.75 + break; \ 15.76 + case 8: \ 15.77 + asm volatile ( \ 15.78 + "1: " LOCK_PREFIX "cmpxchg8b %4\n" \ 15.79 + "2:\n" \ 15.80 + ".section .fixup,\"ax\"\n" \ 15.81 + "3: movl $1,%1\n" \ 15.82 + " jmp 2b\n" \ 15.83 + ".previous\n" \ 15.84 + ".section __ex_table,\"a\"\n" \ 15.85 + " .align 4\n" \ 15.86 + " .long 1b,3b\n" \ 15.87 + ".previous" \ 15.88 + : "=A" (_o), "=r" (_rc) \ 15.89 + : "c" ((u32)((u64)(_n)>>32)), "b" ((u32)(_n)), \ 15.90 + "m" (*__xg((volatile void *)(_p))), "0" (_o), "1" (0) \ 15.91 + : "memory"); \ 15.92 + break; \ 15.93 + } \ 15.94 + _rc; \ 15.95 +}) 15.96 + 15.97 +static inline void atomic_write64(uint64_t *p, uint64_t v) 15.98 +{ 15.99 + uint64_t w = *p, x; 15.100 + while ( (x = __cmpxchg8b(p, w, v)) != w ) 15.101 + w = x; 15.102 +} 15.103 + 15.104 +#define mb() \ 15.105 + asm volatile ( "lock; addl $0,0(%%esp)" : : : "memory" ) 15.106 + 15.107 +#define __save_flags(x) \ 15.108 + asm volatile ( "pushfl ; popl %0" : "=g" (x) : ) 15.109 +#define __restore_flags(x) \ 15.110 + asm volatile ( "pushl %0 ; popfl" : : "g" (x) : "memory", "cc" ) 15.111 + 15.112 +#define local_irq_save(x) \ 15.113 + asm volatile ( "pushfl ; popl %0 ; cli" : "=g" (x) : : "memory" ) 15.114 +#define local_irq_restore(x) \ 15.115 + __restore_flags(x) 15.116 + 15.117 +#endif /* __X86_32_SYSTEM_H__ */
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/xen/include/asm-x86/x86_64/system.h Wed Nov 21 09:12:06 2007 -0700 16.3 @@ -0,0 +1,68 @@ 16.4 +#ifndef __X86_64_SYSTEM_H__ 16.5 +#define __X86_64_SYSTEM_H__ 16.6 + 16.7 +#define cmpxchg(ptr,o,n) \ 16.8 + ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \ 16.9 + (unsigned long)(n),sizeof(*(ptr)))) 16.10 + 16.11 +/* 16.12 + * This function causes value _o to be changed to _n at location _p. 16.13 + * If this access causes a fault then we return 1, otherwise we return 0. 16.14 + * If no fault occurs then _o is updated to the value we saw at _p. If this 16.15 + * is the same as the initial value of _o then _n is written to location _p. 16.16 + */ 16.17 +#define __cmpxchg_user(_p,_o,_n,_isuff,_oppre,_regtype) \ 16.18 + asm volatile ( \ 16.19 + "1: " LOCK_PREFIX "cmpxchg"_isuff" %"_oppre"2,%3\n" \ 16.20 + "2:\n" \ 16.21 + ".section .fixup,\"ax\"\n" \ 16.22 + "3: movl $1,%1\n" \ 16.23 + " jmp 2b\n" \ 16.24 + ".previous\n" \ 16.25 + ".section __ex_table,\"a\"\n" \ 16.26 + " .align 8\n" \ 16.27 + " .quad 1b,3b\n" \ 16.28 + ".previous" \ 16.29 + : "=a" (_o), "=r" (_rc) \ 16.30 + : _regtype (_n), "m" (*__xg((volatile void *)_p)), "0" (_o), "1" (0) \ 16.31 + : "memory"); 16.32 + 16.33 +#define cmpxchg_user(_p,_o,_n) \ 16.34 +({ \ 16.35 + int _rc; \ 16.36 + switch ( sizeof(*(_p)) ) { \ 16.37 + case 1: \ 16.38 + __cmpxchg_user(_p,_o,_n,"b","b","q"); \ 16.39 + break; \ 16.40 + case 2: \ 16.41 + __cmpxchg_user(_p,_o,_n,"w","w","r"); \ 16.42 + break; \ 16.43 + case 4: \ 16.44 + __cmpxchg_user(_p,_o,_n,"l","k","r"); \ 16.45 + break; \ 16.46 + case 8: \ 16.47 + __cmpxchg_user(_p,_o,_n,"q","","r"); \ 16.48 + break; \ 16.49 + } \ 16.50 + _rc; \ 16.51 +}) 16.52 + 16.53 +static inline void atomic_write64(uint64_t *p, uint64_t v) 16.54 +{ 16.55 + *p = v; 16.56 +} 16.57 + 16.58 +#define mb() \ 16.59 + asm volatile ( "mfence" : : : "memory" ) 16.60 + 16.61 +#define __save_flags(x) \ 16.62 + asm volatile ( "pushfq ; popq %q0" : "=g" (x) : :"memory" ) 16.63 +#define __restore_flags(x) \ 16.64 + asm volatile ( "pushq %0 ; popfq" : : "g" (x) : "memory", "cc" ) 16.65 + 16.66 +#define local_irq_save(x) \ 16.67 + asm volatile ( "pushfq ; popq %0 ; cli" : "=g" (x) : : "memory" ) 16.68 +#define local_irq_restore(x) \ 16.69 + __restore_flags(x) 16.70 + 16.71 +#endif /* __X86_64_SYSTEM_H__ */