Re: [PATCH v4] hv: shell: improve console to modify input easier


Eddie Dong
 

Acked-by: Eddie Dong <eddie.dong@...>

-----Original Message-----
From: acrn-dev@... <acrn-dev@...> On
Behalf Of Minggui Cao
Sent: Wednesday, July 27, 2022 4:23 PM
To: acrn-dev@...
Cc: Cao, Minggui <minggui.cao@...>
Subject: [acrn-dev] [PATCH v4] hv: shell: improve console to modify input easier

1. make memcpy_erms as a public API; add a new one
memcpy_erms_backwards, which supports to copy data from tail to head.

2. improve to use right/left/home/end key to move cursor, and support
delete/backspace key to modify current input command.

Signed-off-by: Minggui Cao <minggui.cao@...>


it is based on:
[acrn-dev] [PATCH v4] hv: shell: improve console to buffer history
cmds

---
hypervisor/arch/x86/lib/memory.c | 11 ++-
hypervisor/debug/shell.c | 159 +++++++++++++++++++++++++------
hypervisor/debug/shell_priv.h | 1 +
hypervisor/include/lib/rtl.h | 2 +
4 files changed, 145 insertions(+), 28 deletions(-)

diff --git a/hypervisor/arch/x86/lib/memory.c
b/hypervisor/arch/x86/lib/memory.c
index 9ff58ee32..65c1a6c14 100644
--- a/hypervisor/arch/x86/lib/memory.c
+++ b/hypervisor/arch/x86/lib/memory.c
@@ -24,7 +24,7 @@ void *memset(void *base, uint8_t v, size_t n)
return base;
}

-static inline void memcpy_erms(void *d, const void *s, size_t slen)
+void memcpy_erms(void *d, const void *s, size_t slen)
{
asm volatile ("rep; movsb"
: "=&D"(d), "=&S"(s)
@@ -32,6 +32,15 @@ static inline void memcpy_erms(void *d, const void *s,
size_t slen)
: "memory");
}

+/* copy data from tail to head (backwards) with ERMS (Enhanced REP
+MOVSB/STOSB) */ void memcpy_erms_backwards(void *d, const void *s,
+size_t slen) {
+ asm volatile ("std; rep; movsb; cld"
+ : "=&D"(d), "=&S"(s)
+ : "c"(slen), "0" (d), "1" (s)
+ : "memory");
+}
+
/*
* @brief Copies at most slen bytes from src address to dest address, up to
dmax.
*
diff --git a/hypervisor/debug/shell.c b/hypervisor/debug/shell.c index
979bd464f..ec8eb1f59 100644
--- a/hypervisor/debug/shell.c
+++ b/hypervisor/debug/shell.c
@@ -157,12 +157,17 @@ static struct shell_cmd shell_cmds[] = {
},
};

-/* for function key: up/down key */
+/* for function key: up/down/right/left/home/end and delete key */
enum function_key {
KEY_NONE,

+ KEY_DELETE = 0x5B33,
KEY_UP = 0x5B41,
KEY_DOWN = 0x5B42,
+ KEY_RIGHT = 0x5B43,
+ KEY_LEFT = 0x5B44,
+ KEY_END = 0x5B46,
+ KEY_HOME = 0x5B48,
};

/* The initial log level*/
@@ -287,6 +292,40 @@ static void clear_input_line(uint32_t len)
}
}

+static void set_cursor_pos(uint32_t left_offset) {
+ while (left_offset > 0) {
+ left_offset--;
+ shell_puts("\b");
+ }
+}
+
+static void handle_delete_key(void)
+{
+ if (p_shell->cursor_offset < p_shell->input_line_len) {
+
+ uint32_t delta = p_shell->input_line_len - p_shell-
cursor_offset -
+1;
+
+ /* Send a space + backspace sequence to delete character */
+ shell_puts(" \b");
+
+ /* display the left input chars and remove former last one */
+ shell_puts(p_shell->buffered_line[p_shell->input_line_active]
+ p_shell->cursor_offset + 1);
+ shell_puts(" \b");
+
+ set_cursor_pos(delta);
+
+ memcpy_erms(p_shell->buffered_line[p_shell-
input_line_active] + p_shell->cursor_offset,
+ p_shell->buffered_line[p_shell->input_line_active] +
+p_shell->cursor_offset + 1, delta);
+
+ /* Null terminate the last character to erase it */
+
+p_shell->buffered_line[p_shell->input_line_active][p_shell->input_line_
+len - 1] = 0;
+
+ /* Reduce the length of the string by one */
+ p_shell->input_line_len--;
+ }
+}
+
static void handle_updown_key(enum function_key key_value) {
int32_t to_select, current_select = p_shell->to_select_index; @@ -
316,6 +355,10 @@ static void handle_updown_key(enum function_key
key_value)
}

if (strcmp(p_shell->buffered_line[current_select], p_shell-
buffered_line[p_shell->input_line_active]) != 0) {
+ /* reset cursor pos and clear current input line first, then
output selected cmd */
+ if (p_shell->cursor_offset < p_shell->input_line_len) {
+ shell_puts(p_shell->buffered_line[p_shell-
input_line_active] + p_shell->cursor_offset);
+ }

clear_input_line(p_shell->input_line_len);
shell_puts(p_shell->buffered_line[current_select]);
@@ -325,6 +368,7 @@ static void handle_updown_key(enum function_key
key_value)
memcpy_s(p_shell->buffered_line[p_shell->input_line_active],
SHELL_CMD_MAX_LEN,
p_shell->buffered_line[current_select], len + 1);
p_shell->input_line_len = len;
+ p_shell->cursor_offset = len;
}
}

@@ -333,15 +377,46 @@ static void shell_handle_special_char(char ch)
enum function_key key_value = KEY_NONE;

switch (ch) {
- /* original function key value: ESC + key, so consume the next 2
characters */
+ /* original function key value: ESC + key (2/3 bytes), so consume the
+next 2/3 characters */
case 0x1b:
key_value = (shell_getc() << 8) | shell_getc();
+ if (key_value == KEY_DELETE) {
+ (void)shell_getc(); /* delete key has one more byte */
+ }

switch (key_value) {
+ case KEY_DELETE:
+ handle_delete_key();
+ break;
case KEY_UP:
case KEY_DOWN:
handle_updown_key(key_value);
break;
+ case KEY_RIGHT:
+ if (p_shell->cursor_offset < p_shell->input_line_len) {
+ shell_puts(p_shell->buffered_line[p_shell-
input_line_active] + p_shell->cursor_offset);
+ p_shell->cursor_offset++;
+ set_cursor_pos(p_shell->input_line_len -
p_shell->cursor_offset);
+ }
+ break;
+ case KEY_LEFT:
+ if (p_shell->cursor_offset > 0) {
+ p_shell->cursor_offset--;
+ shell_puts("\b");
+ }
+ break;
+ case KEY_END:
+ if (p_shell->cursor_offset < p_shell->input_line_len) {
+ shell_puts(p_shell->buffered_line[p_shell-
input_line_active] + p_shell->cursor_offset);
+ p_shell->cursor_offset = p_shell-
input_line_len;
+ }
+ break;
+ case KEY_HOME:
+ if (p_shell->cursor_offset > 0) {
+ set_cursor_pos(p_shell->cursor_offset);
+ p_shell->cursor_offset = 0;
+ }
+ break;
default:
break;
}
@@ -358,6 +433,57 @@ static void shell_handle_special_char(char ch)
}
}

+static void handle_backspace_key(void)
+{
+ /* Ensure length is not 0 */
+ if (p_shell->cursor_offset > 0U) {
+ /* Echo backspace */
+ shell_puts("\b");
+ /* Send a space + backspace sequence to delete character */
+ shell_puts(" \b");
+
+ if (p_shell->cursor_offset < p_shell->input_line_len) {
+ uint32_t delta = p_shell->input_line_len - p_shell-
cursor_offset;
+
+ /* display the left input-chars and remove the former
last one */
+ shell_puts(p_shell->buffered_line[p_shell-
input_line_active] + p_shell->cursor_offset);
+ shell_puts(" \b");
+
+ set_cursor_pos(delta);
+ memcpy_erms(p_shell->buffered_line[p_shell-
input_line_active] + p_shell->cursor_offset - 1,
+ p_shell->buffered_line[p_shell-
input_line_active] + p_shell->cursor_offset, delta);
+ }
+
+ /* Null terminate the last character to erase it */
+
+p_shell->buffered_line[p_shell->input_line_active][p_shell->input_line_
+len - 1] = 0;
+
+ /* Reduce the length of the string by one */
+ p_shell->input_line_len--;
+ p_shell->cursor_offset--;
+ }
+}
+
+static void handle_input_char(char ch)
+{
+ uint32_t delta = p_shell->input_line_len - p_shell->cursor_offset;
+
+ /* move the input from cursor offset back first */
+ if (delta > 0) {
+ memcpy_erms_backwards(p_shell->buffered_line[p_shell-
input_line_active] + p_shell->input_line_len,
+ p_shell->buffered_line[p_shell->input_line_active] +
p_shell->input_line_len - 1, delta);
+ }
+
+
+p_shell->buffered_line[p_shell->input_line_active][p_shell->cursor_offs
+et] = ch;
+
+ /* Echo back the input */
+ shell_puts(p_shell->buffered_line[p_shell->input_line_active] + p_shell-
cursor_offset);
+ set_cursor_pos(delta);
+
+ /* Move to next character in string */
+ p_shell->input_line_len++;
+ p_shell->cursor_offset++;
+}
+
static bool shell_input_line(void)
{
bool done = false;
@@ -369,22 +495,7 @@ static bool shell_input_line(void)
switch (ch) {
/* Backspace */
case '\b':
- /* Ensure length is not 0 */
- if (p_shell->input_line_len > 0U) {
- /* Reduce the length of the string by one */
- p_shell->input_line_len--;
-
- /* Null terminate the last character to erase it */
- p_shell->buffered_line[p_shell-
input_line_active][p_shell->input_line_len] = 0;
-
- /* Echo backspace */
- shell_puts("\b");
-
- /* Send a space + backspace sequence to delete
- * character
- */
- shell_puts(" \b");
- }
+ handle_backspace_key();
break;

/* Carriage-return */
@@ -397,6 +508,7 @@ static bool shell_input_line(void)

/* Reset command length for next command processing */
p_shell->input_line_len = 0U;
+ p_shell->cursor_offset = 0U;
break;

/* Line feed */
@@ -410,14 +522,7 @@ static bool shell_input_line(void)
if (p_shell->input_line_len < SHELL_CMD_MAX_LEN) {
/* See if a "standard" prINTable ASCII character
received */
if ((ch >= 32) && (ch <= 126)) {
- /* Add character to string */
- p_shell->buffered_line[p_shell-
input_line_active][p_shell->input_line_len] = ch;
- /* Echo back the input */
- shell_puts(&p_shell->buffered_line[p_shell-
input_line_active]
- [p_shell->input_line_len]);
-
- /* Move to next character in string */
- p_shell->input_line_len++;
+ handle_input_char(ch);
} else {
/* call special character handler */
shell_handle_special_char(ch);
@@ -431,7 +536,7 @@ static bool shell_input_line(void)

/* Reset command length for next command
processing */
p_shell->input_line_len = 0U;
-
+ p_shell->cursor_offset = 0U;
}
break;
}
diff --git a/hypervisor/debug/shell_priv.h b/hypervisor/debug/shell_priv.h index
902802b98..45e88ed4c 100644
--- a/hypervisor/debug/shell_priv.h
+++ b/hypervisor/debug/shell_priv.h
@@ -36,6 +36,7 @@ struct shell {
int32_t input_line_active; /* Active input line index */

int32_t to_select_index; /* used for up/down key to select former
cmds */
+ uint32_t cursor_offset; /* cursor offset position from left input line
+*/

struct shell_cmd *cmds; /* cmds supported */
uint32_t cmd_count; /* Count of cmds supported */
diff --git a/hypervisor/include/lib/rtl.h b/hypervisor/include/lib/rtl.h index
b989b3da1..34695c58f 100644
--- a/hypervisor/include/lib/rtl.h
+++ b/hypervisor/include/lib/rtl.h
@@ -42,6 +42,8 @@ char *strchr(char *s_arg, char ch); size_t
strnlen_s(const char *str_arg, size_t maxlen_arg); void *memset(void *base,
uint8_t v, size_t n); int32_t memcpy_s(void *d, size_t dmax, const void *s,
size_t slen);
+void memcpy_erms(void *d, const void *s, size_t slen); void
+memcpy_erms_backwards(void *d, const void *s, size_t slen);
int64_t strtol_deci(const char *nptr);
uint64_t strtoul_hex(const char *nptr); char *strstr_s(const char *str1, size_t
maxlen1, const char *str2, size_t maxlen2);
--
2.25.1




Join {acrn-dev@lists.projectacrn.org to automatically receive all group messages.