Emulando Linus Torvalds: Crie seu próprio sistema operacional do zero (VI)

Bem, depois de alguns parênteses, continuamos com nossa série de tutoriais. Se voltarmos ao código anterior, devemos ter o ISR da divisão por zero. Agora devemos preencher o restante dos ISRs para os quais postamos (os primeiros 32). Bem, agora vamos continuar com as interrupções de programação, vamos fazer o IRQ também conhecido como Interrompe solicitações. Esses IRQs são gerados por dispositivos de hardware, como teclados, mouses, impressoras, etc. Inicialmente, os primeiros 8 IRQs são mapeados automaticamente para as posições IDT 8 a 15. Como usamos os primeiros 32 para exceções, agora temos que remapea-los. Colocaremos o IRQ de 32 a 45. Para isso devemos primeiro remapear os 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);
}

Agora criamos uma função para instalar os 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");
}

A sentença de asm sti ativamos os IRQs. Bem, agora vamos com algo semelhante ao ISR. As funções de um IRQ básico:

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

Uma parte comum (igual a 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"
);
}

E um manipulador básico:

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);
}

Com isso já devemos ter o IRQ ativado mesmo que eles ainda não façam nada. No próximo capítulo, veremos como obter dados desses IRQs, como o relógio ou o teclado.

PróximoDivel-IRQ


E com isso termina o post de hoje. Como você pode ver agora, escrevo com menos regularidade devido a outros problemas. Mesmo assim vou continuar até ter um sistema operacional mais completo


Deixe um comentário

Seu endereço de email não será publicado. Campos obrigatórios são marcados com *

*

*

  1. Responsável pelos dados: Miguel Ángel Gatón
  2. Finalidade dos dados: Controle de SPAM, gerenciamento de comentários.
  3. Legitimação: Seu consentimento
  4. Comunicação de dados: Os dados não serão comunicados a terceiros, exceto por obrigação legal.
  5. Armazenamento de dados: banco de dados hospedado pela Occentus Networks (UE)
  6. Direitos: A qualquer momento você pode limitar, recuperar e excluir suas informações.

  1.   aitor_cz dito

    Muito obrigado Adrian, assim que tiver algum tempo (agora estou bastante ocupado, entre outras coisas também com um sistema operacional) vou começar a testar o tutorial passo a passo.

  2.   Ruby dito

    Muito obrigado pelo tute.

  3.   sasuke dito

    Uma pergunta, estou fazendo um projeto baseado nessas linguagens de programação
    * Html5
    * Css3
    *Java
    Minha pergunta é se eu gostaria que este projeto fosse executável, para que os usuários o usem em sistemas operacionais como Linux e Windows, você poderia me dizer como eu faço isso

    1.    AdrianArroyoStreet dito

      Não tem nada a ver com isso, mas eu respondo mesmo assim. Acho que será HTML5, CSS3 e JavaScript, não Java, já que HTML5 e Java se dão mal. Com HTML5 você pode criar sites como antes que são acessados ​​da internet. Se você quiser torná-lo local, pode empacotá-lo como um aplicativo Firefox OS e Chrome OS. Se o que você quer é que em cada sistema operacional haja um executável dado uma olhada no XUL Runner que é uma ferramenta para executar o XUL (e portanto HTML5 dentro do elemento) com o motor Gecko.

    2.    Soid Pérez dito

      O quadro ou painel Java é uma opção muito boa. Eu criei alguns aplicativos executáveis ​​em janela usando as classes do java frame como um navegador da web, mas em vez de usá-lo para qualquer página, dou um caminho direto no código e com php eu executo frases em java através de um .jar que cuida do aço. Embora eu recomende usar HTML5, CSS3 e JavaScript, já que, como diz Adrian Java, leva Fatal com Html5 e me trouxe muitas dores de cabeça

  4.   urbano dito

    Um tutorial sobre como fazer sua própria linguagem de programação seria bom

  5.   Ivan dito

    Muito boa essa série de artigos sobre como construir um sistema operacional, você aprende muitas coisas. Estou ansioso para a próxima entrada, já quero ter um teclado no sistema operacional. Tenho mexido no código git e não consegui fazê-lo funcionar com as portas 0x60 e 0x64. Mesmo pensando que para o teclado houve uma interrupção que te deu a tecla pressionada.

    1.    AdrianArroyoStreet dito

      Na verdade, você pode obter entrada do teclado sem interrupção, mas deve ler com ND :: Ports :: InputB na porta 0x60. No entanto, a maneira ideal de fazer isso é com interrupções de IRQ. No momento, estou tentando fazer isso e está demorando um pouco mais para continuar por causa disso.

      1.    carlosorta dito

        Olá Adrian, Tenho verificado o código e estou impressionado com o que faz e como me ajudou a compreender algumas coisas.

        Tenho algumas pequenas dúvidas sobre como funciona e a fonte é a que peguei no seu GIT:

        1.- Na parte IRQ, você mencionou que as posições de 0 a 32 do IDT foram usadas para exceções e de 32 (0x20) a 45 (0x2D) para IRQs, mas os IRQs são 16 no total, o remapeamento não seria de 0x20 a 0x30?

        2.- Na parte IRQ, note que os setgates foram enviados para a secção IDT; Ao separá-los, observe que não produz mais a exceção da divisão por 0, portanto, é necessário adicionar o IDT Flush () para cada modificação feita. Por que o IDT muda ao definir o Timer e a divisão entre 0 para de funcionar?

        3.- Eu estava tentando rastrear o código com alguma impressão para tomar como uma indicação do que ele está executando (para não depurar passo a passo) e percebi que nenhum IRQ está rodando, devo registrar algo mais às interrupções IRQ geradas?

        1.    carlosorta dito

          Esqueci de mencionar que encontrei estes links com informações:
          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

          Aparentemente, para lidar com IRQs, é necessário levar em consideração que tipo de manipulador é usado se, PIC, APIC, IOAPIC. . .etc. Existe uma maneira de dinamizar o gerenciamento de IRQ ou você precisa tentar a sorte?

  6.   carlosorta dito

    Boa tarde Adrian.

    Vi que tinha problemas com os IRQs e por isso o código não podia ser avançado, tirei uma cópia do projeto e comecei a analisá-lo; Acrescentei uma função à tela para imprimir os registros reg de struct reg, no momento da interrupção; Encontrei várias coisas, entre elas que um registro está em execução e ainda não consigo descobrir o porquê; mude a interrupção do Timer para a interrupção do teclado para fazer testes e faz o que deveria mas não consigo encontrar o problema, você poderia me ajudar e continuar com este bom post? 😀

    Deixo o link (ele tem algumas modificações porque uso a Mageia e uso o Grub2, estou usando o VirtualBox para testá-lo)
    https://www.mediafire.com/?93psrgaoozatse8

    Aguardando sua resposta atenciosa e se você tiver alguma dúvida ou precisar de algo, gostaria de ajudar 🙂

    1.    carlosorta dito

      Esqueci de mencionar que também verifiquei o KernelPanic porque os ISRs não funcionaram e estou com o mesmo problema no topo da pilha um valor está sendo filtrado e não sei se é meu compilador ou se há um problema, eu use GCC 4.8.2 com Mageia 4

    2.    AdrianArroyoStreet dito

      Gosto muito que você me ajude no projeto. Eu realmente fiquei preso no Timer e não entendo por que ele não funciona. Fiz testes modificando algumas coisas e não deu certo. Atualmente não consigo editar o código (estou de férias), mas vou dar uma boa olhada nele assim que puder. Apresento um link com informações sobre esse problema que parece ser comum: http://wiki.osdev.org/I_Cant_Get_Interrupts_Working

      Em relação às exceções, acho que me lembro que você tem que fazer uma chamada para "sti" no ASM para ativá-las, embora seja claro que há algo errado em algum lugar.

      1.    carlosorta dito

        Obrigado pela sua resposta e sim, de fato. As interrupções estavam falhando mas havia um problema na inserção dos códigos na pilha e um problema de casting, vou verificar o link e irei fazer testes. Se eu resolver, avisarei você e, caso contrário, informarei sobre o progresso. Boas Festas 🙂

      2.    carlosorta dito

        Não vai ter como ver o código montado? Algo estranho está acontecendo e eu não consigo encontrar o quê? Olha essa tela (coloquei o link no final), é algo estranho já que na função IRQ 2 (o teclado ) ele insere na pilha o valor 0 e 0x20 (32, portanto, ajuste-o para teste), em seguida, pushal (os registradores GPR de 32 bits) seguido pelos registradores de segmentação e, em seguida, no topo da pilha e, em seguida, chame o IRQ Handler. Comecei a ver cada pilha e aparentemente está em ordem, mas se você pode ver a saída da VM você pode ver que ela empilha mais um elemento, não consigo encontrar onde, só sei que é um 0x10 e a estrutura fica fora de serviço. Esta é a estrutura do registro.

        struct regs {
        uint32_t gs, fs, es, ds; / * empurrou os últimos segundos * /
        uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; / * empurrado por 'pushal' * /
        uint32_t int_no, err_code; /* Erro de código */
        uint32_t eip, cs, eflags, useresp, ss; / * Stacked on break * /
        };

        Incomoda-me que coloque mais um elemento no topo e não consigo encontrar onde está empilhado se aparentemente tudo está empilhado como deveria. Você tem alguma ideia do que poderia ser?

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

  7.   carlosorta dito

    Faça a interrupção do teclado funcionar, mas não a interrupção do cronômetro; o erro estava na forma como foi compilado, usei objdump para ver o objeto final e descobri que cada função que foi inserida, mesmo usando "asm volatile", também foi acompanhada por um pushl ebp, mov ebp, esp. Em seguida, basta adicionar um popl ebp a ele para restaurar a pilha inicial e ele passará os argumentos sem falha. Anexo aqui o código para quem quiser conferir e se puder descobrir porque não há interrupção devido ao Timer, adoraria saber e anexo um link onde falam sobre multitarefa http://www.jamesmolloy.co.uk/tutorial_html/9.-Multitasking.html
    Próximo Divel
    https://www.mediafire.com/?kmo83dxyzc7c3cz

    1.    AdrianArroyoStreet dito

      Consegui. Foi um bug em outro local que afetou a ativação do Timer PIC, especificamente no remapeamento do IRQ houve duas linhas que tive que modificar. Graças ao fato de que pude ver um código em um site que naquele ponto tinha algo diferente e clique! A mudança foi no sentido de:
      ND :: Ports :: OutputB (PIC1 + 1, 0xFF);
      ND :: Ports :: OutputB (PIC2 + 1, 0xFF);

      Você teve que alterar o valor de 0xFF (eu diria que indica desativado) para 0x00 (eu diria que indica ativado), embora eu não tenha certeza, mas funciona. Eu atualizei o código no GitHub. Muito, muito obrigado por me ajudar com o projeto que eu abandonei um pouco por conta desse problema. H

      1.    carlosorta dito

        De nada, aguardarei a próxima atualização sobre o assunto e você pode contar comigo para qualquer coisa 🙂 (S)

      2.    carlosorta dito

        Altere a rotina de captura de cordas do teclado; porque está lendo quando a tecla é liberada e monta um 0 no buffer, isso dá problemas na leitura e no final o '\ n' muda para »para que a impressão correta funcione

  8.   Soid Pérez dito

    Olá, eu li seu post inteiro, embora na prática não seja mais que 2 post, é realmente muito bom, salve tudo, mas eu realmente precisarei estudar c ++ e posix para entender porque eu conheço "c" (Estou fascinado por essa linguagem de programação) mas embora c ++ seja c OO eu nunca realmente trabalhei nisso, leia alguns tutoriais no google e então eu retorno isso muito interessante e uma pergunta, a inicialização da janela é semelhante ao linux?

    1.    AdrianArroyoStreet dito

      A inicialização no Windows é semelhante no sentido de que esta é a maneira de inicializar um sistema com um processador x86 e o ​​sistema operacional construído nele tem pouca influência. Na verdade, não estamos iniciando o GRUB, estamos iniciando o GRUB para nós. GRUB, projetado para inicializar o Linux, pode inicializar o Windows e, neste caso, o NextDivel.

      1.    tão idiota dito

        ok obrigado isso significa que o que eu quero fazer é possível já estou estudando c ++ e já criei alguns aplicativos e instalei seu sistema em um pendrive e estou estudando com mais detalhes é um post muito bom