Add 64-bit Block Move support (Direct & Table Indirect) (Ryan Harper)
This patch adds support for 64-bit Block Move instructions. There are multiple modes for 64-bit Block moves, direct, indirect, and table indirect. This patch implements Direct and Table indirect moves which are needed by 64-bit windows and SYM_CONF_DMA_ADDRESSING_MODE=2 for the Linux sym53c8xx_2 driver respectively. Two helper functions are included to check which mode the guest is using. For 64-bit direct moves, we fetch a 3rd DWORD and store the value in the DBMS register. For Table Indirect moves, we look into the table for which register contains the upper 32-bits of the 64-bit address. This selector value indicates which register to pull the value from and into dnad64 register. Finally, lsi_do_dma is updated to use the approriate register to build a 64-bit DMA address if required. With this patch, Windows XP x64, 2003 SP2 x64, can now install to scsi devices. Linux SYM_CONF_DMA_ADDRESSING_MODE=2 need a quirk fixup in Patch 4 to function properly. Signed-off-by: Ryan Harper <ryanh@us.ibm.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5969 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
ab57d96704
commit
dd8edf0122
|
@ -338,6 +338,20 @@ static int lsi_dma_40bit(LSIState *s)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lsi_dma_ti64bit(LSIState *s)
|
||||||
|
{
|
||||||
|
if ((s->ccntl1 & LSI_CCNTL1_EN64TIBMV) == LSI_CCNTL1_EN64TIBMV)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsi_dma_64bit(LSIState *s)
|
||||||
|
{
|
||||||
|
if ((s->ccntl1 & LSI_CCNTL1_EN64DBMV) == LSI_CCNTL1_EN64DBMV)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t lsi_reg_readb(LSIState *s, int offset);
|
static uint8_t lsi_reg_readb(LSIState *s, int offset);
|
||||||
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
|
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
|
||||||
static void lsi_execute_script(LSIState *s);
|
static void lsi_execute_script(LSIState *s);
|
||||||
|
@ -477,8 +491,11 @@ static void lsi_do_dma(LSIState *s, int out)
|
||||||
count = s->current_dma_len;
|
count = s->current_dma_len;
|
||||||
|
|
||||||
addr = s->dnad;
|
addr = s->dnad;
|
||||||
if (lsi_dma_40bit(s))
|
/* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
|
||||||
|
if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
|
||||||
addr |= ((uint64_t)s->dnad64 << 32);
|
addr |= ((uint64_t)s->dnad64 << 32);
|
||||||
|
else if (s->dbms)
|
||||||
|
addr |= ((uint64_t)s->dbms << 32);
|
||||||
else if (s->sbms)
|
else if (s->sbms)
|
||||||
addr |= ((uint64_t)s->sbms << 32);
|
addr |= ((uint64_t)s->sbms << 32);
|
||||||
|
|
||||||
|
@ -888,6 +905,8 @@ again:
|
||||||
}
|
}
|
||||||
s->dbc = insn & 0xffffff;
|
s->dbc = insn & 0xffffff;
|
||||||
s->rbc = s->dbc;
|
s->rbc = s->dbc;
|
||||||
|
/* ??? Set ESA. */
|
||||||
|
s->ia = s->dsp - 8;
|
||||||
if (insn & (1 << 29)) {
|
if (insn & (1 << 29)) {
|
||||||
/* Indirect addressing. */
|
/* Indirect addressing. */
|
||||||
addr = read_dword(s, addr);
|
addr = read_dword(s, addr);
|
||||||
|
@ -895,6 +914,8 @@ again:
|
||||||
uint32_t buf[2];
|
uint32_t buf[2];
|
||||||
int32_t offset;
|
int32_t offset;
|
||||||
/* Table indirect addressing. */
|
/* Table indirect addressing. */
|
||||||
|
|
||||||
|
/* 32-bit Table indirect */
|
||||||
offset = sxt24(addr);
|
offset = sxt24(addr);
|
||||||
cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);
|
cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);
|
||||||
/* byte count is stored in bits 0:23 only */
|
/* byte count is stored in bits 0:23 only */
|
||||||
|
@ -906,6 +927,44 @@ again:
|
||||||
* table, bits [31:24] */
|
* table, bits [31:24] */
|
||||||
if (lsi_dma_40bit(s))
|
if (lsi_dma_40bit(s))
|
||||||
addr_high = cpu_to_le32(buf[0]) >> 24;
|
addr_high = cpu_to_le32(buf[0]) >> 24;
|
||||||
|
else if (lsi_dma_ti64bit(s)) {
|
||||||
|
int selector = (cpu_to_le32(buf[0]) >> 24) & 0x1f;
|
||||||
|
switch (selector) {
|
||||||
|
case 0 ... 0x0f:
|
||||||
|
/* offset index into scratch registers since
|
||||||
|
* TI64 mode can use registers C to R */
|
||||||
|
addr_high = s->scratch[2 + selector];
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
addr_high = s->mmrs;
|
||||||
|
break;
|
||||||
|
case 0x11:
|
||||||
|
addr_high = s->mmws;
|
||||||
|
break;
|
||||||
|
case 0x12:
|
||||||
|
addr_high = s->sfs;
|
||||||
|
break;
|
||||||
|
case 0x13:
|
||||||
|
addr_high = s->drs;
|
||||||
|
break;
|
||||||
|
case 0x14:
|
||||||
|
addr_high = s->sbms;
|
||||||
|
break;
|
||||||
|
case 0x15:
|
||||||
|
addr_high = s->dbms;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BADF("Illegal selector specified (0x%x > 0x15)"
|
||||||
|
" for 64-bit DMA block move", selector);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (lsi_dma_64bit(s)) {
|
||||||
|
/* fetch a 3rd dword if 64-bit direct move is enabled and
|
||||||
|
only if we're not doing table indirect or indirect addressing */
|
||||||
|
s->dbms = read_dword(s, s->dsp);
|
||||||
|
s->dsp += 4;
|
||||||
|
s->ia = s->dsp - 12;
|
||||||
}
|
}
|
||||||
if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
|
if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
|
||||||
DPRINTF("Wrong phase got %d expected %d\n",
|
DPRINTF("Wrong phase got %d expected %d\n",
|
||||||
|
@ -915,8 +974,6 @@ again:
|
||||||
}
|
}
|
||||||
s->dnad = addr;
|
s->dnad = addr;
|
||||||
s->dnad64 = addr_high;
|
s->dnad64 = addr_high;
|
||||||
/* ??? Set ESA. */
|
|
||||||
s->ia = s->dsp - 8;
|
|
||||||
switch (s->sstat1 & 0x7) {
|
switch (s->sstat1 & 0x7) {
|
||||||
case PHASE_DO:
|
case PHASE_DO:
|
||||||
s->waiting = 2;
|
s->waiting = 2;
|
||||||
|
|
Reference in New Issue