OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Apr 25, 2024 2:22 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: Command-line interface
PostPosted: Sun Aug 22, 2004 3:53 am 
Hello,
I am currently programming a mini CLI but I have some problems.
It is supposed to take a key from the keyboard, print it to screen and add it to the 'command buffer'.
When the enter key is pressed, this buffer is printed to screen.

This is my code:
Code:
    xor edi,edi
Shell:
    sti
    hlt

    int 33    ;keyboard interrupt

    cmp al,13
    je EnterKeyPressed

;print the keyboard input

    mov [CmdBuf+di],al
    inc di

    jmp Shell

EnterKeyPressed:

;print 'CmdBuf' to the screen

    xor edi,edi
    jmp Shell

CmdBuf times 10 db 90h
       db 13,0


When I press the enter key, it prints the 'CmdBuf' string as it is (10 NOPs) which means the two code lines 7 and 8 didn't work properly. What could be wrong with these two lines?
PS: the same code is working correctly in my 16bit real-mode OS.

Thanks for any help.


Top
  
 
 Post subject: Re:Command-line interface
PostPosted: Sun Aug 22, 2004 4:16 am 
Offline
Member
Member
User avatar

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

The code posted all looks ok to me, so I'd guess that the base of DS is causing trouble, or "int 33" is trashing EDI.

On another note, what happens if the user types 100 characters before pressing enter?


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:Command-line interface
PostPosted: Sun Aug 22, 2004 4:27 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 2:31 am
Posts: 5964
Location: In a galaxy, far, far away
so, you halt for interrupts and when an interrupt occured, you call int 0x21 to get data, right ...

Oh, i hope that '0x21' is *not* your IRQ1 and that you're not trying to call an IRQ handler from software. That'd lead to ugly results (such as having the handler called twice, interrseting data lost, etc).

_________________
Image May the source be with you.


Top
 Profile  
 
 Post subject: Re:Command-line interface
PostPosted: Sun Aug 22, 2004 4:46 am 
Offline
Member
Member
User avatar

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

Pype.Clicker wrote:
Oh, i hope that '0x21' is *not* your IRQ1 and that you're not trying to call an IRQ handler from software. That'd lead to ugly results (such as having the handler called twice, interrseting data lost, etc).


I assumed "int 33" was a replacement for the real mode BIOS "int 0x16, ah =0", that the keyboard IRQ (handled via a different interrupt) is the only IRQ enabled, and that the OS is single-tasking. There'd be major problems if any of these assumptions aren't correct.

Even if all these assumptions are wrong there must be something in AL when it returns from "int 33", which should end up in CmdBuf (unless "int 33" is returning 0x90 I guess).


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:Command-line interface
PostPosted: Sun Aug 22, 2004 11:55 am 
Hello,

Brendan,
Quote:
The code posted all looks ok to me, so I'd guess that the base of DS is causing trouble, or "int 33" is trashing EDI.

- ds = 10h.
- int 33 (which is the keyboard IRQ) doesn't use edi at all.

Quote:
On another note, what happens if the user types 100 characters before pressing enter?

Nothing special. What is it supposed to do?

Quote:
Even if all these assumptions are wrong there must be something in AL when it returns from "int 33", which should end up in CmdBuf (unless "int 33" is returning 0x90 I guess).

There is something in al, int33 returns the ASCII value of the pressed key and it is correctly printed by the code I posted before but it doesn't end up in the buffer.


Pype.Clicker,
Quote:
so, you halt for interrupts and when an interrupt occured, you call int 0x21 to get data, right ...

Exactly.

Quote:
Oh, i hope that '0x21' is *not* your IRQ1 and that you're not trying to call an IRQ handler from software. That'd lead to ugly results (such as having the handler called twice, interrseting data lost, etc).

Yes, that's what it does. So, if I don't want it to do that, what should I do?
My keyboard IRQ takes the user input, translates it to ASCII code (taking care of locks, shifts, alts and ctrls) and puts it in al.
I thought I could have an int48 that will have a function that does the following:
Code:
getkey:
    int 21h
    ret

But this didn't change anything, the buffer is still not filled properly.
What should I do other than that?

Thanks for any help.


Top
  
 
 Post subject: Re:Command-line interface
PostPosted: Mon Aug 23, 2004 12:22 am 
Offline
Member
Member
User avatar

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

ManOfSteel wrote:
Quote:
The code posted all looks ok to me, so I'd guess that the base of DS is causing trouble, or "int 33" is trashing EDI.

- ds = 10h.
- int 33 (which is the keyboard IRQ) doesn't use edi at all.


Perhaps it's not that EDI is changed - you're using "mov [CmdBuf+di],al". Just try "mov [CmdBuf+edi],al" instead. If CmdBuf is greater than 65535 NASM sometimes truncates it to fit into 16 bits without issuing a warning.

ManOfSteel wrote:
Quote:
On another note, what happens if the user types 100 characters before pressing enter?

Nothing special. What is it supposed to do?


Currently it'd overwrite anything that follows CmdBuf, including the "db 13,0". It might be a good idea to limit the number of characters stored in the buffer. If the user falls asleep with their head on the 'h' key how much will be trashed before you get an exception?

ManOfSteel wrote:
Quote:
Oh, i hope that '0x21' is *not* your IRQ1 and that you're not trying to call an IRQ handler from software. That'd lead to ugly results (such as having the handler called twice, interrseting data lost, etc).

Yes, that's what it does. So, if I don't want it to do that, what should I do?


Have a seperate IRQ handler that gets keypresses from the keyboard, processes them and puts them into a buffer. Then use a software interrupt (or the kernel API, or IPC, or something else) to get the next keypress from the buffer.

The problem with what you're doing is that the CPU will automatically execute the IRQ handler, which will change AL (even when your code isn't waiting for a keypress). If your code is waiting for a keypress the IRQ handler will be run twice.

It also makes it impossible for any other IRQ to be handled, so when you start using anything more than just the keyboard (timers, mouse, disk drives, etc) you'll be stuck. In addition it has the same problems as all polling code does - the CPU can't be doing other things while the keyboard is being used.

If you really do want to use polling, test the "output buffer full" bit in IO port 0x64 until there's something in the input buffer, and don't mess with the IRQ at all. In this case your code would become:

Code:
    mov edi,CmdBuf
    cld
Shell:
    int 66       ;keyboard API
    cmp al,13
    je EnterKeyPressed

;print the keyboard input

    cmp edi,CmdBuf+10
    jae Shell
    stosb
    jmp Shell

EnterKeyPressed:

;print 'CmdBuf' to the screen

    mov edi,CmdBuf
    mov al,90h
    mov ecx,10
    rep stosb
    mov edi,CmdBuf
    jmp Shell

    section .data
CmdBuf times 10 db 90h
    db 13,0
    section .text

int66handler:
.wait:
   rep nop
   in al,0x64
   test al,0x01
   jne .wait

   ;Convert scancode into ASCII

   iretd



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:Command-line interface
PostPosted: Mon Aug 23, 2004 1:04 am 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 11:33 pm
Posts: 3882
Location: Eindhoven
Brendan wrote:
ManOfSteel wrote:
Quote:
On another note, what happens if the user types 100 characters before pressing enter?

Nothing special. What is it supposed to do?


Currently it'd overwrite anything that follows CmdBuf, including the "db 13,0". It might be a good idea to limit the number of characters stored in the buffer. If the user falls asleep with their head on the 'h' key how much will be trashed before you get an exception?

Or leaves the computer on for 100 days in a row without using the keyboard for the typing-goal and using it for the stacking-things-upon-goal... such as I do with my router (yes, my bash did grow to a few megs).


Top
 Profile  
 
 Post subject: Re:Command-line interface
PostPosted: Mon Aug 23, 2004 7:47 am 
Hello,
Quote:
Perhaps it's not that EDI is changed - you're using "mov [CmdBuf+di],al". Just try "mov [CmdBuf+edi],al" instead. If CmdBuf is greater than 65535 NASM sometimes truncates it to fit into 16 bits without issuing a warning.

I already tried that, but then, when I press enter, it won't even print the unchanged buffer anymore, the cursor will stay where it was and not a single character will be printed.

Quote:
Have a seperate IRQ handler that gets keypresses from the keyboard, processes them and puts them into a buffer. Then use a software interrupt (or the kernel API, or IPC, or something else) to get the next keypress from the buffer.

And this software interrupt will call the keyboard IRQ (int 21h) and I will include a call to this software interrupt in the CLI, right?
In that case, where can I use the 'hlt' instruction, cause wherever I put it, no more key are being read from the keyboard.


Now, concerning the main problem, how do you explain that
Code:
mov byte [CommandBuffer],'a'

this works ...

Code:
mov byte [0b8100h],al
mov byte [0b8101h],4

... this works too ...

Code:
mov byte [CommandBuffer],al

... and this doesn't work.

Thanks for any help


Top
  
 
 Post subject: Re:Command-line interface
PostPosted: Mon Aug 23, 2004 8:13 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 2:31 am
Posts: 5964
Location: In a galaxy, far, far away
okay, just to show you how it can be done (and was done in BIOS)

Code:
   KeyStroke --> 8042 --> IRQ1

        int 0x09: inb(0x60); // read scancode from the 8042
                     character = decode[scancode];
                     if (buffer_is_full()) beep();
                     else buffer[where++]=character;
                     outb(0x20,0x20);

        int 0x16: while (buffer_is_empty()) halt();
                     // note that it could have been another IRQ than kb!
                     character=buffer[free++];
                     return character;


when a user whished to get a char, he was simply calling int 0x16.
If you want to get a whole line (which wasn't possible with the BIOS alone, iirc), DOS was building a larger buffer (or receiving it as parameter) and repeatedly called

Code:
        while (current_length<max_length) {
            character=read_char_with_int16()
            switch(character)
            case CR: buffer[current_length]='$';
                          return current_length;
            case BS: current_length--;
                          erase_last_character_with_int10();
                          break;
            default:    buffer[current_length++]=character;
                          display_last_character_with_int10()
                          break;
        }

_________________
Image May the source be with you.


Top
 Profile  
 
 Post subject: Re:Command-line interface
PostPosted: Tue Aug 24, 2004 12:59 am 
Offline
Member
Member
User avatar

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

ManOfSteel wrote:
Quote:
Perhaps it's not that EDI is changed - you're using "mov [CmdBuf+di],al". Just try "mov [CmdBuf+edi],al" instead. If CmdBuf is greater than 65535 NASM sometimes truncates it to fit into 16 bits without issuing a warning.

I already tried that, but then, when I press enter, it won't even print the unchanged buffer anymore, the cursor will stay where it was and not a single character will be printed.


So you're telling me that when you use "mov [CmdBuf+edi],al" instead, the buffer gets changed to something that doesn't print properly? Isn't this better than not changing the buffer at all? If this is the case use "mov [CmdBuf+edi],al" and then try to figure out why AL isn't returning printable characters (big hint follows)...

ManOfSteel wrote:
And this software interrupt will call the keyboard IRQ (int 21h) and I will include a call to this software interrupt in the CLI, right?


NO! Nothing should ever call the keyboard IRQ directly.

Imagine the CPU is busy calculating PI to 1 million decimal places, and the user presses a key. The keyboard hardware tells the PIC chip to tell the CPU that in needs attention. The CPU realizes that the keyboard hardware needs attention, looks up the entry in the IDT for the IRQ, and starts running the IRQ handler. When the IRQ handler is finished it uses "IRETD" to return the CPU to what-ever it was doing before the IRQ occured. In this way IRQs seem to happen in the background without affecting anything else, but also the IRQs are handled (almost) immediately (ie. without waiting several days for some software to start polling).

Now considering that the IRQ handler should never effect any code that it interrupts, how does the results of the IRQ (e.g. the keypress data) get where it's going? This is why there's a buffer or queue. The IRQ handler puts the keypress data into this buffer/queue and that is all.

Later on, software can retrieve the keypress data from the buffer when it needs it (without messing with any IRQ handler).

ManOfSteel wrote:
In that case, where can I use the 'hlt' instruction, cause wherever I put it, no more key are being read from the keyboard.


Ok, I've attached code (due to the pointless 4 Kb limit) to demonstate what I'm trying to say. Please read though it :)


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  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: jzef, Majestic-12 [Bot] and 216 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