[SeaBIOS] [PATCH 3/3] add serial console support

Kevin O'Connor kevin at koconnor.net
Tue Jul 5 16:30:41 CEST 2016


On Mon, Jul 04, 2016 at 10:39:54PM +0200, Gerd Hoffmann wrote:
> Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

Not sure if this is still an RFC.  I think it needs to have a Kconfig
option.  It should probably also have runtime enable option.

[...]
> --- a/Makefile
> +++ b/Makefile
> @@ -29,7 +29,7 @@ LD32BIT_FLAG:=-melf_i386
>  
>  # Source files
>  SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
> -    system.c serial.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
> +    system.c serial.c sercon.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \

How about console.c instead of sercon.c?

[...]
> --- /dev/null
> +++ b/src/sercon.c
> @@ -0,0 +1,545 @@

There should be a copyright statement.

[...]
> +VARLOW u8 sercon_char[8];
> +VARLOW u8 sercon_attr[8];

Out of curiosity, is 8 needed for effective "uncluttering" or is it an
optimization?  (That is, would a size of 1 suffice for the common
case?)

[...]
> +static void sercon_lazy_putchar(u8 chr, u8 attr, u8 teletype)
> +{
> +    u8 idx;
> +
> +    if (cursor_pos_row() != GET_LOW(sercon_row_last) ||
> +        cursor_pos_col() <  GET_LOW(sercon_col_last) ||
> +        cursor_pos_col() >= GET_LOW(sercon_col_last) + ARRAY_SIZE(sercon_char)) {
> +        sercon_lazy_flush();
> +    }
> +
> +    idx = cursor_pos_col() - GET_LOW(sercon_col_last);
> +    SET_LOW(sercon_char[idx], chr);
> +    if (teletype)
> +        cursor_pos_set(cursor_pos_row(),
> +                       cursor_pos_col()+1);

This doesn't handle end of column wrapping properly.

> +    else
> +        SET_LOW(sercon_attr[idx], attr);
> +}

FYI, once sercon_1013 is implemented then 'teletype' is not mutually
exclusive with 'use_attr'.

[...]
> +static void sercon_1000(struct bregs *regs)
> +{
> +    int mode, rows, cols;
> +
> +    mode = regs->al;
> +    switch (mode) {
> +    case 0x03:
> +    default:
> +        cols = 80;
> +        rows = 25;
> +        regs->al = 0x30;
> +    }
> +    SET_LOW(sercon_col_last, 0);
> +    SET_LOW(sercon_row_last, 0);
> +
> +    cursor_pos_set(0, 0);
> +    SET_BDA(video_mode, mode);
> +    SET_BDA(video_cols, cols);
> +    SET_BDA(video_rows, rows-1);
> +    SET_BDA(cursor_type, 0x0007);
> +
> +    sercon_term_reset();
> +    sercon_term_clear_screen();

Should only clear screen if high-bit of regs->al not set.

> +/* Set text-mode cursor shape */
> +static void sercon_1001(struct bregs *regs)
> +{
> +    /* dummy (add show/hide cursor?) */
> +}

Not sure if hiding the cursor is necessary, but it should
SET_BDA(cursor_type, regs->cx)

[...]
> +static void sercon_1003(struct bregs *regs)
> +{
> +    regs->ax = 0;
> +    regs->ch = 0;
> +    regs->cl = 7;

regs->cx = GET_BDA(cursor_type)

Not sure why regs->ax is cleared.

[...]
> +static void sercon_1009(struct bregs *regs)
> +{
> +    u16 count = regs->cx;
> +
> +    if (count == 1) {
> +        sercon_lazy_putchar(regs->al, regs->bl, 0);
> +
> +    } else if (regs->al == 0x20 &&
> +               video_rows() * video_cols() == count &&
> +               cursor_pos_row() == 0 &&
> +               cursor_pos_col() == 0) {
> +        /* override everything with spaces -> this is clear screen */
> +        sercon_lazy_flush();
> +        sercon_set_attr(regs->bl);
> +        sercon_term_clear_screen();
> +
> +    } else {
> +        sercon_lazy_flush();
> +        sercon_set_attr(regs->bl);
> +        while (count) {
> +            sercon_putchar(regs->al);

At a minimum that should be sercon_print_utf8(), though could
sercon_lazy_putchar() be used?

[...]
> +static void sercon_100e(struct bregs *regs)
> +{
> +    switch (regs->al) {
> +    case 7:
> +        // beep
> +        break;

sercon_putchar(0x07)

> +void VISIBLE16
> +sercon_10(struct bregs *regs)
> +{
> +    if (!GET_LOW(sercon_port))
> +        return;
> +
> +    switch (regs->ah) {
> +    case 0x00: sercon_1000(regs); break;
> +    case 0x01: sercon_1001(regs); break;
> +    case 0x02: sercon_1002(regs); break;
> +    case 0x03: sercon_1003(regs); break;
> +    case 0x06: sercon_1006(regs); break;
> +    case 0x08: sercon_1008(regs); break;
> +    case 0x09: sercon_1009(regs); break;
> +    case 0x0e: sercon_100e(regs); break;
> +    case 0x0f: sercon_100f(regs); break;
> +    case 0x4f: sercon_104f(regs); break;
> +    default:   sercon_10XX(regs); break;
> +    }
> +}

I noticed sercon_1007, sercon_100a, and sercon_1013 aren't
implemented.  I guess they aren't used frequently, but they've been
around since the original IBM MDA adapter.

[...]
> +void VISIBLE16
> +sercon_check_event(void)

Not sure VISIBLE16 is needed.

> +{
> +    u16 addr = GET_LOW(sercon_port);
> +    u16 keycode;
> +    u8 byte, count = 0;
> +    int seq, chr, len;
> +
> +    // check to see if there is a active serial port
> +    if (!addr)
> +        return;
> +    if (inb(addr + SEROFF_LSR) == 0xFF)
> +        return;
> +
> +    // flush pending output
> +    sercon_lazy_flush();
> +
> +    // read all available data
> +    while (inb(addr + SEROFF_LSR) & 0x01) {
> +        byte = inb(addr + SEROFF_DATA);
> +        if (GET_LOW(rx_bytes) < sizeof(rx_buf)) {
> +            SET_LOW(rx_buf[rx_bytes], byte);
> +            SET_LOW(rx_bytes, GET_LOW(rx_bytes) + 1);
> +            count++;
> +        }
> +    }
> +
> +next_char:
> +    // no (more) input data
> +    if (!GET_LOW(rx_bytes))
> +        return;
> +
> +    // lookup escape sequences
> +    if (GET_LOW(rx_bytes) > 1 && GET_LOW(rx_buf[0]) == 0x1b) {
> +        for (seq = 0; seq < ARRAY_SIZE(termseq); seq++) {
> +            len = GET_GLOBAL(termseq[seq].len);
> +            if (GET_LOW(rx_bytes) < len + 1)
> +                continue;
> +            for (chr = 0; chr < len; chr++) {
> +                if (GET_GLOBAL(termseq[seq].seq[chr]) != GET_LOW(rx_buf[chr + 1]))
> +                    break;
> +            }
> +            if (chr == len) {
> +                enqueue_key(GET_GLOBAL(termseq[seq].keycode));
> +                shiftbuf(len + 1);
> +                goto next_char;
> +            }
> +        }
> +    }
> +
> +    // Seems we got a escape sequence we didn't recognise.
> +    //  -> If we received data wait for more, maybe it is just incomplete.
> +    if (GET_LOW(rx_buf[0]) == 0x1b && count)
> +        return;
> +
> +    // Handle input as individual chars.
> +    chr = GET_LOW(rx_buf[0]);
> +    keycode = ascii_to_keycode(chr);
> +    if (keycode)
> +        enqueue_key(keycode);
> +    shiftbuf(1);
> +    goto next_char;
> +}

I would prefer if we could avoid backwards gotos.

In general, looks good.
-Kevin



More information about the SeaBIOS mailing list