Calling an interrupt from the handling of another.

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Calling an interrupt from the handling of another.

Post by eXeCuTeR »

The situation is as follows:
I'm implementing 'cat' and every thing works splendidly GREAT! except that it handles a `cat request` (`cat file1` for instance) by calling fat_read which uses floppy_read which waits for an interrupt, while all this is done under the handling of the keyboard interrupt. (i've called it in such names you would understand what it does)
So what is actually needed is to wait for an interrupt (for floppy, since reading involves waiting for interrupts) inside an handling of an interrupt (the keyboard one!)

Sure, I could have played with iret and ret and manipulate with the EIP but that is does not look good and really annoying.

Here's some code snippets in case you haven't completely understood what happend (the code works just fine, it is just that an interrupt has to be called for inside the handling of another)
(No need to actually read the code because it is fine, just to make things more clear for those who have not fully understood)
(try to ignore the disturbing indention, it's just that I'm using KWrite so copying it to here makes it look bad)

cat.c:

Code: Select all

  if((pos=find_entry(cwd, (const char *)name, (const char *)ext)))
  {
    if(!(pos->attributes & ATTR_SUB_DIRECTORY))
    {
      if(pos->file_size > LARGEST_FILE_FOR_SHOW) printf("cat error: file is too large to be shown.");
      else
      {
	char *buffer = (char *)malloc(pos->file_size+1);
	memset((void *)buffer, 0, pos->file_size+1);
	fat_read(pos, buffer, pos->file_size, 0);
	printf("%s", buffer);
	kfree((void **)&buffer);
      }
    }
    else
      printf("cat error: requested file is a directory.\n");
  }
  else
    printf("cat error: requested file is neither a file or a directory.\n");
keyboard.c:

Code: Select all

void keyboard_handler(registers_t *regs)
{
...some code
pos->cmd->exec(current_cmd->args); // calls cat
...some code
}
fat.c:

Code: Select all

int fat_read(fat_entry_t *file, const char *buffer, unsigned int size, unsigned int offset)
{
...some code
floppy_read_sector(cluster_to_sector(cluster));
...some code
}
floppy.c:

Code: Select all

void floppy_read_sector_chs(unsigned char cylinder, unsigned char head, unsigned char sector)
{
...some code
floppy_wait_int(); // or either floppy_sense_interrupt(&st0, &cyl); is there also
...some code
}
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Calling an interrupt from the handling of another.

Post by pcmattman »

You need some method to nest interrupts safely - usually involves jumping to a new "nesting level" and loading a stack for that level. As you wind back (interrupts return) you can reduce the nesting level accordingly and free up the stacks. This is a super simplified explanation of how we go about nested IRQs and interrupts in Pedigree.

Really though, I can identify a bigger problem you're dealing with - you say all this is happening from your keyboard IRQ? That sounds to me like you've just hacked in a command prompt to the IRQ handler rather than doing it "properly"...
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Calling an interrupt from the handling of another.

Post by gerryg400 »

eXeCuTeR, pcmattman is correct. This is a very unusual and perhaps problematic approach. Are you asking for a different way to do it ?
If a trainstation is where trains stop, what is a workstation ?
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Calling an interrupt from the handling of another.

Post by eXeCuTeR »

pcmattman wrote:You need some method to nest interrupts safely - usually involves jumping to a new "nesting level" and loading a stack for that level. As you wind back (interrupts return) you can reduce the nesting level accordingly and free up the stacks. This is a super simplified explanation of how we go about nested IRQs and interrupts in Pedigree.

Really though, I can identify a bigger problem you're dealing with - you say all this is happening from your keyboard IRQ? That sounds to me like you've just hacked in a command prompt to the IRQ handler rather than doing it "properly"...
Hmm, what's the alternative? Parsing a command and getting the arguments for it is done through the keyboard handler, how could I pass such information to higher levels rather than an IRQ?
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Calling an interrupt from the handling of another.

Post by pcmattman »

Buffer the keys that are pressed in a FIFO or something (ring buffers work well) that applications access through a well-defined API. That way the actual reading of key presses happens outside of an IRQ.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Calling an interrupt from the handling of another.

Post by gerryg400 »

There are a few ways, but mostly the answer is to convert the asynchronous interrupt to a synchronous event that the kernel or driver can handle. For a keyboard driver you might do this

Code: Select all

/* ISR - occurs every keypress - asynchronous */
1. Read key from keyboard hardware
2. Maybe handle ctrl, shift and alt status
3. translate key to char.
4. Put char in buffer in driver 
5. Set flag to say key is available.
6. Do hardware things like ack keyboard and PIC.
7. IRET


/* Readkey system call - called from cat process */
1. disable interrupts
2. Checks flag to see whether there is a key available
3. Removes char and clears flag if buffer is empty
4. enables interrupts.
5. Return char or NULL if no key OR might block waiting for key to become available

If a trainstation is where trains stop, what is a workstation ?
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Calling an interrupt from the handling of another.

Post by eXeCuTeR »

pcmattman wrote:Buffer the keys that are pressed in a FIFO or something (ring buffers work well) that applications access through a well-defined API. That way the actual reading of key presses happens outside of an IRQ.
Thought of this way, to be honest. Thanks, by implementing it this way, no harm will be done and problem will be solved.
But only one thing is unclear...
how can I define such an API that applications will EDITED:not be able to just write to, say, (if this FIFO is at 0x1234 for instance) just write to 0x1234.
To make these pages that these addresses occupy only accessible on DPL0 (ring0) and every time an application is trying to reach it, it'll call a system call which will do the trick? Is this a good design enough?

EDIT: Thanks gerry, it is the basic idea indeed even though I think I'll just write to the buffer whenever I have a command parsed with its arguments and not every char - this doesn't really risk anything. when the command is ready (enter was pressed), i'll "pipe" it out to the buffer, set a key that will indicate that a command is ready to be triggered.

if you could also just refer to my new question (which I think I gave a fair answer, but just to make sure I don't make another design error).
Last edited by eXeCuTeR on Thu Jul 22, 2010 10:20 pm, edited 1 time in total.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Calling an interrupt from the handling of another.

Post by gerryg400 »

You mean this question ?
how can I define such an API that applications will be able to just write to, say, (if this FIFO is at 0x1234 for instance) just write to 0x1234.
I think it's better not to do this. You should try to abstract away the memory reference. The API should be ReadKey() or getch() or something. The kernel can handle the index, permissions, blocking etc. That way you can modify your kernel later and all your APPS will still work. These are the reasons for developing an API.
If a trainstation is where trains stop, what is a workstation ?
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Calling an interrupt from the handling of another.

Post by eXeCuTeR »

gerryg400 wrote:You mean this question ?
how can I define such an API that applications will be able to just write to, say, (if this FIFO is at 0x1234 for instance) just write to 0x1234.
I think it's better not to do this. You should try to abstract away the memory reference. The API should be ReadKey() or getch() or something. The kernel can handle the index, permissions, blocking etc. That way you can modify your kernel later and all your APPS will still work. These are the reasons for developing an API.
Hehe no, I actually meant the opposite (how to prevent such case): how could I make such thing NOT to happen, I forgot to add a critical word (just read my next lines, you'll see). sorry about that. (been awake for way too long)
So, I'm thinking of making ReadKey() a system call, that will return the buffer when called if ready.
By doing it this way, I actually must move a character by a character, which is kind bad for me because all the parsing of the command is already done in the IRQ handler.
Any other way maybe? (to keep the buffer safe from applications and also create an easy to implement API)
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Calling an interrupt from the handling of another.

Post by gerryg400 »

By doing it this way, I actually must move a character by a character, which is kind bad for me because all the parsing of the command is already done in the IRQ handler.
Any other way maybe? (to keep the buffer safe from applications and also create an easy to implement API)
I was recommending that the ISR simply put the chars in the buffer. The parsing would be done in the APP. The APP calls ReadKey until it gets a '\n' and then parses the command.
If a trainstation is where trains stop, what is a workstation ?
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Re: Calling an interrupt from the handling of another.

Post by egos »

gerryg400 is right. Just small remark: character translation could be done by application from (virtual) key scancodes, control key flags and keyboard indicator flags. Even more generalized way is to use event queue for foreground process. For keyboard I use KEYDOWN and KEYUP events with following parameters: event identifier (dword), virtual key scancode (dword), control key flags (dword: low byte - left, next byte - right), keyboard indicator flags (dword).
If you have seen bad English in my words, tell me what's wrong, please.
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Calling an interrupt from the handling of another.

Post by eXeCuTeR »

Hmm, I'm thinking about it again and I'm not sure if a ring buffer is actually needed. I actually need a room from only 1 byte, since getch()/ReadKey() read only one and all the other functions just like getline(), rely on these. What do you guys think?
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Calling an interrupt from the handling of another.

Post by gerryg400 »

The ring buffer is for type-ahead. So the user can continue typing the next command while the APP (in this case cat) is still executing.
If a trainstation is where trains stop, what is a workstation ?
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Calling an interrupt from the handling of another.

Post by eXeCuTeR »

gerryg400 wrote:The ring buffer is for type-ahead. So the user can continue typing the next command while the APP (in this case cat) is still executing.
But what happens when you call getch once, and the user keeps on typing.
Then you call getch one more time, what will be returned?
As I see it know, the keyboard ring buffer, whenever a character is pressed, it pushes at into the ring buffer.
So when calling getch() it actually just reads the next character in the FIFO? (while there could be alot of values)
Also kinda buggy in a point where the use types lots of characters, and also, our memory if finite, and the buffer is circular, so some data could be lost.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Calling an interrupt from the handling of another.

Post by gerryg400 »

Generally for type-ahead you just need a few chars. The user might type a few, then realise nothing is happening yet so he waits. If the buffer is too big, the user will be annoyed that characters that he cannot remember typing, or didn't mean to type (e.g. leant on the keyboard) are still being processed. I just checked and my driver has a 32 key ring-buffer per terminal.
If a trainstation is where trains stop, what is a workstation ?
Post Reply