OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 9:46 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 12 posts ] 
Author Message
 Post subject: Unexpexted behavior from bochs
PostPosted: Tue May 09, 2017 8:44 am 
Offline

Joined: Tue May 09, 2017 8:27 am
Posts: 14
I am in the middle of writing a keyboard driver but i am experiencing some weird behavior from bochs.

On qemu when i press and hold a key i receive repeated interrupts with the make scancode, e.g for the "a" key i get:

0x1E 0x1E 0x1E 0x1E 0x1E ... and 0x9E when i release the key

Bochs however is sending the make scancode and the release scan code repeatedly. for example with the "a" key:

0x1E 0x9E 0x1E 0x9E 0x1E 0x9E 0x1E 0x9E ...

I am assuming from what i have read that qemu is displaying the expected behavior, if i am wrong please correct me.

Anybody have an explanation for the different results in the different emulators and a possible way to correct it?


Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Tue May 09, 2017 8:53 am 
Offline
Member
Member

Joined: Tue May 13, 2014 3:02 am
Posts: 280
Location: Private, UK
I wouldn't be at all surprised if both these behaviors were accurate to real hardware, depending on the model of keyboard in use.

PS/2 controllers and keyboards are one of those things that, while they've been around for ages and are pretty well documented, have a large amount of "edge cases" and differing behaviour. Even real hardware (even original IBM hardware) has different behaviour in some circumstances.

I know for a fact that different emulation/virtualization platforms have definite bugs (e.g. QEMU always reports the keyboard scanset as a "translated" value, even when translation is off) and other oddities (I've given up making my OS work with VMWare for now because its PS/2 emulation is very "awkward").

I'd recommend that you make your OS/keyboard driver work with both of these. It's pretty simple to "synthesise" key-up events when you're presented with "duplicate" key-down events.

_________________
Image


Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Tue May 09, 2017 9:06 am 
Offline
Member
Member
User avatar

Joined: Sun Jul 14, 2013 6:01 pm
Posts: 442
release should only aired when they key is released.

however there could be buggy bioses, so your code must somewhat usably work in both situtation.

_________________
Operating system for SUBLEQ cpu architecture:
http://users.atw.hu/gerigeri/DawnOS/download.html


Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Wed May 10, 2017 9:30 am 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
Can anyone else replicate this in Bochs? I may have time today to test it, but I can't promise that.

@dethboy: if you could post your keyboard code - or better yet, a link to a public repo with the code* - it would give us a better idea of what is actually happening.

* If you don't have your code under VCS (it could be git, Subversion, mercurial, bazaar, whatever, just as long as you are using one) and on an offsite VCS host like Github already, I recommend that you drop everything and set that up right now - you really, really want this, trust me. Nothing ruins your day like accidentally trashing your top-level code base, and everybody trashes their code base at least once in a while no matter how careful they are.

Idle speculation time: It almost sounds as if Bochs is trying to simulate key bounce, but that doesn't really make sense; first off, in the case of key bounce, you would expect the sequence to be more like

0x1E 0x1E 0x1E 0x1E 0x1E 0x9E 0x1E 0x9E 0x1E 0x9E

with the bounce effect settling down around the third repetition.

More crucially, I am quite sure that all PC keyboard implementations de-bounce the key signals in hardware - a trivial matter which can often be done just by placing a capacitor across the input line - before the scan code is even generated. No key on a modern keyboard should ever give a bounce that the PC itself could see, so simulating it would make absolutely no sense.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Last edited by Schol-R-LEA on Wed May 10, 2017 12:10 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Wed May 10, 2017 12:08 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
dethboy wrote:
I am in the middle of writing a keyboard driver but i am experiencing some weird behavior from bochs.

On qemu when i press and hold a key i receive repeated interrupts with the make scancode, e.g for the "a" key i get:

0x1E 0x1E 0x1E 0x1E 0x1E ... and 0x9E when i release the key

Bochs however is sending the make scancode and the release scan code repeatedly. for example with the "a" key:

0x1E 0x9E 0x1E 0x9E 0x1E 0x9E 0x1E 0x9E ...

I am assuming from what i have read that qemu is displaying the expected behavior, if i am wrong please correct me.

Anybody have an explanation for the different results in the different emulators and a possible way to correct it?

Something that comes to my mind on this is repeat rate.

Either you have set the repeat rate in bochs or actually programmed the (emulated) keyboard's repeat rate so that it produces this result.

Just a thought, it could be nothing.

Ben
http://www.fysnet.net/input_and_output_devices.htm


Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Wed May 10, 2017 1:04 pm 
Offline
Member
Member

Joined: Sat Nov 21, 2009 5:11 pm
Posts: 852
Bochs is simply wrong here. There is nothing to be done about it, so just leave it be. Do not synthesize key up events to try to match Bochs' behaviour.


Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Wed May 10, 2017 1:19 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
Gigasoft wrote:
Bochs is simply wrong here. There is nothing to be done about it, so just leave it be. Do not synthesize key up events to try to match Bochs' behaviour.

Unless this is a known flaw in Bochs (which I have not taken the time to check), wouldn't it be premature to say this until the OP has had a chance to reply to Ben and post their code?

If it is a known flaw, please give what detail on it you can, and if it isn't mentioned in the Wiki, it needs to be added as a note about the current implementation of Bochs and how it affects testing.

I need to go through the archive and other resources on this. It sounds like you have a particular previous discussion in mind.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Wed May 10, 2017 1:37 pm 
Offline

Joined: Tue May 09, 2017 8:27 am
Posts: 14
Schol-R-LEA: Posting code would be a good idea, right now it's in a bit of disarray with test code all about. Also, i sort of like banging my head against it til if figure it out. I was really looking for if anyone knew if there was some sort of emulator configuration i was missing.

BenLunt:
BenLunt wrote:
Something that comes to my mind on this is repeat rate.

Either you have set the repeat rate in bochs or actually programmed the (emulated) keyboard's repeat rate so that it produces this result.


i was thinking something similar do you know how to "set the repeat rate in bochs"

i was thinking i should send configuration commands to the keyboard but i was getting no ACKs (because i didn't know what i was doing) and i felt i should remedy that

also there sometimes is a left over keyup from pressing the enter key on the grub menu that seems to be gumming up the works some


Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Wed May 10, 2017 1:54 pm 
Offline

Joined: Tue May 09, 2017 8:27 am
Posts: 14
actually lemme post the code.There are only three files right now so its not to cumbersome

boot.s
Code:
kb_int:
    pusha

    #movw $0x0f74, (0xb8000)
    #movw $0x0f65, (0xb8002)
    #movw $0x0f73, (0xb8004)
    #movw $0x0f74, (0xb8006)
    #for some reason causing a reboot when not using grub
    #breakpont
    #xchgw %bx, %bx 158
    in $0x60, %al
    nop
   
   
   

    mov %al, (scancode)
    cmp $0x9E, %al
    mov (ticks), %ebx
    jne store_sc
    sub (last_keypress), %ebx   #normal keypress takes 3 or 4, initial repeat is B subsequent 0
    #xchgw %bx, %bx
    #movw $0x0f58, (0xb8000)
store_sc:
    movl %ebx, (last_keypress)
    mov $0x20, %al
    out %al, $0x20
    call keypress

    popa
    iret
clock_int:
    incl (ticks)
    #xchgw %bx, %bx
    mov $0x20, %al
    out %al, $0x20
    iret
dummy_exc:
    movw $0x0f46, (0xb8006)
    cli
    hlt

dummy_int:
    #pusha
    #add $0x0f00, %eax
    movw $0x0f21, (0xb8006)
    mov $0x20, %al
    out %al, $0x20
    #popa
    iret

.size _start, . - _start

.section .data
msg:
    .string "message 1\n"
msg2:
    .string "Leftover data found in keyboard buffer, disposing\n"
idt_info:
    .word 0x800 - 1
    .int  0x0
ticks:
    .int 0x0 #supplies 4,294,967,295 or apx 2761 days of uptime, good enough for now
last_keypress:
    .int 0x0


linker.ld
Code:
ENTRY(_start)

SECTIONS {
    /* Load the kernel at 1Mib, seems customary, why? */
   
    /* this moves the pointer */
    . = 1M;

    .text BLOCK(4K) : ALIGN(4K) {
        *(.multiboot)
        *(.text)
    }

    .rodata BLOCK(4K) : ALIGN(4K) {
        *(.rodata)
    }

    .data BLOCK(4K) : ALIGN(4K) {
        *(.data)
    }

    .bss BLOCK(4K) : ALIGN(4K) {
        *(COMMON)
        *(.bss)
    }
}


kernel.c
Code:
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#if defined(__linux__)
#error "you are not using the cross compiler"
#endif

#if !defined(__i386__)
#error "this needs to be compiles with an i686-elf compiler"
#endif

enum vga_color {
    VGA_COLOR_BLACK = 0,
    VGA_COLOR_BLUE = 1,
    VGA_COLOR_GREEN = 2,
    VGA_COLOR_CYAN = 3,
    VGA_COLOR_RED = 4,
    VGA_COLOR_MAGENTA = 5,
    VGA_COLOR_BROWN = 6,
    VGA_COLOR_LIGHT_GREY = 7,
    VGA_COLOR_DARK_GREY = 8,
    VGA_COLOR_LIGHT_BLUE = 9,
    VGA_COLOR_LIGHT_GREEN = 10,
    VGA_COLOR_LIGHT_CYAN = 11,
    VGA_COLOR_LIGHT_RED = 12,
    VGA_COLOR_LIGHT_MAGENTA = 13,
    VGA_COLOR_LIGHT_BROWN = 14,
    VGA_COLOR_WHITE = 15,
};

static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
    return fg | bg << 4;
}

static inline uint16_t vga_entry(unsigned char uc, uint8_t color) {
    return (uint16_t) uc | (uint16_t) color << 8;
}

size_t strlen(const char* str) {
    size_t len = 0;
    while(str[len]) {
        len++;
    }
    return len;
}

static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 26;

size_t terminal_row;
size_t terminal_column;
uint8_t terminal_color;
uint16_t* terminal_buffer;

uint16_t* columns;
uint8_t* video_ram;

void terminal_initialize(void) {
    terminal_row = 0;
    terminal_column = 0;
    terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
    terminal_buffer = (uint16_t*) 0xb8000;
   
    columns = (uint16_t*) 0x044A;
   
    for (size_t y = 0; y < VGA_HEIGHT; y++) {
        for (size_t x = 0; x < VGA_WIDTH; x++) {
            const size_t index = (y * VGA_WIDTH) + x;
            terminal_buffer[index] = vga_entry(' ', terminal_color);
        }
    }
}

void terminal_setcolor(uint8_t color) {
    terminal_color = color;
}

void terminal_putentryat(char c, uint8_t color, size_t x, size_t y) {
    const size_t index = y * VGA_WIDTH + x;
    terminal_buffer[index] = vga_entry(c, color);
}

void terminal_scroll(void) {
    // no buffer needed
    terminal_row = 0;
    terminal_column = 0;
    for (size_t y = 0; y < VGA_HEIGHT; y++) {
        for (size_t x = 0; x < VGA_WIDTH; x++) {
            const size_t index = (y * VGA_WIDTH) + x;
            if (y < VGA_HEIGHT - 1) {
               terminal_buffer[index] =  terminal_buffer[index + VGA_WIDTH];
            } else {
                terminal_buffer[index] = vga_entry(' ', terminal_color);
            }
        }
    }
    terminal_row = VGA_HEIGHT - 1;
    terminal_column = 0;
}

void terminal_putchar(char c) {
    if (c == '\n') {
        // what about \r
        terminal_column = VGA_WIDTH - 1;
    } else {
        terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
    }
    if (++terminal_column == VGA_WIDTH) {
        terminal_column = 0;
        if (++terminal_row == VGA_HEIGHT) {
            terminal_scroll();
        }
    }
   
}

void terminal_write(const char* data, size_t size) {
    for (size_t i = 0; i < size; i++) {
        terminal_putchar(data[i]);
    }
}

void terminal_writestring(const char* data) {
    terminal_write(data, strlen(data));
}

char* int_to_string(int number) {
    char* tmp = NULL;
   
    int count = 0;
    while (number > 0) {
        int remain = number % 10;
        tmp[count] = remain + 48;

        number = (number - remain) / 10;
        count++;
    }
    char* retvalue = tmp + count;

    for (int newcount = 0; newcount < count; newcount++) {

        retvalue[newcount] = tmp[count - (newcount + 1)];
    }
    retvalue[count] = '\0';
    return retvalue;
}

static inline uint8_t inb(uint16_t port) {
    uint8_t ret;
    asm volatile ("inb %1, %0" : "=a"(ret): "Nd" (port));
    return ret;       
}

static inline void outb(uint16_t port, uint8_t val) {
    asm volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
}

static inline void io_wait(void) {
    asm volatile ( "jmp 1f\n\t"
                   "1:jmp 2f\n\t"
                   "2:" );
}

char getScancode() {
    char c = 0;
    do {
        if (inb(0x60) != c) {
            c = inb(0x60);
            if (c > 0) {
                return c;
            }
        }
    } while (1);
}

void update_cursor(void) {
    unsigned short pos = (terminal_row * VGA_WIDTH) + terminal_column;
    outb(0x3d4, 0x0f);
    outb(0x3D5, (unsigned char)(pos & 0xFF));
    outb(0x3D4, 0x0E);
    outb(0x3D5, (unsigned char )((pos >> 8) & 0xFF));
}
uint8_t scancode = 0x00;

uint8_t km_no_keys[256] = {
    0x0,
    0x0 /*escape*/, '1', '2', '3', '4', '5', '6', '7' , '8', '9', '0', '-', '=', 0x0, /*backspace*/
    0x0 /*tab*/, 'q', 'w', 'e', 'r', 't', 'y', 'u' , 'i', 'o', 'p', '[', ']', '\n', /*enter*/
    0x0 /*l-ctl*/, 'a', 's', 'd', 'f', 'g', 'h', 'j' , 'k', 'l', ';', '\'', '`',
    0x0 /*l-shift*/, '\\', 'z', 'x', 'c', 'v', 'b', 'n' , 'm', ',', '.', '/', 0x0, /*r-shift*/
    '*' /*keypad-multiply*/, 0x0 /*l-alt*/, ' ', 0x0 /*caps-lock*/, 'c', 'v', 'b', 'n' , 'm', ',', '.', '/', 0x0, /*r-shift*/
   
};
uint8_t *keymaps[1] = {km_no_keys};

void keypress(void) {

    uint8_t keyboard_state = 0x00;


    uint8_t old_col = terminal_column;
    uint8_t old_row = terminal_row;
   
    terminal_row = (size_t) 20;
    if (scancode < 0x80) {
        terminal_column = (size_t) 1;
    } else {
        terminal_column = (size_t) 5;
    }
   
    char *thesc = int_to_string(scancode);
    if (strlen(thesc) == 2) {
        terminal_putchar('0');
    }
    terminal_writestring(thesc);
    if (scancode < 0x80) {
        terminal_writestring("    ");;
    }
    terminal_row = old_row;
    terminal_column = old_col;
   
 
    if (scancode < 0x80) {
        switch (scancode) {
            case 0x01: //escape
                break;
            case 0x0E: //backspace
                break;
            case 0x0F: //tab
                break;
            //case 0x1c: //enter
                //break;
            case 0x1d: //left ctl
                break;
            case 0x2a: //left shift
                break;
            case 0x36: //right shift
                break;
            case 0x38: //left alt
                break;
            case 0x3A: //caps lock
                break;
            //default:
                //terminal_putchar(keymaps[keyboard_state][scancode]);
                //update_cursor();
        }
       
    }
   
   
    terminal_writestring(int_to_string(scancode));
    terminal_putchar(' ');

}


void ps2_wait_write() {
    while((inb(0x64) & 2) != 0) {
        // do nothing
    }
}

void ps2_wait_read() {
    while((inb(0x64) & 1) == 0) {
        // do nothing
        // geting no response on till a keypress
    }
}

void byte_to_bin_string(uint8_t data) {
    for (int x = 0; x < 8; x++) {
        if (((data >> x) & 1) == 0) {
            terminal_putchar('0');
        } else {
            terminal_putchar('1');
        }
    }
}

unsigned char ps2_send(unsigned char data) {
    terminal_writestring("waiting for write\n");
   
    ps2_wait_write();
   
    terminal_writestring("writing\n");
   
    outb(0x64, data);
   
    terminal_writestring("waiting for read\n");
    terminal_writestring("current keyboard status: ");
    terminal_writestring(int_to_string((int)inb(0x64)));
    terminal_putchar('\n');
   
    ps2_wait_read();
   
    terminal_writestring("returning\n");
    return inb(0x60);
}

void kernel_main(void) {

   
    terminal_writestring("Welcome to TestOS\n");
    terminal_writestring("this is a second string\n");
    terminal_putchar('\n');

    update_cursor();
   
}



Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Wed May 10, 2017 11:27 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

BenLunt wrote:
dethboy wrote:
Bochs however is sending the make scancode and the release scan code repeatedly.

Something that comes to my mind on this is repeat rate.

Either you have set the repeat rate in bochs or actually programmed the (emulated) keyboard's repeat rate so that it produces this result.


The other thing I'd consider is what Bochs is using to communicate with the host.

For Bochs there's multiple options (x, win32, carbon, sdl, sdl2, SVGAlib, term/ncurses, wxWidgets, ...) and for some of these options it's impossible for Bochs to receive "key released events" from the host and therefore impossible for Bochs to emulate key repeat properly.


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Thu May 11, 2017 4:39 am 
Offline
Member
Member

Joined: Thu Aug 13, 2015 4:57 pm
Posts: 384
Like Brendan said it's quite possible it's caused by a higher level "translation". I often use SSH and run Qemu under that, haven't actually tested how it affects keyboard events though. However I'm guessing SSH only transmits characters and not keyup/keydown, which means Qemu (or Bochs in OP's case) would only receive characters where the correct action would be to generate emulated keyup/keydown events based on each character, which means it's the repeat rate on the host (or the SSH app) system where SSH client is sitting since it's sending those characters over.

Interestingly this is part of the problem of legacy, these translations reduce information and thus can only be done in one way and these days people use pretty complex setups and then there's interesting issues. I for one use dual virtualization (Windows runs VMWare, under which is Linux under which I run Qemu to test my OS)..


Top
 Profile  
 
 Post subject: Re: Unexpexted behavior from bochs
PostPosted: Thu May 11, 2017 8:15 am 
Offline

Joined: Tue May 09, 2017 8:27 am
Posts: 14
Brendan, thanks!

it turns out that the behavior is caused by using the x display library, when i switched to SDL it switched to sending multiple make scancodes and only sends the release when the key is actually released


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Majestic-12 [Bot], SemrushBot [Bot] and 61 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group