Emulating Linus Torvalds: Create your own operating system from scratch (VI)

Well, after a little parenthesis we continue with our series of tutorials. If we return to the previous code, we must have the ISR of the division by zero. Now we must fill in the rest of the ISRs for which we had posted a message (the first 32). Well now we are going to continue programming interruptions, we are going to do the IRQs also known as Interrupt Requests. These IRQs are generated by hardware devices such as keyboards, mice, printers, etc. Initially the first 8 IRQs are automatically mapped to IDT positions 8 to 15. As we have used the first 32 for exceptions now we have to remap them. We will put the IRQ from 32 to 45. For this we must first remap the IRQs:

void ND::IRQ::Remap(int pic1, int pic2)
{
#define PIC1 0x20
#define PIC2 0xA0
#define ICW1 0x11
#define ICW4 0x01
/* send ICW1 */
ND::Ports::OutputB(PIC1, ICW1);
ND::Ports::OutputB(PIC2, ICW1);
/* send ICW2 */
ND::Ports::OutputB(PIC1 + 1, pic1); /* remap */
ND::Ports::OutputB(PIC2 + 1, pic2); /* pics */
/* send ICW3 */
ND::Ports::OutputB(PIC1 + 1, 4); /* IRQ2 -> connection to slave */
ND::Ports::OutputB(PIC2 + 1, 2);
/* send ICW4 */
ND::Ports::OutputB(PIC1 + 1, ICW4);
ND::Ports::OutputB(PIC2 + 1, ICW4);
/* disable all IRQs */
ND::Ports::OutputB(PIC1 + 1, 0xFF);
}

Now we create a function to install the IRQs:

void ND::IRQ::Install()
{
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_BLACK);
ND::Screen::PutString("\nInstalling IRQ...");
ND::IRQ::Remap(0x20,0x28);
ND::IDT::SetGate(32,(unsigned)ND::IRQ::IRQ1,0x08,0x8E);
ND::IDT::SetGate(33,(unsigned)ND::IRQ::IRQ2,0x08,0x8E);
ND::IDT::SetGate(34,(unsigned)ND::IRQ::IRQ3,0x08,0x8E);
ND::IDT::SetGate(35,(unsigned)ND::IRQ::IRQ4,0x08,0x8E);
ND::IDT::SetGate(36,(unsigned)ND::IRQ::IRQ5,0x08,0x8E);
ND::IDT::SetGate(37,(unsigned)ND::IRQ::IRQ6,0x08,0x8E);
ND::IDT::SetGate(38,(unsigned)ND::IRQ::IRQ7,0x08,0x8E);
ND::IDT::SetGate(39,(unsigned)ND::IRQ::IRQ8,0x08,0x8E);
ND::IDT::SetGate(40,(unsigned)ND::IRQ::IRQ9,0x08,0x8E);
ND::IDT::SetGate(41,(unsigned)ND::IRQ::IRQ10,0x08,0x8E);
ND::IDT::SetGate(42,(unsigned)ND::IRQ::IRQ11,0x08,0x8E);
ND::IDT::SetGate(43,(unsigned)ND::IRQ::IRQ12,0x08,0x8E);
ND::IDT::SetGate(44,(unsigned)ND::IRQ::IRQ13,0x08,0x8E);
ND::IDT::SetGate(45,(unsigned)ND::IRQ::IRQ14,0x08,0x8E);
ND::IDT::SetGate(46,(unsigned)ND::IRQ::IRQ15,0x08,0x8E);
ND::IDT::SetGate(47,(unsigned)ND::IRQ::IRQ16,0x08,0x8E);
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_GREEN);
ND::Screen::PutString("done");
asm volatile("sti");
}

The sentence of asm sti we activate the IRQs. Well now we go with something similar to ISR. The functions of a basic IRQ:

void ND::IRQ::IRQ1()
{
asm volatile(
"cli \n"
"pushl 0\n"
"pushl 32\n"
"jmp ND_IRQ_Common"
);
}

A common part (same as ISR):

extern "C"
void ND_IRQ_Common()
{
asm volatile(
"pusha \n"
"push %ds\n"
"push %es\n"
"push %fs\n"
"push %gs\n"
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movl %esp, %eax \n"
"push %eax \n"
"movl $ND_IRQ_Handler, %eax \n"
"call *%eax \n"
"popl %eax \n"
"popl %ds \n"
"popl %es \n"
"popl %fs \n"
"popl %gs \n"
"popa \n"
"addl 8, %esp \n"
"iret \n"
);
}

And a basic handler:

extern "C"
void ND_IRQ_Handler(struct regs* r)
{
void (*handler)(struct regs *r);
if(r->int_no >= 40)
{
ND::Ports::OutputB(0xA0,0x20);
}
ND::Ports::OutputB(0x20,0x20);
}

With this we should already have the IRQ activated even if they still do not do anything. In the next chapter we will see how to obtain data from these IRQs such as the clock or the keyboard.

NextDivel-IRQ


And with this ends today's post. As you can see now I write less regularly due to other issues. Even so I will continue until I have a more complete operating system


Leave a Comment

Your email address will not be published. Required fields are marked with *

*

*

  1. Responsible for the data: Miguel Ángel Gatón
  2. Purpose of the data: Control SPAM, comment management.
  3. Legitimation: Your consent
  4. Communication of the data: The data will not be communicated to third parties except by legal obligation.
  5. Data storage: Database hosted by Occentus Networks (EU)
  6. Rights: At any time you can limit, recover and delete your information.

  1.   aitor_cz said

    Thank you very much Adrian, as soon as I have some time (now I am quite busy, among other things also with an operating system) I will start to test the tutorial step by step.

  2.   Ruby said

    Thank you very much for the tute.

  3.   sasuke said

    One question I am doing a project based on these programming languages
    * Html5
    * Css3
    *Java
    My question is I would like this project to be executable, so users use it in operating systems such as linux and windows, could you tell me how I do that

    1.    AdrianArroyoStreet said

      It has nothing to do with this but I answer you anyway. I assume it will be HTML5, CSS3, and JavaScript not Java, as HTML5 and Java get along fatally. With HTML5 you can create websites as before that are accessed from the internet. If you want to make it local you can package it as a Firefox OS and Chrome OS app. If what you want is that in each operating system there is an executable taken a look at XUL Runner which is a tool to execute XUL (and therefore HTML5 inside the element) with the Gecko engine.

    2.    Soid perez said

      Java frame or panel is a very good option I have created some executable apps in window using the java frame classes as a web browser but instead of using it for any page I give it a direct path in the code and with php I execute java sentences through of a .jar that takes care of steel. Although I would recommend using HTML5, CSS3 and JavaScript since as Adrian Java says it takes Fatal with Html5 and it brought me many headaches

  4.   urban said

    A tutorial on how to make your own programming language would be nice

  5.   Ivan said

    Very good this series of articles on how to build an operating system, you learn many things. I'm looking forward to the next entry, I already want to have a keyboard in the OS. I've been messing around with the git code, and I haven't been able to get it to work with port 0x60 and 0x64. Even though I thought that for the keyboard there was an interruption that gave you the pressed key.

    1.    AdrianArroyoStreet said

      You can actually get keyboard input without interruption, but you must read with ND :: Ports :: InputB on port 0x60. However the ideal way to do this is with IRQ interrupts. I am currently trying to do it and it is taking a little longer to continue because of that.

      1.    carlosorta said

        Hi Adrian, I've been checking the code and I'm impressed with what it does and how well it has helped me to understand some things.

        I have a few small questions about how it works and the source is the one I got from your GIT:

        1.- In the part of the IRQs, you mentioned that the positions from 0 to 32 of the IDT were used for exceptions and from 32 (0x20) to 45 (0x2D) for the IRQs, but the IRQs are 16 in total , the remaping would not be from 0x20 to 0x30?

        2.- In the IRQ part, note that the setgates were sent to the IDT section; When you separate them, notice that it no longer produces the exception of division by 0, so it is necessary to add the IDT Flush () for each modification that is made. Why when setting the Timer the IDT is altered and the division between 0 stops working?

        3.- I was trying to trace the code with some printing to take as an indication of what it is executing (so as not to be debugging step by step) and I realized that no IRQ is running, do I have to register something else to IRQ interrupts generated?

        1.    carlosorta said

          I forgot to mention that I found these links with information:
          http://arstechnica.com/civis/viewtopic.php?f=20&t=899001
          http://www.superfrink.net/athenaeum/OS-FAQ/os-faq-pics.html
          http://orga2.exp.dc.uba.ar/data/downloads/clasespracticas/interrupciones2_clase_17.pdf
          http://www.intel-assembler.it/PORTALE/4/231468_8259A_PIC.pdf

          Apparently for handling IRQs, it is necessary to take into account what type of handler is used if, PIC, APIC, IOAPIC. . .etc. Is there a way to make a dynamic of IRQ management or do you need to try luck?

  6.   carlosorta said

    Good afternoon Adrian.

    I saw that I had problems with the IRQs and that is why the code could not be advanced, I took a copy of the project and I began to analyze it; I added a function to the screen printing to print the reg records of struct reg, at the moment of making the interruptions; I found several things, among them that a registry is running and I still can't find why; change the Timer interrupt for the keyboard interrupt to test and do what it should but I can't find the problem, could you help me and continue with this good post? 😀

    I leave the link (it has some modifications because I use Mageia and I use Grub2, I am using VirtualBox to test it)
    https://www.mediafire.com/?93psrgaoozatse8

    Waiting for your attentive response and if you have any questions or need something I would like to help 🙂

    1.    carlosorta said

      I forgot to mention that I also checked the KernelPanic because the ISRs did not work and I have the same problem at the top of the stack a value is being filtered and I do not know if it is my compiler or there is a problem, I use GCC 4.8.2 with Mageia 4

    2.    AdrianArroyoStreet said

      I really like that you help me in the project. I really got stuck in the Timer and I don't understand why it doesn't work. I did tests modifying quite a few things and it didn't work out. Currently I can't edit code (I'm on vacation away) but I'll take a good look at it as soon as I can. I give you a link with information about this problem that seems to be something common: http://wiki.osdev.org/I_Cant_Get_Interrupts_Working

      Regarding the exceptions, I think I remember that you have to make a call to "sti" in ASM to activate them although it is clear that there is something wrong somewhere.

      1.    carlosorta said

        Thanks for your answer and yes, indeed. The interrupts were failing but it was a problem inserting the codes in the stack and a casting problem, I will check the link and I will be doing tests. If I solve it I will let you know and if not I will inform you of progress. Happy Holidays 🙂

      2.    carlosorta said

        There will be no way to see the assembled code? Is something strange happening and I can't find what? Look at this screen (I put the link at the end), it is something strange since in the IRQ 2 function (the keyboard) it enters the Stack the value 0 and 0x20 (32, so fit it to test) then pushal (the 32-bit GPR registers) followed by the segmentation registers and then the top of the stack and then call IRQ Handler. I started to see each stack and apparently it is in order but if you can see the output of the VM you can see that it stacks one more element, I can't find where, I just know that it is a 0x10 and the structure gets out of order. This is the record structure.

        struct regs {
        uint32_t gs, fs, es, ds; / * pushed the secs last * /
        uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; / * pushed by 'pushal' * /
        uint32_t int_no, err_code; /* Error code */
        uint32_t eip, cs, eflags, useresp, ss; / * Stacked on break * /
        };

        It gives me a can that puts one more element at the top and I can't find where it is stacked if apparently everything is stacked as it should be. Do you have any idea what it could be?

        http://www.subeimagenes.com/img/sin-titulo-1036729.jpg

  7.   carlosorta said

    Get the keyboard interrupt to work but not the timer interrupt; the error was in the way it is compiled, I used objdump to see the final object and it turned out that every function that was entered even using "asm volatile" was also accompanied by a pushl ebp, mov ebp, esp. Then just add a popl ebp to it to restore the initial stack and it will pass the arguments without fail. Here I attach the code for those who want to check it and if you can find out why the interruption is not generated by the Timer I would love to know it and I attach a link where they talk about multitasking http://www.jamesmolloy.co.uk/tutorial_html/9.-Multitasking.html
    Next Level
    https://www.mediafire.com/?kmo83dxyzc7c3cz

    1.    AdrianArroyoStreet said

      I got it. It was a bug in another place that affected the activation of the Timer PIC, specifically in the IRQ remap there were two lines that I had to modify. Thanks to the fact that I could see a code on a website that at that point had something different and click! The change was along the lines of:
      ND :: Ports :: OutputB (PIC1 + 1, 0xFF);
      ND :: Ports :: OutputB (PIC2 + 1, 0xFF);

      You had to change the value from 0xFF (I would say it indicates disabled) to 0x00 (I would say it indicates enabled) although I'm not really sure, but it works. I have updated the code on GitHub. Thank you very, very much for helping me with the project that I had a little abandoned due to this problem. H

      1.    carlosorta said

        You're welcome, I'll look forward to the next update of the topic and you can count on me for anything 🙂 (Y)

      2.    carlosorta said

        Change the keyboard string capture routine; because it is reading when the key is released and it mounts a 0 in the buffer, that gives problems in the reading and at the end the '\ n' change it to »so that the correct printing works

  8.   Soid perez said

    Hello, I read your entire post, although in practice it is no more than 2 post, it is really very good, save everything but I really will need to study c ++ and posix to understand it because I know about "c" (I am fascinated by that programming language) Although c ++ is c OO I have never really worked on it, read me some tutorials in google and then I come back this very interesting and a question, is the window startup similar to linux?

    1.    AdrianArroyoStreet said

      Booting in Windows is similar in the sense that this is the way to boot a system with an x86 processor and the operating system built on it has little influence. We're not really booting ourselves anyway, it's starting GRUB for us. GRUB, designed to boot Linux, can boot Windows and in this case NextDivel.

      1.    sound said

        ok thanks that means that what I want to do is possible I am already studying c ++ and I have created some apps and installed your system on a pendrive and I am studying it in more detail is a very good post