qemu-sparc queue

-----BEGIN PGP SIGNATURE-----
 
 iQFSBAABCgA8FiEEzGIauY6CIA2RXMnEW8LFb64PMh8FAmYOtvEeHG1hcmsuY2F2
 ZS1heWxhbmRAaWxhbmRlLmNvLnVrAAoJEFvCxW+uDzIf+5oIAJtRPiTP5aUmN4nU
 s72NBtgARBJ+5hHl0fqFFlCrG9elO28F1vhT9DwwBOLwihZCnfIXf+SCoE+pvqDw
 c+AMN/RnDu+1F4LF93W0ZIr305yGDfVlU+S3vKGtB9G4rcLeBDmNlhui2d0Bqx9R
 jwX1y57vcPclObE0KL6AVOfSDPYiVEVQSiTr3j4oW8TqAs2bduEZMRh6esb3XMIA
 hmj8mhZAszfh1YvX8ufbxtPQsnNuFMM+Fxgxp0pux8QaI0addDHwVNObRUYlTUZ1
 o4xCw7TRXXotaHde/OqZApFECs+md3R7rC2wj7s3ae0ynohHHDFfaB5t1f4pm+kA
 /6UN/Jc=
 =XwaI
 -----END PGP SIGNATURE-----

Merge tag 'qemu-sparc-20240404' of https://github.com/mcayland/qemu into staging

qemu-sparc queue

# -----BEGIN PGP SIGNATURE-----
#
# iQFSBAABCgA8FiEEzGIauY6CIA2RXMnEW8LFb64PMh8FAmYOtvEeHG1hcmsuY2F2
# ZS1heWxhbmRAaWxhbmRlLmNvLnVrAAoJEFvCxW+uDzIf+5oIAJtRPiTP5aUmN4nU
# s72NBtgARBJ+5hHl0fqFFlCrG9elO28F1vhT9DwwBOLwihZCnfIXf+SCoE+pvqDw
# c+AMN/RnDu+1F4LF93W0ZIr305yGDfVlU+S3vKGtB9G4rcLeBDmNlhui2d0Bqx9R
# jwX1y57vcPclObE0KL6AVOfSDPYiVEVQSiTr3j4oW8TqAs2bduEZMRh6esb3XMIA
# hmj8mhZAszfh1YvX8ufbxtPQsnNuFMM+Fxgxp0pux8QaI0addDHwVNObRUYlTUZ1
# o4xCw7TRXXotaHde/OqZApFECs+md3R7rC2wj7s3ae0ynohHHDFfaB5t1f4pm+kA
# /6UN/Jc=
# =XwaI
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 04 Apr 2024 15:19:29 BST
# gpg:                using RSA key CC621AB98E82200D915CC9C45BC2C56FAE0F321F
# gpg:                issuer "mark.cave-ayland@ilande.co.uk"
# gpg: Good signature from "Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>" [full]
# Primary key fingerprint: CC62 1AB9 8E82 200D 915C  C9C4 5BC2 C56F AE0F 321F

* tag 'qemu-sparc-20240404' of https://github.com/mcayland/qemu:
  esp.c: remove explicit setting of DRQ within ESP state machine
  esp.c: ensure esp_pdma_write() always calls esp_fifo_push()
  esp.c: update esp_fifo_{push, pop}() to call esp_update_drq()
  esp.c: introduce esp_update_drq() and update esp_fifo_{push, pop}_buf() to use it
  esp.c: move esp_set_phase() and esp_get_phase() towards the beginning of the file
  esp.c: prevent cmdfifo overflow in esp_cdb_ready()
  esp.c: rework esp_cdb_length() into esp_cdb_ready()
  esp.c: don't assert() if FIFO empty when executing non-DMA SELATNS
  esp.c: introduce esp_fifo_push_buf() function for pushing to the FIFO
  esp.c: change esp_fifo_pop_buf() to take ESPState
  esp.c: use esp_fifo_push() instead of fifo8_push()
  esp.c: change esp_fifo_pop() to take ESPState
  esp.c: change esp_fifo_push() to take ESPState
  esp.c: replace cmdfifo use of esp_fifo_pop() in do_message_phase()
  esp.c: replace esp_fifo_pop_buf() with esp_fifo8_pop_buf() in do_message_phase()
  esp.c: replace esp_fifo_pop_buf() with esp_fifo8_pop_buf() in do_command_phase()
  esp.c: move esp_fifo_pop_buf() internals to new esp_fifo8_pop_buf() function

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-04-04 15:28:06 +01:00
commit ce64e6224a

View File

@ -79,6 +79,24 @@ static void esp_lower_drq(ESPState *s)
}
}
static const char *esp_phase_names[8] = {
"DATA OUT", "DATA IN", "COMMAND", "STATUS",
"(reserved)", "(reserved)", "MESSAGE OUT", "MESSAGE IN"
};
static void esp_set_phase(ESPState *s, uint8_t phase)
{
s->rregs[ESP_RSTAT] &= ~7;
s->rregs[ESP_RSTAT] |= phase;
trace_esp_set_phase(esp_phase_names[phase]);
}
static uint8_t esp_get_phase(ESPState *s)
{
return s->rregs[ESP_RSTAT] & 7;
}
void esp_dma_enable(ESPState *s, int irq, int level)
{
if (level) {
@ -106,26 +124,80 @@ void esp_request_cancelled(SCSIRequest *req)
}
}
static void esp_fifo_push(Fifo8 *fifo, uint8_t val)
static void esp_update_drq(ESPState *s)
{
if (fifo8_num_used(fifo) == fifo->capacity) {
trace_esp_error_fifo_overrun();
bool to_device;
switch (esp_get_phase(s)) {
case STAT_MO:
case STAT_CD:
case STAT_DO:
to_device = true;
break;
case STAT_DI:
case STAT_ST:
case STAT_MI:
to_device = false;
break;
default:
return;
}
fifo8_push(fifo, val);
if (s->dma) {
/* DMA request so update DRQ according to transfer direction */
if (to_device) {
if (fifo8_num_free(&s->fifo) < 2) {
esp_lower_drq(s);
} else {
esp_raise_drq(s);
}
} else {
if (fifo8_num_used(&s->fifo) < 2) {
esp_lower_drq(s);
} else {
esp_raise_drq(s);
}
}
} else {
/* Not a DMA request */
esp_lower_drq(s);
}
}
static uint8_t esp_fifo_pop(Fifo8 *fifo)
static void esp_fifo_push(ESPState *s, uint8_t val)
{
if (fifo8_is_empty(fifo)) {
return 0;
if (fifo8_num_used(&s->fifo) == s->fifo.capacity) {
trace_esp_error_fifo_overrun();
} else {
fifo8_push(&s->fifo, val);
}
return fifo8_pop(fifo);
esp_update_drq(s);
}
static uint32_t esp_fifo_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen)
static void esp_fifo_push_buf(ESPState *s, uint8_t *buf, int len)
{
fifo8_push_all(&s->fifo, buf, len);
esp_update_drq(s);
}
static uint8_t esp_fifo_pop(ESPState *s)
{
uint8_t val;
if (fifo8_is_empty(&s->fifo)) {
val = 0;
} else {
val = fifo8_pop(&s->fifo);
}
esp_update_drq(s);
return val;
}
static uint32_t esp_fifo8_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen)
{
const uint8_t *buf;
uint32_t n, n2;
@ -155,6 +227,14 @@ static uint32_t esp_fifo_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen)
return n;
}
static uint32_t esp_fifo_pop_buf(ESPState *s, uint8_t *dest, int maxlen)
{
uint32_t len = esp_fifo8_pop_buf(&s->fifo, dest, maxlen);
esp_update_drq(s);
return len;
}
static uint32_t esp_get_tc(ESPState *s)
{
uint32_t dmalen;
@ -190,29 +270,11 @@ static uint32_t esp_get_stc(ESPState *s)
return dmalen;
}
static const char *esp_phase_names[8] = {
"DATA OUT", "DATA IN", "COMMAND", "STATUS",
"(reserved)", "(reserved)", "MESSAGE OUT", "MESSAGE IN"
};
static void esp_set_phase(ESPState *s, uint8_t phase)
{
s->rregs[ESP_RSTAT] &= ~7;
s->rregs[ESP_RSTAT] |= phase;
trace_esp_set_phase(esp_phase_names[phase]);
}
static uint8_t esp_get_phase(ESPState *s)
{
return s->rregs[ESP_RSTAT] & 7;
}
static uint8_t esp_pdma_read(ESPState *s)
{
uint8_t val;
val = esp_fifo_pop(&s->fifo);
val = esp_fifo_pop(s);
return val;
}
@ -220,15 +282,13 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
{
uint32_t dmalen = esp_get_tc(s);
if (dmalen == 0) {
return;
}
esp_fifo_push(&s->fifo, val);
esp_fifo_push(s, val);
if (dmalen && s->drq_state) {
dmalen--;
esp_set_tc(s, dmalen);
}
}
static int esp_select(ESPState *s)
{
@ -275,7 +335,7 @@ static void do_command_phase(ESPState *s)
if (!cmdlen || !s->current_dev) {
return;
}
esp_fifo_pop_buf(&s->cmdfifo, buf, cmdlen);
esp_fifo8_pop_buf(&s->cmdfifo, buf, cmdlen);
current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, s->lun);
if (!current_lun) {
@ -310,7 +370,8 @@ static void do_command_phase(ESPState *s)
static void do_message_phase(ESPState *s)
{
if (s->cmdfifo_cdb_offset) {
uint8_t message = esp_fifo_pop(&s->cmdfifo);
uint8_t message = fifo8_is_empty(&s->cmdfifo) ? 0 :
fifo8_pop(&s->cmdfifo);
trace_esp_do_identify(message);
s->lun = message & 7;
@ -320,7 +381,7 @@ static void do_message_phase(ESPState *s)
/* Ignore extended messages for now */
if (s->cmdfifo_cdb_offset) {
int len = MIN(s->cmdfifo_cdb_offset, fifo8_num_used(&s->cmdfifo));
esp_fifo_pop_buf(&s->cmdfifo, NULL, len);
esp_fifo8_pop_buf(&s->cmdfifo, NULL, len);
s->cmdfifo_cdb_offset = 0;
}
}
@ -414,20 +475,30 @@ static void write_response(ESPState *s)
}
}
static int esp_cdb_length(ESPState *s)
static bool esp_cdb_ready(ESPState *s)
{
int len = fifo8_num_used(&s->cmdfifo) - s->cmdfifo_cdb_offset;
const uint8_t *pbuf;
int cmdlen, len;
uint32_t n;
int cdblen;
cmdlen = fifo8_num_used(&s->cmdfifo);
if (cmdlen < s->cmdfifo_cdb_offset) {
return 0;
if (len <= 0) {
return false;
}
pbuf = fifo8_peek_buf(&s->cmdfifo, cmdlen, NULL);
len = scsi_cdb_length((uint8_t *)&pbuf[s->cmdfifo_cdb_offset]);
pbuf = fifo8_peek_buf(&s->cmdfifo, len, &n);
if (n < len) {
/*
* In normal use the cmdfifo should never wrap, but include this check
* to prevent a malicious guest from reading past the end of the
* cmdfifo data buffer below
*/
return false;
}
return len;
cdblen = scsi_cdb_length((uint8_t *)&pbuf[s->cmdfifo_cdb_offset]);
return cdblen < 0 ? false : (len >= cdblen);
}
static void esp_dma_ti_check(ESPState *s)
@ -435,7 +506,6 @@ static void esp_dma_ti_check(ESPState *s)
if (esp_get_tc(s) == 0 && fifo8_num_used(&s->fifo) < 2) {
s->rregs[ESP_RINTR] |= INTR_BS;
esp_raise_irq(s);
esp_lower_drq(s);
}
}
@ -453,9 +523,8 @@ static void esp_do_dma(ESPState *s)
s->dma_memory_read(s->dma_opaque, buf, len);
esp_set_tc(s, esp_get_tc(s) - len);
} else {
len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
esp_raise_drq(s);
}
fifo8_push_all(&s->cmdfifo, buf, len);
@ -509,10 +578,9 @@ static void esp_do_dma(ESPState *s)
fifo8_push_all(&s->cmdfifo, buf, len);
esp_set_tc(s, esp_get_tc(s) - len);
} else {
len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
fifo8_push_all(&s->cmdfifo, buf, len);
esp_raise_drq(s);
}
trace_esp_handle_ti_cmd(cmdlen);
s->ti_size = 0;
@ -543,8 +611,7 @@ static void esp_do_dma(ESPState *s)
/* Copy FIFO data to device */
len = MIN(s->async_len, ESP_FIFO_SZ);
len = MIN(len, fifo8_num_used(&s->fifo));
len = esp_fifo_pop_buf(&s->fifo, s->async_buf, len);
esp_raise_drq(s);
len = esp_fifo_pop_buf(s, s->async_buf, len);
}
s->async_buf += len;
@ -595,8 +662,7 @@ static void esp_do_dma(ESPState *s)
} else {
/* Copy device data to FIFO */
len = MIN(len, fifo8_num_free(&s->fifo));
fifo8_push_all(&s->fifo, s->async_buf, len);
esp_raise_drq(s);
esp_fifo_push_buf(s, s->async_buf, len);
}
s->async_buf += len;
@ -644,7 +710,7 @@ static void esp_do_dma(ESPState *s)
if (s->dma_memory_write) {
s->dma_memory_write(s->dma_opaque, buf, len);
} else {
fifo8_push_all(&s->fifo, buf, len);
esp_fifo_push_buf(s, buf, len);
}
esp_set_tc(s, esp_get_tc(s) - len);
@ -662,7 +728,6 @@ static void esp_do_dma(ESPState *s)
if (fifo8_num_used(&s->fifo) < 2) {
s->rregs[ESP_RINTR] |= INTR_BS;
esp_raise_irq(s);
esp_lower_drq(s);
}
break;
}
@ -679,7 +744,7 @@ static void esp_do_dma(ESPState *s)
if (s->dma_memory_write) {
s->dma_memory_write(s->dma_opaque, buf, len);
} else {
fifo8_push_all(&s->fifo, buf, len);
esp_fifo_push_buf(s, buf, len);
}
esp_set_tc(s, esp_get_tc(s) - len);
@ -707,7 +772,7 @@ static void esp_nodma_ti_dataout(ESPState *s)
}
len = MIN(s->async_len, ESP_FIFO_SZ);
len = MIN(len, fifo8_num_used(&s->fifo));
esp_fifo_pop_buf(&s->fifo, s->async_buf, len);
esp_fifo_pop_buf(s, s->async_buf, len);
s->async_buf += len;
s->async_len -= len;
s->ti_size += len;
@ -732,7 +797,7 @@ static void esp_do_nodma(ESPState *s)
switch (s->rregs[ESP_CMD]) {
case CMD_SELATN:
/* Copy FIFO into cmdfifo */
len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
fifo8_push_all(&s->cmdfifo, buf, len);
@ -751,7 +816,8 @@ static void esp_do_nodma(ESPState *s)
case CMD_SELATNS:
/* Copy one byte from FIFO into cmdfifo */
len = esp_fifo_pop_buf(&s->fifo, buf, 1);
len = esp_fifo_pop_buf(s, buf,
MIN(fifo8_num_used(&s->fifo), 1));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
fifo8_push_all(&s->cmdfifo, buf, len);
@ -768,7 +834,7 @@ static void esp_do_nodma(ESPState *s)
case CMD_TI:
/* Copy FIFO into cmdfifo */
len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
fifo8_push_all(&s->cmdfifo, buf, len);
@ -786,7 +852,7 @@ static void esp_do_nodma(ESPState *s)
switch (s->rregs[ESP_CMD]) {
case CMD_TI:
/* Copy FIFO into cmdfifo */
len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
fifo8_push_all(&s->cmdfifo, buf, len);
@ -794,8 +860,7 @@ static void esp_do_nodma(ESPState *s)
trace_esp_handle_ti_cmd(cmdlen);
/* CDB may be transferred in one or more TI commands */
if (esp_cdb_length(s) && esp_cdb_length(s) ==
fifo8_num_used(&s->cmdfifo) - s->cmdfifo_cdb_offset) {
if (esp_cdb_ready(s)) {
/* Command has been received */
do_cmd(s);
} else {
@ -815,13 +880,12 @@ static void esp_do_nodma(ESPState *s)
case CMD_SEL | CMD_DMA:
case CMD_SELATN | CMD_DMA:
/* Copy FIFO into cmdfifo */
len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
fifo8_push_all(&s->cmdfifo, buf, len);
/* Handle when DMA transfer is terminated by non-DMA FIFO write */
if (esp_cdb_length(s) && esp_cdb_length(s) ==
fifo8_num_used(&s->cmdfifo) - s->cmdfifo_cdb_offset) {
if (esp_cdb_ready(s)) {
/* Command has been received */
do_cmd(s);
}
@ -830,7 +894,7 @@ static void esp_do_nodma(ESPState *s)
case CMD_SEL:
case CMD_SELATN:
/* FIFO already contain entire CDB: copy to cmdfifo and execute */
len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
fifo8_push_all(&s->cmdfifo, buf, len);
@ -852,7 +916,7 @@ static void esp_do_nodma(ESPState *s)
return;
}
if (fifo8_is_empty(&s->fifo)) {
fifo8_push(&s->fifo, s->async_buf[0]);
esp_fifo_push(s, s->async_buf[0]);
s->async_buf++;
s->async_len--;
s->ti_size--;
@ -875,7 +939,7 @@ static void esp_do_nodma(ESPState *s)
case STAT_ST:
switch (s->rregs[ESP_CMD]) {
case CMD_ICCS:
fifo8_push(&s->fifo, s->status);
esp_fifo_push(s, s->status);
esp_set_phase(s, STAT_MI);
/* Process any message in phase data */
@ -887,7 +951,7 @@ static void esp_do_nodma(ESPState *s)
case STAT_MI:
switch (s->rregs[ESP_CMD]) {
case CMD_ICCS:
fifo8_push(&s->fifo, 0);
esp_fifo_push(s, 0);
/* Raise end of command interrupt */
s->rregs[ESP_RINTR] |= INTR_FC;
@ -951,9 +1015,6 @@ void esp_command_complete(SCSIRequest *req, size_t resid)
s->rregs[ESP_RINTR] |= INTR_BS;
esp_raise_irq(s);
/* Ensure DRQ is set correctly for TC underflow or normal completion */
esp_dma_ti_check(s);
if (s->current_req) {
scsi_req_unref(s->current_req);
s->current_req = NULL;
@ -1178,7 +1239,7 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
switch (saddr) {
case ESP_FIFO:
s->rregs[ESP_FIFO] = esp_fifo_pop(&s->fifo);
s->rregs[ESP_FIFO] = esp_fifo_pop(s);
val = s->rregs[ESP_FIFO];
break;
case ESP_RINTR:
@ -1234,7 +1295,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
break;
case ESP_FIFO:
if (!fifo8_is_full(&s->fifo)) {
esp_fifo_push(&s->fifo, val);
esp_fifo_push(s, val);
}
esp_do_nodma(s);
break;