Unexpexted behavior from bochs
Unexpexted behavior from bochs
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?
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?
Re: Unexpexted behavior from bochs
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.
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.
Re: Unexpexted behavior from bochs
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.
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
http://users.atw.hu/gerigeri/DawnOS/download.html
- Schol-R-LEA
- Member
- Posts: 1925
- Joined: Fri Oct 27, 2006 9:42 am
- Location: Athens, GA, USA
Re: Unexpexted behavior from bochs
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.
@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.
Last edited by Schol-R-LEA on Wed May 10, 2017 12:10 pm, edited 1 time in total.
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.
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.
Re: Unexpexted behavior from bochs
Something that comes to my mind on this is repeat rate.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?
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
Re: Unexpexted behavior from bochs
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.
- Schol-R-LEA
- Member
- Posts: 1925
- Joined: Fri Oct 27, 2006 9:42 am
- Location: Athens, GA, USA
Re: Unexpexted behavior from bochs
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?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.
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.
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.
Re: Unexpexted behavior from bochs
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:
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
BenLunt:
i was thinking something similar do you know how to "set the repeat rate in bochs"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 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
Re: Unexpexted behavior from bochs
actually lemme post the code.There are only three files right now so its not to cumbersome
boot.s
linker.ld
kernel.c
boot.s
Code: Select all
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
Code: Select all
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)
}
}
Code: Select all
#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();
}
Re: Unexpexted behavior from bochs
Hi,
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
The other thing I'd consider is what Bochs is using to communicate with the host.BenLunt wrote:Something that comes to my mind on this is repeat rate.dethboy wrote:Bochs however is sending the make scancode and the release scan code repeatedly.
Either you have set the repeat rate in bochs or actually programmed the (emulated) keyboard's repeat rate so that it produces this result.
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.
Re: Unexpexted behavior from bochs
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)..
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)..
Re: Unexpexted behavior from bochs
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
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