Page 1 of 1
Interrupt Handling
Posted: Wed May 21, 2014 1:01 am
by christianh104
I've been having seriously annoying problems getting interrupt handling to work in my OS. I figured out the problem, but the code on the Wiki didn't work for me until I changed it, and it took forever to figure out, so I'm trying to figure out if it's something specific to how I'm doing things or if the Wiki should be changed.
My PIT ISR code looks like this (I don't use inline functions because I use TCC, which just ignores the inline attribute):
Code: Select all
// pushf is defined as asm volatile("pushf"), etc.
#define enter_int() {\
/*pushf();*/\
pusha();\
asm volatile("sub $4, %ebp");\
}
#define ireturn {
asm volatile("add $4, %ebp");\
popa();\
/*popf();*/\
leave();\
iret();\ // BLACK MAGIC!
}
#define ack_irq_master() outb(0x20, 0x20);
#define ack_irq_slave() outb(0xA0, 0x20);ack_irq_master();
void pit_isr () {
enter_int();
for (unsigned char i = 0; i < 10; i++);
ack_irq_master();
ireturn;
}
But I would have issues if the interrupt occurred during another loop, such as:
Code: Select all
unsigned char a = 0;
while (a == 0);
shutdown();
I know this loop should never exit, but it would, until I added the pushf() and popf() to the ISR. I understand that the loop inside the ISR could change the processor flags, and mess up the loop that was running when the interrupt occurred, but if this can happen so easily, why does the Wiki page not include the pushf and popf?
BTW this is my first post, so I'm not too experienced with this forum.
Sorry if this was worded weird, I don't ask questions online often.
Re: Interrupt Handling
Posted: Wed May 21, 2014 1:23 am
by Combuster
Homework question:
1: What items does an interrupt (software or hardware) put on the stack?
2: What happens to the stack and registers before enter_int? Are you actually putting things back they way they were?
Your real problem however is that you wrote interrupt handlers in C. Which is a really bad thing to do.
Re: Interrupt Handling
Posted: Wed May 21, 2014 1:53 am
by christianh104
1. Okay then its something I'm doing , tomorrow I'll single step through my code in bochs with an int 32 and see whats happening to the flags before and after the interrupt. Maybe the compilers using the same place in the stack as the flags are in.
2. I only have that simple loop and irq acknowledge, so it shouldnt modify the stack any more than the pusha, popa.
Thanks for the quick reply, this is really going to help me understand what was causing me so much trouble
I'm actually planning on getting my kernel to have all the basic I/O features I want and then rewriting as much as I can to Assembly to make it faster and smaller. For now, I'm using C just because it makes things easier to get there. It would probably also help a bit if TCC supported optimizations :/
Re: Interrupt Handling
Posted: Wed May 21, 2014 1:56 am
by christianh104
I dont remember why I subtract 4 from esp and then add it back at the end... I know it was for a good reason, but II'll try to remove it tomorrow and see what happens, and I'll try moving esp more to see if tthere's anything that's being overwritten
Re: Interrupt Handling
Posted: Wed May 21, 2014 3:13 am
by bwat
christianh104 wrote:rewriting as much as I can to Assembly to make it faster and smaller.
It seems that, on a reasonably loaded system, a small percentage of time is spent in the OS. Consequently, Amdahl's law says that any overall speedup gained by your rewriting will be expensive in terms of your effort.
Example: if your system spends 10% of the time executing OS code and you made the OS one billion times faster by rewriting it in assembly, then your speedup would be 1.11, i.e. the system as a whole will only be 11% faster.
Re: Interrupt Handling
Posted: Wed May 21, 2014 7:55 am
by christianh104
I know, but I know that when I rewrote my memcpy and memset functions to inline assembly and used rep movsb it made my OS much faster because I use another buffer for VGA and copy it to the actual buffer when its time to draw the screen. I know there's a better way to double buffer, but I was still able to gain a big speedup. I think if I used an optimizing compiler I wouldn't find it as big of a difference
Re: Interrupt Handling
Posted: Wed May 21, 2014 8:14 am
by christianh104
I removed the pushf, popf, and the code that moves esp and of course, now it works. Thank you for the help
Now I understand, so I'm happy lol
Re: Interrupt Handling
Posted: Wed May 21, 2014 8:35 am
by Bender
christianh104 wrote:I know, but I know that when I rewrote my memcpy and memset functions to inline assembly and used rep movsb it made my OS much faster because I use another buffer for VGA and copy it to the actual buffer when its time to draw the screen. I know there's a better way to double buffer, but I was still able to gain a big speedup. I think if I used an optimizing compiler I wouldn't find it as big of a difference
It's okay if you're transferring 4000 bytes (80x25 Text Screen), but it's gonna cost you badly once you start moving large memory blocks (Images? Graphics? idk). It's better to use SSE, prefetching etc. IIRC even GCC provides a highly optimised memcpy, and there are numerous ones on the net. Though I'm not sure about how they would work on small data, because whenever I look at such optimizations, they tend to say: "Can copy 100MB in X unit time vs rep movsb takes X unit time......", but I've never seen one say, 'Can copy 20 bytes in X unit time vs rep movsb which does in X unit time"
.
Re: Interrupt Handling
Posted: Wed May 21, 2014 8:50 am
by hometue
Bender I think they just got tired of showing results in microseconds or nanoseconds so they decided to try transferring bigger data instead to measure the functions in seconds.
Re: Interrupt Handling
Posted: Wed May 21, 2014 11:08 am
by sortie
Don't write interrupt handlers in C! Do it in assembly instead. You are competing with the compiler for control of the raw code generation when you try to write interrupt handlers in C and it is entirely unstable - and you can easily write an interrupt handler in assembly that wraps an actual pure C function. Attempting to write interrupt handlers in C is doomed to fail, as it is a fragile hack unless you use language extensions that make the compiler aware that this is an interrupt handler. On select platforms and compilers, you can use naked functions, but those are easily abused where even simple cases are surprisingly wrong.
Don't use TCC. If it can't optimize properly and have problems with other common and useful language extensions, switch to a more reliable compiler such as GCC. If you are considering switching your operating system from C to assembly on the basis that TCC can't generate proper code, well, that's silly. Mind that you usually want as little assembly as possible in your C operating system, as assembly turns out much harder to maintain (when you do minor changes to the ABI, changing how types are declarated, system call semantics, ...) than C. You can usually get away with having very little assembly and writing the rest using compiler builtins and occasionally inline assembly, or just writing normal C and hoping the compiler recognizes it should use the best instructions for the task. Mind, however, that certain things really belong in assembly files, and interrupt handling is one of those particular things.
Don't prematurely optimize your operating system in assembly. A memcpy is one of the things that can cause large speed ups if it is optimized, that is, it doesn't copy a byte at a time in a loop, but it certainly won't be a bottleneck in your operating system for a while. Mind that video memory is much different from RAM in the sense that it is much slower to access and inefficient accesses to it are disastrous. You usually want specialized copy_to_video_memory functions that you use rather than a simple memcpy. I previously encountered that my memcpy that was tuned for optimal performance in normal RAM, was much slower than my previous memcpy when copying to GPU memory. As such, you should design separate functions for different copying tasks. Note that the VGA text mode memory is slow to access (compared to RAM), you can get a massive free speedup when scrolling by simply caching the VGA text mode memory in RAM and accessing that when needed - and then only writing to the VGA text mode memory when actually needed.
Re: Interrupt Handling
Posted: Wed May 21, 2014 11:39 pm
by hometue
@sortie: By writing the interrupt handler in C do you mean the whole thing (from accepting the interrupt to the iret) or do you mean the interrupt handler in assembly calling a C function?
Re: Interrupt Handling
Posted: Thu May 22, 2014 12:04 am
by Combuster
All the stack and state preservation should happen in assembly. After that you are free to set up a C-compatible environment again and call C functions, but before that you shouldn't leave pure assembly land.