This video explains how to implement the Interrupt Descriptor Table (IDT) in an x86 operating system, covering the creation of IDT entries with specific structures including offset, present bit, DPL, gate type, and segment selector; initializing the Programmable Interrupt Controllers (PICs) at ports 0x20 and 0xA0; setting up Interrupt Service Routines (ISRs) for exception handling (like divide-by-zero errors) using assembly macros; and implementing Interrupt Request (IRQ) handlers for hardware interrupts from devices like keyboards. The implementation uses C code for the IDT setup and assembly code for the common stub that saves CPU registers and calls a C handler function to display exception messages.
Building an IDT for x86 Operating Systems: Interrupt Setup
Added:in this video we're going to work on adding interrupts into our operating system and we're going to be doing this using a data structure that is known as an interrupt descriptor table or IDT and like our gdt we have a nice page on the osdev wiki that can help us understand the structure of the actual interrupts and the interrupt table that we're working with now inside of this interrupt table we're basically going to have a bunch of different entries just like we had with our gdt and we're going to create structs for those we're going to build up those entries and we're going to implement them into our operating system now the question is what is really the purpose of an interrupt and there's really two main reasons why we're working with interrupts and the two main reasons are going to be for interrupt requests and interrupt service routines so interrupt requests are going to be something that will typically come in through Hardware it's basically a request for the processor to interrupt its current operation or execution interrup requests can come from a variety of different places uh some examples may be your keyboard uh some different serial ports on your computer and various different Hardware components of your computer so in order to be able to surface these different Hardware components their Communications with the CPU we need to have some interrupt uh requests available in our operating system now in addition to this we also need to have interrupt service routines and basically these are the routines that are run when an interrupt is received by your operating system so the operating system gets an interrupt it needs to be a able to do something with that interrupt in order to handle it and the main ones that we're going to see in this video are going to be associated with errors in the operating system so for example if there was a divide by zero error in your operating system right now if that were to happen the operating system would just crash it wouldn't do any they would just go back to the grub screen like we saw with our gdt errors now that's not really ideal in most operating systems it will crash and give us the error that occurred we could see this in windows with the blue screen of death and we could see this another operating systems with things like kernel panics generally what we'd like to do is display an error to the user to say this issue happened and here's the information about the stack and the registers that sort of idea for this video we're really just going to demonstrate the message to say hey this exception has happened and here's what we want to do about it so with that being said let's get into the actual implementation now a few things have changed a little bit from this code I just put everything inside of this source file that's source code just help to organize it and for this video I'm going to put my interrupts code instead of its own folder this is going to help me uh organize things a little bit more you don't need to do this uh it's just for me to keep track of everything but we're going to create three files associated with interrupts there's the id. c h and s s is our assembly code which we need this is our C code and this is our header so started out of the header and like I said like the GDC we're going to have a struct for each entry inside of the interrupt table and these entries are going to have a very specific structure associated with them which you can see here inside of the OS Wiki you'll see here that like the gdts we have an offset which is divided up into two pieces this offset is the entry point of the interrupt service routine so it is the function that we want to call when the interrupt occurs interrupt occurs we go to that offset and start executing we have this P which is the present bit like we had n our gdt it set to one to say that the descriptor is valid we have a DPL which was also present in our gdt this is the two bit uh value that represents the CPU privilege level we'll typically set this to 0 0 to have these at kernal level we have this bit that's always going to be zero we have a gate type and a gate type is going to be something that describes the interrupt that we've added in we're always going to see this as a 32-bit interupt gate so 0xe is the one that we're going to be using for these entries we have a bunch of reserved space that we don't need to worry about and then we have a segment selector the segment selector allows us to specify a code segment in the gdt that we are going to use for this particular entry so this is something that we're going to set towards a valid code segment in our uh in our gdt so understanding that idea we'll just put in our struct and as with our gdt we need to make sure that the ordering and the formatting is the exact same as the one that was specified in that Wiki that'll just make sure that we don't have any sort of errors or problems with the formatting here so I'm going to implement each of the different properties that I have and this sort of thing is very similar to our gdt entry so it's not really anything too exciting it's pretty standard and straightforward and we're going to like before before set the attribute as packed for these okay so that's the setup of the entries now like our gdt we are also going to have this pointer struct which is going to of course point to our IDT entries so this is the same sort of idea as what we had with gdt so we have a limit and we have a base and this is of course going to have an attribute as packed now for now there are two functions that we're going to work with one to initialize the IDT and one to set each of the IDT Gates this one is going to have a very similar structure to the gdt it's going to have the index in the array where we're placing the actual gate it's going to have the base value it's going to have the selector values the select values and we're going to have the flags as well so those are the three things we need to provide to it and what we're going to do is we're going to use some bitwise operations to parse things out and get it into this format here which you'll see as we're going through so I'm going to go and copy these over to.c just that way I have both of these function descriptions in and available and then we'll get to work with our implementation okay great so in order to set this up we're going to need a few different things included we're going to include our standard int that way we get over our like uint formats these types of things we're going to include the u.h so we need some utility functions as we're working through this we're going to need some VGA function so include our VGA header and of course we'll include our IDT there's two structs that I'm going to initialize here we have the ID entry struct which I'm going to call IDT entries it will have 250 SI 256 in size as the array so there's going to be 256 entries in the IDT not every single one of them is going to have a value but some of them will so we'll see how that is structured out and I'm going to define the struct for my pointer which is just going to be called ID pointer okay and then I'm going to create an external reference to a function called IDT flush this is similar to the gdt flush it's going to be some assembly code that's going to essentially set up all of these different records that we're creating inside of the IDT table now there's a few interesting things that happen with our IDT the very first thing that we're going to do is set up the limit of the pointer and the base of the pointer this piece is uh quite similar to our gdt table so we're just going to get the size of each of the strips and multiply it by the size of the array so these two numbers here are going to match with each other and then we subtract one just like with the gdt similarly when we set up the base we're just taking the address of IDT entries so the address of this array right here and then what we're going to do is we're going to initialize everything to zero using M set and that's because we're not going to set a value for every single entry here but we do need the you know total number of entries initialized so we're just going to initialize everything to zero and then set the ones that we actually need so this be the size of the ID entry struct uh times 256 just like that okay so all this is very standard straightforward so far this is where we get into the interesting part and it's the fact that we need to actually do some programming for what we call programmable interrupt computer or pic so in your computer there are two pic chips and generally they'll have different namings for them I think like the standard naming is that one of them is called the master chip one of them is called the slave chip uh you could also refer to them as the main chip and the secondary chip uh whatever you want to refer to it as but you'll see those terminologies generally used for these chips generally one of the chips is going to sit at memory addresses 0x20 for commands and 0x 21 for data the second Chip is going to set it 0x a0 for commands and it's going to sit at 0x A1 for data now these will need to be initialized in order for us to be able to use our are interrupts so you need to actually send some data to these chips now how do we send that data well we have to use a special command which I'm going to set up in this util doc that special command is going to be called outport B is what I'll call it it's going to take in a value for a port and it's going to take in a value and what it's going to do is it's going to run the following assembly code it's going to run the command outb for %c 1% 0 and then for the syntax we put this and then we put the formatting of our value for the port and our formatting for the value so you may not have ever seen this operation before I never really talked about it in the x86 video so far what it does is it outputs a bite of data to a specified IO Port so what happens is all these different ports on your CPU could be hooked up to different chips one of them is hooked up to those pic's and what we're going to do is we're going to write data to the port that's hooked up to those pic's so we could set data directly to those chips that's the idea of what we're doing with this port value setup so we're writing to the port associated with those chips a specific value and that value is going to be for the initialization of those chips that we could set them up for for our actual interrupt creation okay so that's what we're looking to do here so that's what this function's purpose is generally going to be right now the reason why I put it in util is because we will use it in a variety of different places not just in the IDT so we are going to set it up here and then just import it wherever we need it so as I mentioned these different uh ports are going to be associated with each of the different areas on the chip so to get this to work what we're going to do is we're going to run outport B and the very first thing that we do is we send 11 to the command ports of each of our chips the primary and secondary ones so we send 11 to each those chips this is going to start those chips up into their initialization mode so now they're waiting for I believe three more commands to except and each of those commands represent something specific it's going to give it an offset and then it's going to give it uh the location of each of the different chips that initialize those and that is going to get us all set and ready to go so that's the first set of commands that we need to do second set of commands that we're going to do is the following we're going to send to the data section of the first chip the value 20 then we're going to send to the data section of the second chip the value 28 so these are what I referred to as the I believe Vector offsets so it's setting up those offsets for our chip and then we're going to send a few more requests out to these data sections okay so again we send off to each of the data sections in this case the values four and two and then we're going to do a few more data section sents so we have another set of those here so we send to 21 0x01 and then we do the same with 0x A1 we send it 0x01 and then finally as the last sort of thing we just send zeros to each of these different chips okay so this is the conventional way that we are going to initialize these pic's so that they are available for our interrupts so this is how we initialize those values okay from here everything is going to be pretty straightforward we're just going to be setting up the gates for all of our different interrupts now this process is a little bit tedious I'll admit to set up these different uh values but we try to get through it as quickly as possible so what we're going to do is we're going to set the IDT gate again we provide a number and then we provide a um an actual function for it to use now we haven't implemented any of these functions yet and we'll we'll do that we're actually going to implement them in assembly we'll number each of them based on their actual service routine number so they'll be 0 through to 31 there's 32 total functions that we're going to implement here now before I get into that I just want to explain to you how we set up these two Flags the and the flags here first one is 0x08 the second one is 0x8e let's talk about what each of these are representing so for 0x8e what this is representing is we would have the following we have 1 0 0 0 1 1 1 0 this top half here is going to be the present bit which is set to one and then the DPL which is set to two zeros and then this bit here which is always zer Z so that's what that first four bits is representing the last four bits is the gate type which as I mentioned is always equal to e right because it's a 32-bit interrupt gate so that's how we got this piece here that's the E and then this is the other bits for the present bit the DPL here and then this bit is just always zero so that's where this 0x 8e is coming from the other one 0x08 what that is is it's really just like a simple one here it's just to 000000 0 and then 1 0 0 what this is representing here is the code segment associated with this so this is really looking at the selector here so selector has to point to a valid a code segment in my gdt that valid code segment is 0x08 which is the code segment that we've initialized in our gdt so that's why this is equal to 0x08 now at this point what we're going to do is we're going to copy this and we're going to do this a whole bunch of times all that's really going to change is that these zeros will change to one two three and then this will change to 1 2 3 and you're going to do this a whole bunch of times you're going to do this about 32 times so in the sake of time I'm just going to go ahead and copy these and I'm going to paste them in you'll see that they're all the same in terms of Entry the only things that changes this number here and this number here and I'll make this code available so that you don't have to go through the process of typing this out yourself because it's extremely tedious and you're not going to learn anything from typing this out so you can just copy and paste it no big deal now similarly we need to make reference to all these different functions so inside of.h what I'm going to do is I'm going to set up an ex turn void to each of these different functions so we'll do ISR Z and then of course we'll do isr1 and this is going to repeat over and over and like I said I'll give you the code so that you don't have to type this out one by one just copy and paste it it's not really worth typing out there's just the same function just with these numbers here okay so that's nice and easy now there are two other interrupts that we would typically Implement here and they're for system calls at 128 and 177 so there is a fairly big jump here but these are the ones that we would use for system calls typically is the ones all the way out at 128 177 and I'll just go ahead and place those in here as well they look the exact same they're just used for system calls which is why their numbers are higher okay so so far so good we could set our IDT gate here make this uh all set and ready to go the actual way that we set each of these Gates is pretty straightforward we just to do some manipulation for the base low which we do using of course our typical bitwise operations and we'll do the same for uh base high right here we'll shift it by 16 and then end it with ZX FFF FF in order to get us to the High bits now to get the values for you know the value here we simply just set it in order to get the value for always zero we really just set it because it's of course always zero so that's nice and easy and then in order to get the flags we're just take that FX value and or it with 0x 60 all that's going to do is it's just going to remove the other bits that are inside of that variable there so you see that flyex we have right here when we're defining that here we have a you know a few different pieces that are associated with it so we just or it in order to eliminate any unnecessary flags and that gives us our IDT Flags so that's all good now last thing that we need to do here is an IDT flush which you have to find as an ex turn function and we'll have to implement that inside of our assembly code we're simply just going to give that a pointer to the ID pointer and we'll be good to go there so that's our set up so far let's go over to our assembly code and uh set up some of the other pieces that we need now we have to be a little bit smart here with the way that we set things up first off easiest one is IDT flush okay this function is not really too complicated same sort of process as what we saw inside of our gdt all we do is we we just extract off the argument from our stack and then we run this command here LT using eax that's going to load the interupt descriptor table using that pointer that we've provided and then we can do STI what this does is it sets the interrupts right now that we have interrupts available we can turn them on and we can use them and then we just return so that's all we need to do for the IDT flush now as you see in our header we've defined all the these different isrs and they're all external which means that they're all at an assembly level we need to implement all of these so one way that you can Implement them is you could you know write out the definitions for each of them and copy and paste and write out 32 functions and you know eventually you'll be done but there is an easier way to do it it turns out that there's really two different kinds of interrup service routines that we would typically have the first one is one that has an error code associated with it so basically an error code is associated with that interrupt so we are able to use that error code and then the other one has no error code so we actually have to just generate like a dummy error code so that the argument is available for us to be able to work with our uh service routine so the way that we can Define these is actually using macros in assembly so a macro is defined just by putting percent macro and then we give basically the name of the macro so I'll call this one the no error code and I'll put a one here the way that this works is basically we'll create a global definition and we'll name this ISR percent one whoops so basically whatever value is provided as an argument will be placed inside of here so if I give this ISR no error code zero this will become ISR Z so you see how that would result in us getting every single function defined right and then we can implement it right here I can do ISR percent one and all this is going to do is it's going to first off do CLI to turn off our interrupts or clear interrupts we're going to push on a basically fake uh error status or error code associated with this so we push on that zero and then what I'm going to do is I'm going to push on the value of percent one so those are the two arguments that are required here and then what I'm going to do is I'm going to jump to what I'm going to call the ISR common stub we'll have a common set of code that's going to handle all of our interrupts so we'll Define that in here a bit later on so that's the n end of this macro now we're also going to have a macro that's going to be associated with our error codes so ISR error code we give it a one we're going to do a global ISR percent one like we did before again ISR perc one we're going to do a CLI to set up the interrupts we're going to push long percent one and then we're going to jump to the ISR common stuff so you see that the only thing that changed between these is that we just don't have to push this onto the stack right that's because the error code is already there so we only have to push this one value on before we jump here that's the only difference between these two macros here now there will be another macro that we'll Define here but we'll get to that when we talk about interrupt requests so we'll just leave it like this for now and then to Define each of our different isrs we simply just say ISR and then whichever macro we want to use so for instance the first interrup service is zero and it's a no error code one so I do to ISO no error code zero and it will generate the ISR Z for me and give it this code okay we're going to have an ISR no error code for one or sorry this should be no error code for one and we're going to continue to repeat this over and over now I can't necessarily just copy and paste this and say that there you know there's not really too much work to do because there are a few different ones that we have to sort of set up in specific ways so up to seven we have no error codes then when we get to eight we do have an error code so a is going to have an error code nine is going to have no error code but then uh 10 11 12 and all the way up to 14 are going to have an error code so 10 11 12 13 14 these will all have an error code on them so this will be 11 12 13 and 14 so those are all error codes ones and then we have a whole bunch more that have no error code so all over the rest from 15 all the way down to 177 are going to have no error code associated with them and this is the way that we set up our interrupt service routines with error codes now next after this what I could do is I can set up my common stub so I'm going to create an external reference to a function called ISR Handler this will Implement in C but the ISR common stub will Implement in assembly what we're going to do is we're going to push all of our registers onto the stack we're then going to move into eax the register DS we're then going to push that onto the stack to preserve it we are also going to move CR2 onto the stack through the same sort of method and then what we're going to do is we're essentially just going to move our ax into uh or we're going to move 10 into ax and then like we often do we're going to initialize our segments so we're going to initialize our data segment to that we're going to initialize es to it we're going to initialize FS to it and we are going to initialize GS to it okay then we are going to push onto the stack the ESP register right that's our stack pointer in this case so what we've really done is we've placed all of the relevant registers associated with this interrupt onto the stack and what's going to happen is we're going to call a function called ISR Handler which we're going to implement in C and that's going to get all of that information and it's going to be able to use that information to tell the user you know what the values were of these registers and Stu before this actually happened that's mainly what we're doing here okay so next I'm going to move or I'm going to return back from this function so I'm going to add a onto the ESP I'm going to pop ebx and I'm going to go ahead and move that back into each of my different registers here so we're going to move these into each of these here es fs and GS so that's the way that we're generally going to set things up here now as I'm looking at this it looks like maybe this shouldn't be DX but rather should be DS and I'm just going to confirm that here quickly just to make sure that I've got that correct because it looks like that might be yeah that was just I think a little bit of a typo there right so yeah it should be DS so DS es fs and GS so those should be the values there okay from here what we're going to do is we're going to then pop all of the registers off using pop a we're going to add to the ESP by8 we're going to do an STI and then we're going to do an I return from this and that's going to be what we need for this common step now we're getting very very close to having our interrupts wired in here a few final steps that we're going to need to do is to deal with this ISR Handler so this ISR Handler is going to be set up inside of our header file here first so ISR Handler which is going to take in a struct called interrupt registers and we're going to implement this inside of our id. C file okay so we copy this over and I'll just paste it here for me to use now we need to of course implement this struct called interrupt registers I'm going to implement that inside of my util since I will use it in a number of different places and the struct will be called interrupt registers and like I said it's really just going to store all of the different registers that are associated with an interrupt so you see that we're going to have the data segment the CR2 register we're going to track the values of the EDI the ESI the EBP the ESP the ebx the edx ECX eax these are all pushed on by that push a command right we're also going to have an interrupt number remember that we are providing this from the ISR uh number functions right ISR Z isr1 they're each going to have an interrupt number and an error code associated with them and then you know aside from these registers here we also have a few related to EIP uh the Cs register we need the E fls register we need the use res register and the SS register these will be pushed by the processor automatically for us so we'll have all this information available okay so we come back over to our ISR Handler what we're going to do is we're going to print out a message based on the interrupt and generally what this involves is I'm going to create this list list of different messages based on each different interrupt so we can discuss all the different interrupts that we have available and what we're going to do about them so we'll have this uh exception messages we'll have a few different types so a zero would mean division by zero Cur a one is what we call a debug interrupt next would be a non-maskable interrupt then we have a breakpoint we would have an into detected overflow and all these are really just standard kinds of interrupts so if you were to look up a like an interrupt table you would see these kind of interrupts specified in this exact order right each one has a specified number associated with it so we can use each of these and some of these are probably you know familiar types of uh terminology right like invalid op code would be you know of course you have an invalid operation in our code right things like a double fault and triple fault were things that we had discussed as we were sort of going through our actual process here um so we would have our double fault here uh we could have a co-processor uh segment overrun we could have a bad TSS segment we could have a segment not present uh we could have a a stack fault we could have a general uh protection fault there could be a page fault there could be an unknown interrupt there could be a a co-processor fault an alignment fault and then the last one here is just called a machine check and then the remaining ones that we have available are all just reserved and I'm just going to copy these in there's a bunch of different ones that are available so from L here 104 to 116 we see that the remainder of these are just reserved and all our ISR Handler is going to do is it's going to take a look and it's going to say if the register's interrupt number so it's going to pull the interrup number if it's less than 32 then what I'm going to do is I'm going to print using my VGA the exception messages associated with that interrupt number so it's going to grab that interrup number it's going to print its exception message and then what I like to do is just sort of print out like a new line and then print out a message that just says exception system halted and generally we'll halt the system here so to do that we could just put in like an infinite Loop like this and we are good to go so this is going to take you know if we have an interrupt that we recognize out of any of these it's going to give us that exception and it's going to say oh we've encountered an exception and the system has halted and with that that we now have all of our interrupts actually set up so the last thing that we'll need to do for this process is to implement our irqs or our interrupt requests so the interrupt requests will be the next thing that we'll take a look at handling here to implement the interrupt requests is going to be fairly straightforward basically it's going to take up some of the remaining slots that we have here from the 32 Gates that we've added so far so basically when we're taking a look at this ISR Handler the reason why it stopped at 32 is because everything past there is going to be an interrupt request instead of an interrupt uh service routine so an interrupt request as I mentioned is going to be related to Hardware so things like keyboards and other devices may send interupt requests to the CPU to ask it to interrupt its execution we'll see that process in more detail as we continue to implement different Hardware components like keyboards and drivers related to those so to start off let's take a look at how we can get these interupt requests set up so generally the way that this is going to work is going to be very similar to our interrupts that we already have so we're going to add in some new interrupt Gates the exact same gate style and frankly the exact same syntax right so rather than using ISR as our syntax though we're going to change this to irq so rather than saying ISR Z we're going to say irq of zero these are going to go the same way 0x08 and 0x 8 e right the exact same values just this change to iq0 rather than ISR since these are now interrupt requests and as I mentioned with these relat just a process of copying and pasting you're going to do this 16 times to get zero through to 15 that gives us our 16 interrupt requests that are going to be standard for our system now in addition to this inside of our header of course we need to create external references to these functions same sort of process as the isrs it's just an external void and then irq Q 0 through 15 to match the functions that we require now we're going to implement these inside of assembly and we're going to implement them using these macros like we did before so generally what we're going to do is we're going to set up a new Macro for our irq it's only one kind of irq we don't need to create like an error code not an error code one we just have a single one now I think I forgot to mention previously that this one indicates that there's one argument provided so this one argument here and it gets plugged in at this percent one sign with the irq there's two so we use two here and basically one of them is going to give us the irq number so we can create all these different function names like this and then the other one is just going to be used as our value that we push on as an argument so that being percent two right here and you can see everything else works pretty well the same way we clear the interrupt we push a zero Z on this is similar to this non-error code version here we then push on the irq that we are given and then we're going to jump off to what we're going to call the irq common St just like this and then with these different error codes right here we're simply just going to Define our irqs the irq has two arguments so 032 for instance is going to be our first irq and it's going to have a value of 32 remember these start just past the ISR so the ISR ended at 31 so these begin at 32 and you're going to repeat this process 15 times just going to copy it in because it's again a lot to do and not really much benefit to see if we type it out right so you see here we just have 32 33 34 all the way up to 47 there's 16 total here now the irq Handler actually looks very similar to the ISR Handler for that matter it's pretty well find for me to just copy this here and we just need to change up a few small things inside of it to get it to work so this is going to be referencing a different function called the irq Handler we're going to call this the irq common stub it's still going to do a push a we're going to move uh these different registers onto the stack we're going to take 10 here all the way into all of these we are going to push the ISP we are going to make a call to irq Handler instead of ISR Handler and all of this looks good to stay the same so that's all we really need to do there now coming back to the IDT is where we're going to actually Implement that function as well as a few others that are going to be helpful so the irq Handler is going to work like this so we're going to create first off an array of what we're going to call irq routines this is going to keep track of all of the irq based functions that are going to be associated with these interrupt requests and we're going to start off off by zeroing them all out and I like to divide this up basically so there's eight on each row so four eight and then down here 1 2 3 4 1 two 3 4 just like that so this gives us the 16 routines that are associated with our interrupt requests and basically the way that this is going to work is we're going to have two functions here one is going to be called install Handler and what this is going to do is it's going to take in an irq and it's going to take in a Handler function that uses the interrupt registers as an argument and all it's going to do is it's going to associate the routine that was provided with the Handler function that was requir that was uh that was provided and for people who have some highle programming experience this is kind of like an event handware right we are basically associating an event with a function that's going to handle it kind of like a call back right same sort of idea here we're saying if this interupt request comes in this is the function that handles it so the idea is that when we create a device say like a keyboard we can register it with an interrupt and what's going to happen is when that interrupt happens we have the function to handle it and we're going to be able to handle it through this install handware so you'll see this process being used fairly often and in some cases we may need to deregister or unregister or and this case I think we call it uninstall usually and to uninstall we simply just make a call to this function here it's going to take in an irq and it's simply just going to set that irq back to zero so that's the way that we uninstall these handlers and then the final piece here is if we hit that irq Handler from the routine that we defined again like previous it takes in this interrupt register structure and what it's going to do is it's going to get that Handler that's associated so that um that interrupt set here that we have and it's going to say the Handler is equal to the irq routines at the registers int number minus 32 okay so we're going to take that we're going to minus 32 in order to get one of the indexes inside of this list here right because remember the interest number is going to be starting at 32 so we take 32 and subtract it from that value in order to get into this array here okay so that's how we get into the array if that has a Handler associated with it so if there's a Handler function we are simply just going to call that Handler function with the registers that we have and then in general there's a few special sort of cases if the interrupt number is greater than or equal to 4 we actually have to send out a signal to 0x a0 with a value of 20 and then in all cases we have to also send out a signal to 20 with the same value like this so this is always required for interrupt handlers just to send those signals out to again our our pic so this would be the general setup of our interruptor requests and at this point we should have everything up and running looks like I've got everything wired in so let's go over to our command line let's try to make in just a fix any errors that have inevitably creeped up here so it looks like I have oh I've missed a comma in my register declaration that would be just over here at my u.h yeah just missed this comma here so that's not so bad and then what we're going to do is just keep looking at some of these different ones uh it looks like there is a semicolon error in my uh gdt and let me just uh take a look at this here this is just before uh looks like just before gdt flush for the X turn reference to it uh yeah so we see here uh X turn void gdt flush it's likely something that has happened uh just outside here so looks like that's fine it might be inside of the gdt struct that we have the uh problem looks like all of that is generally fine uh let's just take a look here actually the error would be just in util byh yeah I just forgot a semicolon here so that looks to be the problem so let's just do another make here and I get this other error uh junk DX after register and likely all this is is in U.C I've just forgotten yeah I've just forgotten a comma here here so that should fix that problem make one more time there we go looks like everything is making successfully now we can add in our interrupts into our make file to get those to make as well so GCC um we'll do c Flags hyphen C so the Valu is in Source slash interrupts slash uh IDT doc I'll Call this id. o and then we also have a assembly file associated with that so l32 Source uh interrupts slid T.S and I'll call that IDT s.o and actually for oh yeah I put a lowercase i here so we'll just keep that nice and consistent and then right over here inside of our object files we can of course get these looped in so id. o and IDT s.o and let's go ahead and try to make this and see what happens so when I do a make here we're going to see a few different errors so one of the errors actually comes out of the fact that inside of our utel file. C we are having this uh standard int. imported in the header file instead of the C file so if I move this over to the C file it will reduce the Redundant Imports because you'll see here that you get some conflicting types because both IDT and util are importing the standard int uh header so when we fix that it will fix up a lot of these errors for us it'll be left with a few smaller ones that are more manageable so first off this one here in mem set I just forgot the uh struct keyword so we'll just go ahead and fix this one up here so if I come over here you'll see uh right inside of here size of this should be struct I often forget that keyword so fix that up a few other things that I noticed here is uh this here this star is in the wrong place should be car star and there should be a semicolon after this here that'll fix up a few other errors so let's go ahead and make and we'll see we have one more reg is not defined it should be regs registers like this and that should fix that up for us okay and we can see here that we have one other error related to our macros here uh the expected an end of file at line 144 in the macros uh let's go over gdts or sorry.s rather at 144 it looks like we were having some troubles with this compiling here so when I'm taking a look at my macros I just want to make sure that they're all defined in a consistent way it looks like they are now when I'm taking a look at this I just want to see are there any sort of things inside of this file that look a little odd uh end of file well still Define a macro oh I probably forgot the end macro that's probably it y that is it there we go so I need that end macro here and that'll fix that up for us and now it looks like everything builts fine so to test this out what we're going to do is we're going to go into kernel. C I'm going to include my interrupts uh.h like this and what we're going to do is we'll do an init IDT to initialize our IDT and basically we should just see uh nothing crashing would be ideal so let's go ahead and launch this and see what happens uh might take a few to get to it there we go and as you can see it doesn't crash so that's a really good side now one thing that we could do to test this is get an exception to throw one exception that we have is 1 divid 0 if I try to print that onto the screen I should see an exception occur let's give that a try and see what happens do you see that we get division by zero exception system halted that's great that means that that exception was caught it was handled and we printed this out onto the screen and we halted the operating system so with this all of our interrupts are now set up and ready to go so we're able to use these interrupts now and we're going to use these in the next few videos to start to wire in some of our Hardware into the operating system so thanks much for watching and I'll see you in the next video
Up Next

Writing a Simple VGA Graphics Driver in OS Development
@PageKey
9K views•2022-05-10

BitTorrent Protocol Explained: Piece Selection & Peer Choking
@StevenGordonAU
481 views•2013-02-22

x86 Operating Systems: BIOS Interrupt 0x10 to Print a Boot Message
@olivestemlearning
7.3K views•2023-08-27

Enigma Machine Mechanics: WWII Encryption Explained
@JaredOwen
13.2M views•2021-12-11
Related Study Plans & Knowledge Roadmaps
Structured learning paths in Computer Science
























![More I/O devices: Interrupt controller and timers - 16-bit Intel x86 breadboard computer [part 6]](https://i.ytimg.com/vi/8G3bwkIS3do/sddefault.jpg)













![[UR] COAL Final Prep Guide, Fall 2024 FAST NUCES LHR](https://i.ytimg.com/vi/cHmH-_l3bF4/sddefault.jpg)
