OSDev.org

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

All times are UTC - 6 hours




Post new topic Reply to topic  [ 2 posts ] 
Author Message
 Post subject: Keyboard
PostPosted: Fri May 19, 2017 4:52 pm 
Offline

Joined: Fri May 19, 2017 4:24 pm
Posts: 1
When I press a key, only the letter should be printed on the display, but instead the OS adds extra characters to the letter(in picture). What is the problem? I think it probably is in the on_key() function.
My code is provided down below:

Code:

asm("jmp kmain");
#define VIDEO_BUF_PTR (0xb8000)
#define IDT_TYPE_INTR (0x0E)
#define IDT_TYPE_TRAP (0x0F)
#define GDT_CS (0x8)
#define PIC1_PORT (0x20)
#define CURSOR_PORT (0x3D4)
#define VIDEO_WIDTH (80)

unsigned char keyboard[128] =
{
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */
'9', '0', '-', '=', '\b', /* Backspace */
'\t', /* Tab */
'q', 'w', 'e', 'r', /* 19 */
't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */
0, /* 29 - Control */
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */
'\'', '`', 0, /* Left shift */
'\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */
'm', ',', '.', '/', 0, /* Right shift */
'*',
0, /* Alt */
' ', /* Space bar */
1, /* Caps lock */
0, /* 59 - F1 key ... > */
0, 0, 0, 0, 0, 0, 0, 0,
0, /* < ... F10 */ /*68*/
0, /* 69 - Num lock*/
0, /* Scroll Lock */
'7', '8', '9', '-', '4', '5', '6', '+', /*78*/
'1', /* 79 - End key*/
'2', /* Down Arrow */
'3', /* Page Down */
'0', /* Insert Key */
0, /* Delete Key */
0, 0, 0,
0, /* F11 Key */
0, /* F12 Key */
0, /* All other keys are undefined */
};

struct idt_entry
{
   unsigned short base_lo;
   unsigned short segm_sel;
   unsigned char always0;
   unsigned char flags;
   unsigned short base_hi;
} __attribute__((packed));

struct idt_ptr
{
   unsigned short limit;
   unsigned int base;
} __attribute__((packed));

struct idt_entry g_idt[256];
struct idt_ptr g_idtp;

void default_intr_handler()
{
   asm("pusha");
   asm("popa; leave; iret");
}

typedef void (*intr_handler)();
void intr_reg_handler(int num, unsigned short segm_sel, unsigned short flags, intr_handler hndlr)
{
   unsigned int hndlr_addr = (unsigned int) hndlr;
   g_idt[num].base_lo = (unsigned short) (hndlr_addr & 0xFFFF);
   g_idt[num].segm_sel = segm_sel;
   g_idt[num].always0 = 0;
   g_idt[num].flags = flags;
   g_idt[num].base_hi = (unsigned short) (hndlr_addr >> 16);
}

void intr_init()
{
   int i;
   int idt_count = sizeof(g_idt) / sizeof(g_idt[0]);
   for(i = 0; i < idt_count; i++)
      intr_reg_handler(i, GDT_CS, 0x80 | IDT_TYPE_INTR, default_intr_handler);
}

void intr_start()
{
   int idt_count = sizeof(g_idt) / sizeof(g_idt[0]);
   g_idtp.base = (unsigned int) (&g_idt[0]);
   g_idtp.limit = (sizeof (struct idt_entry) * idt_count) - 1;
   asm("lidt %0" : : "m" (g_idtp) );
}

void intr_enable()
{
   asm("sti");
}

void intr_disable()
{
   asm("cli");
}

static inline unsigned char inb (unsigned short port)
{
   unsigned char data;
   asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port));
   return data;
}

static inline void outb (unsigned short port, unsigned char data)
{
   asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port));
}

void out_str(int color, const char* ptr, unsigned int strnum)
{
   unsigned char* video_buf = (unsigned char*) VIDEO_BUF_PTR;
   video_buf += 80*2 * strnum;
   while (*ptr)
   {
      video_buf[0] = (unsigned char) *ptr; // Символ (код)
      video_buf[1] = color; // Цвет символа и фона
      video_buf += 2;
      ptr++;
   }
}

void cursor_moveto(unsigned int strnum, unsigned int pos)
{
   unsigned short new_pos = (strnum * VIDEO_WIDTH) + pos;
   outb(CURSOR_PORT, 0x0F);
   outb(CURSOR_PORT + 1, (unsigned char)(new_pos & 0xFF));
   outb(CURSOR_PORT, 0x0E);
   outb(CURSOR_PORT + 1, (unsigned char)( (new_pos >> 8) & 0xFF));
}


char scan_to_char(unsigned char s)
{
   
   if(keyboard[s] == 0) return '\t';
   return (keyboard[s]);
}


int g_caret = 0;

void clear_str()
{
   char* vb = (char*) VIDEO_BUF_PTR;
   int i;
   for (i = 0; i<80; i++)
   {
      vb[i*2]=' ';
      vb[i*2+1] = 0x0A;
   }
   cursor_moveto(0,0);   
}

char onscreenchar(const unsigned char ch)
{
   return keyboard[ch];
}

void on_key(unsigned char scan_code)
{
   
   unsigned char c;
   c = scan_to_char(scan_code);
   char* vb = (char*) VIDEO_BUF_PTR;
   if (c != '\t'){
      vb[g_caret*2] = c;
      vb[g_caret*2+1] = 0x07;
      //g_caret = g_caret + 2;
      g_caret++;
      cursor_moveto(0, g_caret);
   }
   
   
}

void keyb_process_keys()
{
   if (inb(0x64) & 0x01)
   {
      unsigned char scan_code;
      unsigned char state;
      scan_code = inb(0x60);
      if (scan_code < 128);
         on_key(scan_code);
   }
}

void keyb_handler()
{
   asm("pusha");
   keyb_process_keys();
   outb(PIC1_PORT, 0x20);
   asm("popa; leave; iret");
}

void keyb_init()
{
   intr_reg_handler(0x09, GDT_CS, 0x80 | IDT_TYPE_INTR, keyb_handler);
   outb(PIC1_PORT + 1, 0xFF ^ 0x02);
}

void videomode()
{
   asm("movb $0x00, %ah");
   asm("movb $0x03, %al");
   asm("int $0x10");
   asm("ret");

}
void shutdown()
{   
   asm("movw $0x0604, %dx");
   asm("movw $0x2000, %ax");
   asm("outw %ax, %dx");    
}

int gcd(int a, int b){
   return b == 0 ? a : gcd(b, a % b);
}

int solve(int a, int b, int c){
   return 0;
}

int lcm(int a, int b){
   int max;
   max = (a > b) ? a : b;
   do
   {
      if (max % a == 0 && max % b == 0)
      {
         char maxch = (char)max;
         out_str(0x02, &maxch, 24); //Must be changed!
         //cout << "LCM = " << max;
         break;
      }
      else
         ++max;
   } while (true);
   return 0;
}


const char* second_str = "Compilers: bootloader: gas, kernel: gcc";
const char* third_str = "entered color";
const char* gcd_str = "gcd";
const char* solve_str = "solve";
const char* lcm_str = "lcm";
const char* shutdown_str = "shutdown";
const char* info_str = "info";


extern "C" int kmain()
{
   const char* hello = "Welcome to SolverOS!";
   out_str(0x01, hello, 20);
   
   
   out_str(0x03, second_str, 22);
   out_str(0x04, third_str, 23);
   
   intr_init();
   keyb_init();
   intr_start();
   intr_enable();

   //intr_disable();


   while(1)
   {
      asm("hlt");
   }
   return 0;
}


Attachments:
KpQvdabrVgk.jpg
KpQvdabrVgk.jpg [ 39.71 KiB | Viewed 1675 times ]
Top
 Profile  
 
 Post subject: Re: Keyboard
PostPosted: Fri May 19, 2017 7:11 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
At first glance, in your code you have:
Code:
      if (scan_code < 128);
         on_key(scan_code);

I don't think you intended to put a semicolon ; on the end of the if statement. There may be other issues as well but thought I'd point this out.

You say you are using GCC but the extern "C" usage suggests you are using g++ ?

I have a concern about this:
Code:
void keyb_handler()
{
   asm("pusha");
   keyb_process_keys();
   outb(PIC1_PORT, 0x20);
   asm("popa; leave; iret");
}

This code assumes that there will be a stack frame generated, and even worse that stack frame will likely by default alter EBP before reaching PUSHA meaning that it is possible registers have been clobbered before saving them. If you are using GCC 7.1 or above the interrupt attribute on functions is no longer ignored for x86 targets. It is now documented in GCC this way:
Quote:
Interrupt

Use this attribute to indicate that the specified function is an interrupt handler or an exception handler (depending on parameters passed to the function, explained further). The compiler generates function entry and exit sequences suitable for use in an interrupt handler when this attribute is present. The IRET instruction, instead of the RET instruction, is used to return from interrupt handlers. All registers, except for the EFLAGS register which is restored by the IRET instruction, are preserved by the compiler. Since GCC doesn’t preserve MPX, SSE, MMX nor x87 states, the GCC option -mgeneral-regs-only should be used to compile interrupt and exception handlers
.
Your other options are to create a stub (keyb_handler)in a separate assembly file that calls the keyb_process_keys in the C code. You can also do this with a basic ASM block outside of a function:
Code:
extern "C" void keyb_handler(void);
extern "C" void keyb_process_keys(void);
extern "C" void default_intr_handler(void);

__asm__(".global default_intr_handler\n"
        "default_intr_handler:\n\t"
        "iret");

/* Define a keyboard handler stub that makes a call to a C function */
__asm__(".global keyb_handler\n"
        "keyb_handler:\n\t"
        "cld\n\t"                    /* Set direction flag forward for C functions */
        "pusha\n\t"                  /* Save all the registers */
        "call keyb_process_keys\n\t"
        "popa\n\t"                   /* Restore all the registers */
        "iret");

Alter keyb_process_keys to be:
Code:
void keyb_process_keys()
{
   if (inb(0x64) & 0x01)
   {
      unsigned char scan_code;
      unsigned char state;
      scan_code = inb(0x60);
      if (scan_code < 128)
         on_key(scan_code);
   }
   outb(PIC1_PORT, 0x20);
}

The other assumption is that you have properly generated a GDT (and loaded it) prior to calling kmain. You don't show us the rest of your code so it is hard to judge if there is a problem outside the concerns above. There may be other bugs in your bootloader and there is an indication in this code that you are not using a mulitboot loader (or something like it) and have coded your own bootloader to bootstrap you into the C code.


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot], Octocontrabass and 99 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