Misc HW patches
- Fix SD cards wired in SPI mode - Fix microvm-only build by selecting Kconfig ACPI_PCI - Fix legacy Intel SMT info removing 'x-vendor-cpuid-only-v2' property check -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmiSP8sACgkQ4+MsLN6t wN52pw//R2z+DDdtezzOGIsCS8lmcI+sp0rM2UXA0LLuqH4++/SNgSOuH/yr0k9g 3DxvYxQ+zgx2gxrxG9T/KlGYdl6lE3mb9cWBah8+4UUeKuji2Zt3dh0LrZoIt9A0 EfHfPihpmVxf0OWXzDUsu3WdUyso3QHHJWVqiUCqnhvNsx1ZSAA7gOUOURL8YUEt BsCJ4ufRJA6SRqLgiOQHSn1zRVwEmXZWRt6lqWx45ynzxkquaA+pvGY3UlzUsw4b 5XyBL5Wyq1K7/FTXVXiMCYSNhgSUEbKy7Agnrr1i5s+/XfBjXMuzGFwjAWdCdwVW /Kqqndlu6COla9APndqjfMhCHU6Ql8KyKqb9HImvZyMks4QNiX3c18CjAuCVoIzE GxoXaTQ/y+Dv4tarI4EEP5m4P3gka7QVekhbSLQZJAdNDrt0QlOgmyvDLin4tQho ot/jXYTnbPZBfyZyecFnY/6Uszr5dcrI1bXdEYhiy3LZUWkzM2xNq9BJ6Y2495Ad ryqZ09UzVK8Rn6KaXTXx926eFWxFVN2VOolmLJ50D8MQfwrmMAsHtHl+qoa6T6Ta ezgnuHwONjNYAgGQgVz483/nKu4TvQ6q9bATYrZIumBITXLgVqS7GRFZ9Q17Y+V4 UHlIJ/Ay32KkMAKD+cNj01s7g6nK3YS2tP7tt16IOQHhVmsNvGE= =Rq7l -----END PGP SIGNATURE----- Merge tag 'hw-misc-20250805' of https://github.com/philmd/qemu into staging Misc HW patches - Fix SD cards wired in SPI mode - Fix microvm-only build by selecting Kconfig ACPI_PCI - Fix legacy Intel SMT info removing 'x-vendor-cpuid-only-v2' property check # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmiSP8sACgkQ4+MsLN6t # wN52pw//R2z+DDdtezzOGIsCS8lmcI+sp0rM2UXA0LLuqH4++/SNgSOuH/yr0k9g # 3DxvYxQ+zgx2gxrxG9T/KlGYdl6lE3mb9cWBah8+4UUeKuji2Zt3dh0LrZoIt9A0 # EfHfPihpmVxf0OWXzDUsu3WdUyso3QHHJWVqiUCqnhvNsx1ZSAA7gOUOURL8YUEt # BsCJ4ufRJA6SRqLgiOQHSn1zRVwEmXZWRt6lqWx45ynzxkquaA+pvGY3UlzUsw4b # 5XyBL5Wyq1K7/FTXVXiMCYSNhgSUEbKy7Agnrr1i5s+/XfBjXMuzGFwjAWdCdwVW # /Kqqndlu6COla9APndqjfMhCHU6Ql8KyKqb9HImvZyMks4QNiX3c18CjAuCVoIzE # GxoXaTQ/y+Dv4tarI4EEP5m4P3gka7QVekhbSLQZJAdNDrt0QlOgmyvDLin4tQho # ot/jXYTnbPZBfyZyecFnY/6Uszr5dcrI1bXdEYhiy3LZUWkzM2xNq9BJ6Y2495Ad # ryqZ09UzVK8Rn6KaXTXx926eFWxFVN2VOolmLJ50D8MQfwrmMAsHtHl+qoa6T6Ta # ezgnuHwONjNYAgGQgVz483/nKu4TvQ6q9bATYrZIumBITXLgVqS7GRFZ9Q17Y+V4 # UHlIJ/Ay32KkMAKD+cNj01s7g6nK3YS2tP7tt16IOQHhVmsNvGE= # =Rq7l # -----END PGP SIGNATURE----- # gpg: Signature made Tue 05 Aug 2025 13:30:51 EDT # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * tag 'hw-misc-20250805' of https://github.com/philmd/qemu: hw/i386/microvm: Explicitly select ACPI_PCI target/i386/cpu: Move addressable ID encoding out of compat property in CPUID[0x1] tests/functional: Test SD cards in SPI mode (using sifive_u machine) hw/sd/sdcard: Remove SDState::mode field hw/sd/sdcard: Disable checking STBY mode in SPI SEND_CSD/CID hw/sd/sdcard: Factor spi_cmd_SEND_CxD() out hw/sd/sdcard: Allow using SWITCH_FUNCTION in more SPI states hw/sd/sdcard: Use complete SEND_OP_COND implementation in SPI mode hw/sd/sdcard: Implement SPI R2 return value hw/sd/sdcard: Fill SPI response bits in card code hw/sd/sdbus: Provide buffer size to sdbus_do_command() hw/sd/sdcard: Factor sd_response_size() out hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata() Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
d2d08975fc
15 changed files with 251 additions and 167 deletions
|
|
@ -1695,6 +1695,7 @@ S: Supported
|
|||
F: docs/system/riscv/sifive_u.rst
|
||||
F: hw/*/*sifive*.c
|
||||
F: include/hw/*/*sifive*.h
|
||||
F: tests/functional/test_riscv64_sifive_u.py
|
||||
|
||||
AMD Microblaze-V Generic Board
|
||||
M: Sai Pavan Boddu <sai.pavan.boddu@amd.com>
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ config MICROVM
|
|||
select I8259
|
||||
select MC146818RTC
|
||||
select VIRTIO_MMIO
|
||||
select ACPI_PCI
|
||||
select ACPI_HW_REDUCED
|
||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||
select USB_XHCI_SYSBUS
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ static void allwinner_sdhost_send_command(AwSdHostState *s)
|
|||
{
|
||||
SDRequest request;
|
||||
uint8_t resp[16];
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
|
||||
/* Auto clear load flag */
|
||||
s->command &= ~SD_CMDR_LOAD;
|
||||
|
|
@ -246,10 +246,7 @@ static void allwinner_sdhost_send_command(AwSdHostState *s)
|
|||
request.arg = s->command_arg;
|
||||
|
||||
/* Send request to SD bus */
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, resp);
|
||||
if (rlen < 0) {
|
||||
goto error;
|
||||
}
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, resp, sizeof(resp));
|
||||
|
||||
/* If the command has a response, store it in the response registers */
|
||||
if ((s->command & SD_CMDR_RESPONSE)) {
|
||||
|
|
|
|||
|
|
@ -113,15 +113,12 @@ static void bcm2835_sdhost_send_command(BCM2835SDHostState *s)
|
|||
{
|
||||
SDRequest request;
|
||||
uint8_t rsp[16];
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
|
||||
request.cmd = s->cmd & SDCMD_CMD_MASK;
|
||||
request.arg = s->cmdarg;
|
||||
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, rsp);
|
||||
if (rlen < 0) {
|
||||
goto error;
|
||||
}
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, rsp, sizeof(rsp));
|
||||
if (!(s->cmd & SDCMD_NO_RESPONSE)) {
|
||||
if (rlen == 0 || (rlen == 4 && (s->cmd & SDCMD_LONG_RESPONSE))) {
|
||||
goto error;
|
||||
|
|
|
|||
|
|
@ -90,7 +90,8 @@ void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
|
|||
}
|
||||
}
|
||||
|
||||
int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
|
||||
size_t sdbus_do_command(SDBus *sdbus, SDRequest *req,
|
||||
uint8_t *resp, size_t respsz)
|
||||
{
|
||||
SDState *card = get_card(sdbus);
|
||||
|
||||
|
|
@ -98,7 +99,7 @@ int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
|
|||
if (card) {
|
||||
SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
|
||||
|
||||
return sc->do_command(card, req, response);
|
||||
return sc->do_command(card, req, resp, respsz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -130,7 +130,8 @@ static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir,
|
|||
sd_rsp_type_t resptype, int init)
|
||||
{
|
||||
uint32_t rspstatus, mask;
|
||||
int rsplen, timeout;
|
||||
size_t rsplen;
|
||||
int timeout;
|
||||
SDRequest request;
|
||||
uint8_t response[16];
|
||||
|
||||
|
|
@ -157,7 +158,7 @@ static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir,
|
|||
request.arg = host->arg;
|
||||
request.crc = 0; /* FIXME */
|
||||
|
||||
rsplen = sdbus_do_command(&host->sdbus, &request, response);
|
||||
rsplen = sdbus_do_command(&host->sdbus, &request, response, sizeof(response));
|
||||
|
||||
/* TODO: validate CRCs */
|
||||
switch (resptype) {
|
||||
|
|
|
|||
|
|
@ -173,14 +173,12 @@ static void pl181_do_command(PL181State *s)
|
|||
{
|
||||
SDRequest request;
|
||||
uint8_t response[16];
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
|
||||
request.cmd = s->cmd & PL181_CMD_INDEX;
|
||||
request.arg = s->cmdarg;
|
||||
trace_pl181_command_send(request.cmd, request.arg);
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, response);
|
||||
if (rlen < 0)
|
||||
goto error;
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
|
||||
if (s->cmd & PL181_CMD_RESPONSE) {
|
||||
if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
|
||||
goto error;
|
||||
|
|
|
|||
198
hw/sd/sd.c
198
hw/sd/sd.c
|
|
@ -61,6 +61,7 @@
|
|||
typedef enum {
|
||||
sd_r0 = 0, /* no response */
|
||||
sd_r1, /* normal response command */
|
||||
spi_r2, /* STATUS */
|
||||
sd_r2_i, /* CID register */
|
||||
sd_r2_s, /* CSD register */
|
||||
sd_r3, /* OCR register */
|
||||
|
|
@ -146,7 +147,6 @@ struct SDState {
|
|||
|
||||
/* Runtime changeables */
|
||||
|
||||
uint32_t mode; /* current card mode, one of SDCardModes */
|
||||
int32_t state; /* current card state, one of SDCardStates */
|
||||
uint32_t vhs;
|
||||
bool wp_switch;
|
||||
|
|
@ -247,6 +247,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
|
|||
static const char *response_name[] = {
|
||||
[sd_r0] = "RESP#0 (no response)",
|
||||
[sd_r1] = "RESP#1 (normal cmd)",
|
||||
[spi_r2] = "RESP#2 (STATUS reg)",
|
||||
[sd_r2_i] = "RESP#2 (CID reg)",
|
||||
[sd_r2_s] = "RESP#2 (CSD reg)",
|
||||
[sd_r3] = "RESP#3 (OCR reg)",
|
||||
|
|
@ -313,27 +314,24 @@ static void sd_set_voltage(SDState *sd, uint16_t millivolts)
|
|||
}
|
||||
}
|
||||
|
||||
static void sd_set_mode(SDState *sd)
|
||||
static enum SDCardModes sd_mode(SDState *sd)
|
||||
{
|
||||
switch (sd->state) {
|
||||
case sd_inactive_state:
|
||||
sd->mode = sd_inactive;
|
||||
break;
|
||||
|
||||
return sd_inactive;
|
||||
case sd_idle_state:
|
||||
case sd_ready_state:
|
||||
case sd_identification_state:
|
||||
sd->mode = sd_card_identification_mode;
|
||||
break;
|
||||
|
||||
return sd_card_identification_mode;
|
||||
case sd_standby_state:
|
||||
case sd_transfer_state:
|
||||
case sd_sendingdata_state:
|
||||
case sd_receivingdata_state:
|
||||
case sd_programming_state:
|
||||
case sd_disconnect_state:
|
||||
sd->mode = sd_data_transfer_mode;
|
||||
break;
|
||||
return sd_data_transfer_mode;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -729,16 +727,82 @@ static int sd_req_crc_validate(SDRequest *req)
|
|||
return sd_crc7(buffer, 5) != req->crc; /* TODO */
|
||||
}
|
||||
|
||||
static size_t sd_response_size(SDState *sd, sd_rsp_type_t rtype)
|
||||
{
|
||||
switch (rtype) {
|
||||
case sd_r1:
|
||||
case sd_r1b:
|
||||
return sd_is_spi(sd) ? 1 : 4;
|
||||
|
||||
case spi_r2:
|
||||
assert(sd_is_spi(sd));
|
||||
return 2;
|
||||
|
||||
case sd_r2_i:
|
||||
case sd_r2_s:
|
||||
assert(!sd_is_spi(sd));
|
||||
return 16;
|
||||
|
||||
case sd_r3:
|
||||
case sd_r7:
|
||||
return sd_is_spi(sd) ? 5 : 4;
|
||||
|
||||
case sd_r6:
|
||||
assert(!sd_is_spi(sd));
|
||||
return 4;
|
||||
|
||||
case sd_r0:
|
||||
case sd_illegal:
|
||||
return sd_is_spi(sd) ? 1 : 0;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void sd_response_r1_make(SDState *sd, uint8_t *response)
|
||||
{
|
||||
stl_be_p(response, sd->card_status);
|
||||
if (sd_is_spi(sd)) {
|
||||
response[0] = sd->state == sd_idle_state
|
||||
&& !FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP);
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_RESET) << 1;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, ILLEGAL_COMMAND) << 2;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, COM_CRC_ERROR) << 3;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_SEQ_ERROR) << 4;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, ADDRESS_ERROR) << 5;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, BLOCK_LEN_ERROR) << 6;
|
||||
response[0] |= 0 << 7;
|
||||
} else {
|
||||
stl_be_p(response, sd->card_status);
|
||||
}
|
||||
|
||||
/* Clear the "clear on read" status bits */
|
||||
sd->card_status &= ~CARD_STATUS_C;
|
||||
}
|
||||
|
||||
static void spi_response_r2_make(SDState *sd, uint8_t *resp)
|
||||
{
|
||||
/* Prepend R1 */
|
||||
sd_response_r1_make(sd, resp);
|
||||
|
||||
resp[1] = FIELD_EX32(sd->card_status, CSR, CARD_IS_LOCKED) << 0;
|
||||
resp[1] |= (FIELD_EX32(sd->card_status, CSR, LOCK_UNLOCK_FAILED)
|
||||
|| FIELD_EX32(sd->card_status, CSR, WP_ERASE_SKIP)) << 1;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, ERROR) << 2;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, CC_ERROR) << 3;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, CARD_ECC_FAILED) << 4;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, WP_VIOLATION) << 5;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, ERASE_PARAM) << 6;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, OUT_OF_RANGE) << 7;
|
||||
}
|
||||
|
||||
static void sd_response_r3_make(SDState *sd, uint8_t *response)
|
||||
{
|
||||
if (sd_is_spi(sd)) {
|
||||
/* Prepend R1 */
|
||||
sd_response_r1_make(sd, response);
|
||||
response++;
|
||||
}
|
||||
stl_be_p(response, sd->ocr & ACMD41_R3_MASK);
|
||||
}
|
||||
|
||||
|
|
@ -756,6 +820,11 @@ static void sd_response_r6_make(SDState *sd, uint8_t *response)
|
|||
|
||||
static void sd_response_r7_make(SDState *sd, uint8_t *response)
|
||||
{
|
||||
if (sd_is_spi(sd)) {
|
||||
/* Prepend R1 */
|
||||
sd_response_r1_make(sd, response);
|
||||
response++;
|
||||
}
|
||||
stl_be_p(response, sd->vhs);
|
||||
}
|
||||
|
||||
|
|
@ -952,7 +1021,7 @@ static const VMStateDescription sd_vmstate = {
|
|||
.minimum_version_id = 2,
|
||||
.pre_load = sd_vmstate_pre_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(mode, SDState),
|
||||
VMSTATE_UNUSED(4),
|
||||
VMSTATE_INT32(state, SDState),
|
||||
VMSTATE_UINT8_ARRAY(cid, SDState, 16),
|
||||
VMSTATE_UINT8_ARRAY(csd, SDState, 16),
|
||||
|
|
@ -1252,7 +1321,7 @@ static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req)
|
|||
static sd_rsp_type_t sd_invalid_mode_for_cmd(SDState *sd, SDRequest req)
|
||||
{
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: CMD%i in a wrong mode: %s (spec %s)\n",
|
||||
sd->proto->name, req.cmd, sd_mode_name(sd->mode),
|
||||
sd->proto->name, req.cmd, sd_mode_name(sd_mode(sd)),
|
||||
sd_version_str(sd->spec_version));
|
||||
|
||||
return sd_illegal;
|
||||
|
|
@ -1305,7 +1374,7 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req,
|
|||
const void *data, size_t size)
|
||||
{
|
||||
if (sd->state != sd_transfer_state) {
|
||||
sd_invalid_state_for_cmd(sd, req);
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
|
||||
sd->state = sd_sendingdata_state;
|
||||
|
|
@ -1341,14 +1410,6 @@ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req)
|
|||
return sd_is_spi(sd) ? sd_r1 : sd_r0;
|
||||
}
|
||||
|
||||
/* CMD1 */
|
||||
static sd_rsp_type_t spi_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
|
||||
{
|
||||
sd->state = sd_transfer_state;
|
||||
|
||||
return sd_r1;
|
||||
}
|
||||
|
||||
/* CMD2 */
|
||||
static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req)
|
||||
{
|
||||
|
|
@ -1420,11 +1481,17 @@ static sd_rsp_type_t emmc_cmd_sleep_awake(SDState *sd, SDRequest req)
|
|||
/* CMD6 */
|
||||
static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req)
|
||||
{
|
||||
if (sd->mode != sd_data_transfer_mode) {
|
||||
if (sd_mode(sd) != sd_data_transfer_mode) {
|
||||
return sd_invalid_mode_for_cmd(sd, req);
|
||||
}
|
||||
if (sd->state != sd_transfer_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
if (sd_is_spi(sd)) {
|
||||
if (sd->state == sd_idle_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
} else {
|
||||
if (sd->state != sd_transfer_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
}
|
||||
|
||||
sd_function_switch(sd, req.arg);
|
||||
|
|
@ -1517,14 +1584,30 @@ static sd_rsp_type_t emmc_cmd_SEND_EXT_CSD(SDState *sd, SDRequest req)
|
|||
sd->ext_csd, sizeof(sd->ext_csd));
|
||||
}
|
||||
|
||||
/* CMD9 */
|
||||
static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
|
||||
static sd_rsp_type_t spi_cmd_SEND_CxD(SDState *sd, SDRequest req,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
/*
|
||||
* XXX as of v10.1.0-rc1 command is reached in sd_idle_state,
|
||||
* so disable this check.
|
||||
if (sd->state != sd_standby_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
|
||||
sd->csd, 16);
|
||||
*/
|
||||
|
||||
/*
|
||||
* Since SPI returns CSD and CID on the DAT lines,
|
||||
* switch to sd_transfer_state.
|
||||
*/
|
||||
sd->state = sd_transfer_state;
|
||||
|
||||
return sd_cmd_to_sendingdata(sd, req, 0, data, size);
|
||||
}
|
||||
|
||||
/* CMD9 */
|
||||
static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
|
||||
{
|
||||
return spi_cmd_SEND_CxD(sd, req, sd->csd, sizeof(sd->csd));
|
||||
}
|
||||
|
||||
static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
|
||||
|
|
@ -1539,11 +1622,7 @@ static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
|
|||
/* CMD10 */
|
||||
static sd_rsp_type_t spi_cmd_SEND_CID(SDState *sd, SDRequest req)
|
||||
{
|
||||
if (sd->state != sd_standby_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
|
||||
sd->cid, 16);
|
||||
return spi_cmd_SEND_CxD(sd, req, sd->cid, sizeof(sd->cid));
|
||||
}
|
||||
|
||||
static sd_rsp_type_t sd_cmd_SEND_CID(SDState *sd, SDRequest req)
|
||||
|
|
@ -1575,7 +1654,7 @@ static sd_rsp_type_t sd_cmd_STOP_TRANSMISSION(SDState *sd, SDRequest req)
|
|||
/* CMD13 */
|
||||
static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
|
||||
{
|
||||
if (sd->mode != sd_data_transfer_mode) {
|
||||
if (sd_mode(sd) != sd_data_transfer_mode) {
|
||||
return sd_invalid_mode_for_cmd(sd, req);
|
||||
}
|
||||
|
||||
|
|
@ -1592,7 +1671,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
|
|||
}
|
||||
|
||||
if (sd_is_spi(sd)) {
|
||||
return sd_r2_s;
|
||||
return spi_r2;
|
||||
}
|
||||
|
||||
return sd_req_rca_same(sd, req) ? sd_r1 : sd_r0;
|
||||
|
|
@ -1601,7 +1680,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
|
|||
/* CMD15 */
|
||||
static sd_rsp_type_t sd_cmd_GO_INACTIVE_STATE(SDState *sd, SDRequest req)
|
||||
{
|
||||
if (sd->mode != sd_data_transfer_mode) {
|
||||
if (sd_mode(sd) != sd_data_transfer_mode) {
|
||||
return sd_invalid_mode_for_cmd(sd, req);
|
||||
}
|
||||
switch (sd->state) {
|
||||
|
|
@ -1906,8 +1985,14 @@ static sd_rsp_type_t sd_acmd_SET_BUS_WIDTH(SDState *sd, SDRequest req)
|
|||
/* ACMD13 */
|
||||
static sd_rsp_type_t sd_acmd_SD_STATUS(SDState *sd, SDRequest req)
|
||||
{
|
||||
return sd_cmd_to_sendingdata(sd, req, 0,
|
||||
sd->sd_status, sizeof(sd->sd_status));
|
||||
sd_rsp_type_t rsp;
|
||||
|
||||
rsp = sd_cmd_to_sendingdata(sd, req, 0,
|
||||
sd->sd_status, sizeof(sd->sd_status));
|
||||
if (sd_is_spi(sd) && rsp != sd_illegal) {
|
||||
return spi_r2;
|
||||
}
|
||||
return rsp;
|
||||
}
|
||||
|
||||
/* ACMD22 */
|
||||
|
|
@ -1967,6 +2052,9 @@ static sd_rsp_type_t sd_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
|
|||
sd->state = sd_ready_state;
|
||||
}
|
||||
|
||||
if (sd_is_spi(sd)) {
|
||||
return sd_r1;
|
||||
}
|
||||
return sd_r3;
|
||||
}
|
||||
|
||||
|
|
@ -1998,7 +2086,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
|
|||
if (req.cmd != 55 || sd->expecting_acmd) {
|
||||
trace_sdcard_normal_command(sd->proto->name,
|
||||
sd->last_cmd_name, req.cmd,
|
||||
req.arg, sd_state_name(sd->state));
|
||||
req.arg,
|
||||
sd_mode_name(sd_mode(sd)),
|
||||
sd_state_name(sd->state));
|
||||
}
|
||||
|
||||
/* Not interpreting this as an app command */
|
||||
|
|
@ -2084,7 +2174,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
|
|||
{
|
||||
sd->last_cmd_name = sd_acmd_name(sd, req.cmd);
|
||||
trace_sdcard_app_command(sd->proto->name, sd->last_cmd_name,
|
||||
req.cmd, req.arg, sd_state_name(sd->state));
|
||||
req.cmd, req.arg,
|
||||
sd_mode_name(sd_mode(sd)),
|
||||
sd_state_name(sd->state));
|
||||
sd->card_status |= APP_CMD;
|
||||
|
||||
if (sd->proto->acmd[req.cmd].handler) {
|
||||
|
|
@ -2139,8 +2231,9 @@ static bool cmd_valid_while_locked(SDState *sd, unsigned cmd)
|
|||
return cmd_class == 0 || cmd_class == 7;
|
||||
}
|
||||
|
||||
static int sd_do_command(SDState *sd, SDRequest *req,
|
||||
uint8_t *response) {
|
||||
static size_t sd_do_command(SDState *sd, SDRequest *req,
|
||||
uint8_t *response, size_t respsz)
|
||||
{
|
||||
int last_state;
|
||||
sd_rsp_type_t rtype;
|
||||
int rsplen;
|
||||
|
|
@ -2183,7 +2276,6 @@ static int sd_do_command(SDState *sd, SDRequest *req,
|
|||
}
|
||||
|
||||
last_state = sd->state;
|
||||
sd_set_mode(sd);
|
||||
|
||||
if (sd->expecting_acmd) {
|
||||
sd->expecting_acmd = false;
|
||||
|
|
@ -2203,36 +2295,37 @@ static int sd_do_command(SDState *sd, SDRequest *req,
|
|||
}
|
||||
|
||||
send_response:
|
||||
rsplen = sd_response_size(sd, rtype);
|
||||
assert(rsplen <= respsz);
|
||||
|
||||
switch (rtype) {
|
||||
case sd_r1:
|
||||
case sd_r1b:
|
||||
sd_response_r1_make(sd, response);
|
||||
rsplen = 4;
|
||||
break;
|
||||
|
||||
case spi_r2:
|
||||
spi_response_r2_make(sd, response);
|
||||
break;
|
||||
|
||||
case sd_r2_i:
|
||||
memcpy(response, sd->cid, sizeof(sd->cid));
|
||||
rsplen = 16;
|
||||
break;
|
||||
|
||||
case sd_r2_s:
|
||||
memcpy(response, sd->csd, sizeof(sd->csd));
|
||||
rsplen = 16;
|
||||
break;
|
||||
|
||||
case sd_r3:
|
||||
sd_response_r3_make(sd, response);
|
||||
rsplen = 4;
|
||||
break;
|
||||
|
||||
case sd_r6:
|
||||
sd_response_r6_make(sd, response);
|
||||
rsplen = 4;
|
||||
break;
|
||||
|
||||
case sd_r7:
|
||||
sd_response_r7_make(sd, response);
|
||||
rsplen = 4;
|
||||
break;
|
||||
|
||||
case sd_r0:
|
||||
|
|
@ -2244,7 +2337,6 @@ send_response:
|
|||
sd->data_offset = 0;
|
||||
/* fall-through */
|
||||
case sd_illegal:
|
||||
rsplen = 0;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
|
|
@ -2510,7 +2602,7 @@ static const SDProto sd_proto_spi = {
|
|||
.name = "SPI",
|
||||
.cmd = {
|
||||
[0] = {0, sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE},
|
||||
[1] = {0, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
|
||||
[1] = {0, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
|
||||
[5] = {9, sd_spi, "IO_SEND_OP_COND", sd_cmd_optional},
|
||||
[6] = {10, sd_spi, "SWITCH_FUNCTION", sd_cmd_SWITCH_FUNCTION},
|
||||
[8] = {0, sd_spi, "SEND_IF_COND", sd_cmd_SEND_IF_COND},
|
||||
|
|
@ -2546,7 +2638,7 @@ static const SDProto sd_proto_spi = {
|
|||
[13] = {8, sd_spi, "SD_STATUS", sd_acmd_SD_STATUS},
|
||||
[22] = {8, sd_spi, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS},
|
||||
[23] = {8, sd_spi, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT},
|
||||
[41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
|
||||
[41] = {8, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
|
||||
[42] = {8, sd_spi, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT},
|
||||
[51] = {8, sd_spi, "SEND_SCR", sd_acmd_SEND_SCR},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ static void sdhci_send_command(SDHCIState *s)
|
|||
{
|
||||
SDRequest request;
|
||||
uint8_t response[16];
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
bool timeout = false;
|
||||
|
||||
s->errintsts = 0;
|
||||
|
|
@ -346,7 +346,7 @@ static void sdhci_send_command(SDHCIState *s)
|
|||
request.arg = s->argument;
|
||||
|
||||
trace_sdhci_send_command(request.cmd, request.arg);
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, response);
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
|
||||
|
||||
if (s->cmdreg & SDHC_CMD_RESPONSE) {
|
||||
if (rlen == 4) {
|
||||
|
|
@ -400,7 +400,7 @@ static void sdhci_end_transfer(SDHCIState *s)
|
|||
request.cmd = 0x0C;
|
||||
request.arg = 0;
|
||||
trace_sdhci_end_transfer(request.cmd, request.arg);
|
||||
sdbus_do_command(&s->sdbus, &request, response);
|
||||
sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
|
||||
/* Auto CMD12 response goes to the upper Response register */
|
||||
s->rspreg[3] = ldl_be_p(response);
|
||||
}
|
||||
|
|
|
|||
100
hw/sd/ssi-sd.c
100
hw/sd/ssi-sd.c
|
|
@ -70,23 +70,6 @@ struct ssi_sd_state {
|
|||
#define TYPE_SSI_SD "ssi-sd"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
|
||||
|
||||
/* State word bits. */
|
||||
#define SSI_SDR_LOCKED 0x0001
|
||||
#define SSI_SDR_WP_ERASE 0x0002
|
||||
#define SSI_SDR_ERROR 0x0004
|
||||
#define SSI_SDR_CC_ERROR 0x0008
|
||||
#define SSI_SDR_ECC_FAILED 0x0010
|
||||
#define SSI_SDR_WP_VIOLATION 0x0020
|
||||
#define SSI_SDR_ERASE_PARAM 0x0040
|
||||
#define SSI_SDR_OUT_OF_RANGE 0x0080
|
||||
#define SSI_SDR_IDLE 0x0100
|
||||
#define SSI_SDR_ERASE_RESET 0x0200
|
||||
#define SSI_SDR_ILLEGAL_COMMAND 0x0400
|
||||
#define SSI_SDR_COM_CRC_ERROR 0x0800
|
||||
#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
|
||||
#define SSI_SDR_ADDRESS_ERROR 0x2000
|
||||
#define SSI_SDR_PARAMETER_ERROR 0x4000
|
||||
|
||||
/* multiple block write */
|
||||
#define SSI_TOKEN_MULTI_WRITE 0xfc
|
||||
/* terminate multiple block write */
|
||||
|
|
@ -104,7 +87,7 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
|||
{
|
||||
ssi_sd_state *s = SSI_SD(dev);
|
||||
SDRequest request;
|
||||
uint8_t longresp[16];
|
||||
uint8_t longresp[5];
|
||||
|
||||
/*
|
||||
* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.
|
||||
|
|
@ -146,8 +129,9 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
|||
/* manually issue cmd12 to stop the transfer */
|
||||
request.cmd = 12;
|
||||
request.arg = 0;
|
||||
s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
|
||||
if (s->arglen <= 0) {
|
||||
s->arglen = sdbus_do_command(&s->sdbus, &request,
|
||||
longresp, sizeof(longresp));
|
||||
if (s->arglen == 0) {
|
||||
s->arglen = 1;
|
||||
/* a zero value indicates the card is busy */
|
||||
s->response[0] = 0;
|
||||
|
|
@ -170,73 +154,15 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
|||
/* FIXME: Check CRC. */
|
||||
request.cmd = s->cmd;
|
||||
request.arg = ldl_be_p(s->cmdarg);
|
||||
DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
|
||||
s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
|
||||
if (s->arglen <= 0) {
|
||||
s->arglen = 1;
|
||||
s->response[0] = 4;
|
||||
DPRINTF("SD command failed\n");
|
||||
} else if (s->cmd == 8 || s->cmd == 58) {
|
||||
/* CMD8/CMD58 returns R3/R7 response */
|
||||
DPRINTF("Returned R3/R7\n");
|
||||
s->arglen = 5;
|
||||
s->response[0] = 1;
|
||||
memcpy(&s->response[1], longresp, 4);
|
||||
} else if (s->arglen != 4) {
|
||||
BADF("Unexpected response to cmd %d\n", s->cmd);
|
||||
/* Illegal command is about as near as we can get. */
|
||||
s->arglen = 1;
|
||||
s->response[0] = 4;
|
||||
} else {
|
||||
/* All other commands return status. */
|
||||
uint32_t cardstatus;
|
||||
uint16_t status;
|
||||
/* CMD13 returns a 2-byte statuse work. Other commands
|
||||
only return the first byte. */
|
||||
s->arglen = (s->cmd == 13) ? 2 : 1;
|
||||
s->arglen = sdbus_do_command(&s->sdbus, &request,
|
||||
longresp, sizeof(longresp));
|
||||
DPRINTF("CMD%d arg 0x%08x = %d\n", s->cmd, request.arg, s->arglen);
|
||||
assert(s->arglen > 0);
|
||||
memcpy(s->response, longresp, s->arglen);
|
||||
|
||||
/* handle R1b */
|
||||
if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
|
||||
s->stopping = 1;
|
||||
}
|
||||
|
||||
cardstatus = ldl_be_p(longresp);
|
||||
status = 0;
|
||||
if (((cardstatus >> 9) & 0xf) < 4)
|
||||
status |= SSI_SDR_IDLE;
|
||||
if (cardstatus & ERASE_RESET)
|
||||
status |= SSI_SDR_ERASE_RESET;
|
||||
if (cardstatus & ILLEGAL_COMMAND)
|
||||
status |= SSI_SDR_ILLEGAL_COMMAND;
|
||||
if (cardstatus & COM_CRC_ERROR)
|
||||
status |= SSI_SDR_COM_CRC_ERROR;
|
||||
if (cardstatus & ERASE_SEQ_ERROR)
|
||||
status |= SSI_SDR_ERASE_SEQ_ERROR;
|
||||
if (cardstatus & ADDRESS_ERROR)
|
||||
status |= SSI_SDR_ADDRESS_ERROR;
|
||||
if (cardstatus & CARD_IS_LOCKED)
|
||||
status |= SSI_SDR_LOCKED;
|
||||
if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
|
||||
status |= SSI_SDR_WP_ERASE;
|
||||
if (cardstatus & SD_ERROR)
|
||||
status |= SSI_SDR_ERROR;
|
||||
if (cardstatus & CC_ERROR)
|
||||
status |= SSI_SDR_CC_ERROR;
|
||||
if (cardstatus & CARD_ECC_FAILED)
|
||||
status |= SSI_SDR_ECC_FAILED;
|
||||
if (cardstatus & WP_VIOLATION)
|
||||
status |= SSI_SDR_WP_VIOLATION;
|
||||
if (cardstatus & ERASE_PARAM)
|
||||
status |= SSI_SDR_ERASE_PARAM;
|
||||
if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
|
||||
status |= SSI_SDR_OUT_OF_RANGE;
|
||||
/* ??? Don't know what Parameter Error really means, so
|
||||
assume it's set if the second byte is nonzero. */
|
||||
if (status & 0xff)
|
||||
status |= SSI_SDR_PARAMETER_ERROR;
|
||||
s->response[0] = status >> 8;
|
||||
s->response[1] = status;
|
||||
DPRINTF("Card status 0x%02x\n", status);
|
||||
/* handle R1b (busy signal) */
|
||||
if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
|
||||
s->stopping = 1;
|
||||
}
|
||||
s->mode = SSI_SD_PREP_RESP;
|
||||
s->response_pos = 0;
|
||||
|
|
@ -333,7 +259,7 @@ static int ssi_sd_post_load(void *opaque, int version_id)
|
|||
return -EINVAL;
|
||||
}
|
||||
if (s->mode == SSI_SD_CMDARG &&
|
||||
(s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) {
|
||||
(s->arglen >= ARRAY_SIZE(s->cmdarg))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (s->mode == SSI_SD_RESPONSE &&
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ sdhci_write_dataport(uint16_t data_count) "write buffer filled with %u bytes of
|
|||
sdhci_capareg(const char *desc, uint16_t val) "%s: %u"
|
||||
|
||||
# sd.c
|
||||
sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *state) "%s %20s/ CMD%02d arg 0x%08x (state %s)"
|
||||
sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *state) "%s %23s/ACMD%02d arg 0x%08x (state %s)"
|
||||
sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *mode, const char *state) "%s %20s/ CMD%02d arg 0x%08x (mode %s, state %s)"
|
||||
sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *mode, const char *state) "%s %23s/ACMD%02d arg 0x%08x (mode %s, state %s)"
|
||||
sdcard_response(const char *rspdesc, int rsplen) "%s (sz:%d)"
|
||||
sdcard_powerup(void) ""
|
||||
sdcard_inquiry_cmd41(void) ""
|
||||
|
|
|
|||
|
|
@ -96,7 +96,17 @@ struct SDCardClass {
|
|||
DeviceClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
int (*do_command)(SDState *sd, SDRequest *req, uint8_t *response);
|
||||
/**
|
||||
* Process a SD command request.
|
||||
* @sd: card
|
||||
* @req: command request
|
||||
* @resp: buffer to receive the command response
|
||||
* @respsz: size of @resp buffer
|
||||
*
|
||||
* Return: size of the response
|
||||
*/
|
||||
size_t (*do_command)(SDState *sd, SDRequest *req,
|
||||
uint8_t *resp, size_t respsz);
|
||||
/**
|
||||
* Write a byte to a SD card.
|
||||
* @sd: card
|
||||
|
|
@ -153,7 +163,16 @@ struct SDBusClass {
|
|||
void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts);
|
||||
uint8_t sdbus_get_dat_lines(SDBus *sdbus);
|
||||
bool sdbus_get_cmd_line(SDBus *sdbus);
|
||||
int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response);
|
||||
/**
|
||||
* sdbus_do_command: Process a SD command request
|
||||
* @sd: card
|
||||
* @req: command request
|
||||
* @resp: buffer to receive the command response
|
||||
* @respsz: size of @resp buffer
|
||||
*
|
||||
* Return: size of the response
|
||||
*/
|
||||
size_t sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *resp, size_t respsz);
|
||||
/**
|
||||
* Write a byte to a SD bus.
|
||||
* @sd: bus
|
||||
|
|
|
|||
|
|
@ -7885,8 +7885,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|||
* count, but Intel needs maximum number of addressable IDs for
|
||||
* logical processors per package.
|
||||
*/
|
||||
if (cpu->vendor_cpuid_only_v2 &&
|
||||
(IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
|
||||
if ((IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
|
||||
num = 1 << apicid_pkg_offset(topo_info);
|
||||
} else {
|
||||
num = threads_per_pkg;
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ tests_riscv64_system_quick = [
|
|||
]
|
||||
|
||||
tests_riscv64_system_thorough = [
|
||||
'riscv64_sifive_u',
|
||||
'riscv64_tuxrun',
|
||||
]
|
||||
|
||||
|
|
|
|||
51
tests/functional/test_riscv64_sifive_u.py
Executable file
51
tests/functional/test_riscv64_sifive_u.py
Executable file
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Functional test that boots a Linux kernel on a Sifive U machine
|
||||
# and checks the console
|
||||
#
|
||||
# Copyright (c) Linaro Ltd.
|
||||
#
|
||||
# Author:
|
||||
# Philippe Mathieu-Daudé
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
|
||||
from qemu_test import Asset, LinuxKernelTest
|
||||
from qemu_test import skipIfMissingCommands
|
||||
|
||||
|
||||
class SifiveU(LinuxKernelTest):
|
||||
|
||||
ASSET_KERNEL = Asset(
|
||||
'https://storage.tuxboot.com/buildroot/20241119/riscv64/Image',
|
||||
'2bd8132a3bf21570290042324fff48c987f42f2a00c08de979f43f0662ebadba')
|
||||
ASSET_ROOTFS = Asset(
|
||||
('https://github.com/groeck/linux-build-test/raw/'
|
||||
'9819da19e6eef291686fdd7b029ea00e764dc62f/rootfs/riscv64/'
|
||||
'rootfs.ext2.gz'),
|
||||
'b6ed95610310b7956f9bf20c4c9c0c05fea647900df441da9dfe767d24e8b28b')
|
||||
|
||||
def test_riscv64_sifive_u_mmc_spi(self):
|
||||
self.set_machine('sifive_u')
|
||||
kernel_path = self.ASSET_KERNEL.fetch()
|
||||
rootfs_path = self.uncompress(self.ASSET_ROOTFS)
|
||||
|
||||
self.vm.set_console()
|
||||
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
|
||||
'root=/dev/mmcblk0 rootwait '
|
||||
'earlycon=sbi console=ttySIF0 '
|
||||
'panic=-1 noreboot')
|
||||
self.vm.add_args('-kernel', kernel_path,
|
||||
'-drive', f'file={rootfs_path},if=sd,format=raw',
|
||||
'-append', kernel_command_line,
|
||||
'-no-reboot')
|
||||
self.vm.launch()
|
||||
self.wait_for_console_pattern('Boot successful.')
|
||||
|
||||
os.remove(rootfs_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
LinuxKernelTest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue