debug: vuart: add guest break key support

The break key (key value 0x0) was used as switch key from guest serial
to hv console and guest serial could not receive break key. This blocked
some guest debugging features like KGDB/KDB, sysrq, etc.

This patch leverages escape sequence "<escape> + <break>" to send break to
guest and "<escape> + e" to switch from guest serial to hv console.

Tracked-On: #8583
Signed-off-by: Qiang Zhang <qiang4.zhang@intel.com>
Reviewed-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
Qiang Zhang 2024-04-17 15:05:50 +08:00 committed by acrnsi-robot
parent 01beb65527
commit c623e11125
3 changed files with 36 additions and 11 deletions

View File

@ -22,7 +22,8 @@ struct hv_timer console_timer;
#define CONSOLE_KICK_TIMER_TIMEOUT 40UL /* timeout is 40ms*/
/* Switching key combinations for shell and uart console */
#define GUEST_CONSOLE_TO_HV_SWITCH_KEY 0 /* CTRL + SPACE */
#define GUEST_CONSOLE_ESCAPE_KEY 0x0 /* the "break", put twice to send "break" to guest */
#define GUEST_CONSOLE_TO_HV_SWITCH_KEY 'e' /* escape + e to switch back to hv console */
uint16_t console_vmid = CONFIG_CONSOLE_DEFAULT_VM;
/* if use INIT to kick pcpu only, if not notification IPI still is used for sharing CPU */
@ -112,16 +113,35 @@ static void vuart_console_rx_chars(struct acrn_vuart *vu)
if (ch == -1)
break;
if (ch == GUEST_CONSOLE_TO_HV_SWITCH_KEY) {
/* Switch the console */
console_vmid = ACRN_INVALID_VMID;
printf("\r\n\r\n ---Entering ACRN SHELL---\r\n");
break;
if (vu->escaping) {
vu->escaping = false;
switch (ch) {
case GUEST_CONSOLE_ESCAPE_KEY:
vuart_putchar(vu, ch);
vu->lsr |= LSR_BI;
recv = true;
break;
case GUEST_CONSOLE_TO_HV_SWITCH_KEY:
/* Switch the console */
console_vmid = ACRN_INVALID_VMID;
printf("\r\n\r\n ---Entering ACRN SHELL---\r\n");
/* following inputs are for hv, don't handle in this loop */
goto exit;
default:
printf("Unknown escaping key: '%c'\r\n", ch);
break;
}
} else {
if (ch == GUEST_CONSOLE_ESCAPE_KEY) {
vu->escaping = true;
} else {
vuart_putchar(vu, ch);
recv = true;
}
}
vuart_putchar(vu, ch);
recv = true;
}
exit:
if (recv) {
vuart_toggle_intr(vu);
}

View File

@ -135,7 +135,7 @@ static uint8_t vuart_intr_reason(const struct acrn_vuart *vu)
{
uint8_t ret;
if (((vu->lsr & LSR_OE) != 0U) && ((vu->ier & IER_ELSI) != 0U)) {
if (((vu->lsr & (LSR_OE | LSR_BI)) != 0U) && ((vu->ier & IER_ELSI) != 0U)) {
ret = IIR_RLS;
} else if ((fifo_numchars(&vu->rxfifo) > 0U) && ((vu->ier & IER_ERBFI) != 0U)) {
ret = IIR_RXTOUT;
@ -499,7 +499,7 @@ uint8_t vuart_read_reg(struct acrn_vuart *vu, uint16_t offset)
}
reg = vu->lsr;
/* The LSR_OE bit is cleared on LSR read */
vu->lsr &= ~LSR_OE;
vu->lsr &= ~(LSR_OE | LSR_BI);
break;
case UART16550_MSR:
/*
@ -655,6 +655,7 @@ void init_legacy_vuarts(struct acrn_vm *vm, const struct vuart_config *vu_config
vu->irq = vu_config[i].irq;
if (vuart_register_io_handler(vm, vu->port_base, i) != 0U) {
vu->active = true;
vu->escaping = false;
}
/*
* The first vuart is used for VM console.
@ -674,6 +675,7 @@ void deinit_legacy_vuarts(struct acrn_vm *vm)
for (i = 0U; i < MAX_VUART_NUM_PER_VM; i++) {
if (vm->vuart[i].port_base != INVALID_COM_BASE) {
vm->vuart[i].active = false;
vm->vuart[i].escaping = false;
if (vm->vuart[i].target_vu != NULL) {
vuart_deinit_connection(&vm->vuart[i]);
}
@ -696,6 +698,7 @@ void init_pci_vuart(struct pci_vdev *vdev)
vm_cfg->vuart[idx].t_vuart.vuart_id = pci_cfg->t_vuart.vuart_id;
vu->active = true;
vu->escaping = false;
if (pci_cfg->vuart_idx != 0U) {
vuart_setup_connection(vm, &vm_cfg->vuart[idx], idx);
}
@ -707,6 +710,7 @@ void deinit_pci_vuart(struct pci_vdev *vdev)
struct acrn_vuart *vu = vdev->priv_data;
vu->active = false;
vu->escaping = false;
if (vu->target_vu != NULL) {
vuart_deinit_connection(vu);
}

View File

@ -75,6 +75,7 @@ struct acrn_vuart {
char vuart_tx_buf[TX_BUF_SIZE];
bool thre_int_pending; /* THRE interrupt pending */
bool active;
bool escaping; /* in escaping sequence, for console vuarts */
struct acrn_vuart *target_vu; /* Pointer to target vuart */
struct acrn_vm *vm;
struct pci_vdev *vdev; /* pci vuart */