Quase quatro meses depois tenho uma nova versão do sistema. Antes de apresentar o que mudou, vou mostrar algumas estatísticas sobre os arquivos.
Na versão anterior (0.3.1) eram 10 arquivos, com 1824 linhas de código em bruto (contando linhas em branco) e 1496 linhas efetivas (descontando linhas em branco, mas contando comentários).
Já nesta versão (0.4) são nada menos que 23 arquivos, com 6073 linhas em bruto e 4812 linhas efetivas. O tamanho do binário final também mudou, foi de 12 KB para 32 KB, com tamanho de imagem (contando a seção BSS) indo de 16 KB para 36K.
Mas o que mudou tanto? Como o título sugere, foi uma jornada dura, que pouca coisa ou nada aparece, mas a parte fundamental do "prédio" está bem definida agora. Visualmente nada mudou:
O que marcou esta versão foi a inclusão de algumas bibliotecas, a maioria terá funcionalidade tanto dentro do kernel, quanto em quaisquer programas que fizermos para o sistema, além da parte fundamental de qualquer SO, as chamadas de sistema. Talvez isto tenha sido o mais importante.
A chamada de sistema é a forma com que um aplicativo rodando em espaço de usuário requisita serviços do kernel, atualmente há diversas (algumas) formas de se fazer isso (Interrupções, Instruções específicas - SYSCALL, bibliotecas compartilhadas - DLLs). Cada sistema faz da sua maneira, mas a forma que acho mais simples é por interrupção, além de ser compatível com máquinas mais antigas, como um 486 por exemplo (eu tenho um!).
Talvez me perguntem, porque está preocupado com as chamadas de sistema agora, se ainda falta muita coisa para conseguir rodar um aplicativo no sistema?
A resposta é bem simples, como estou implementado diversas bibliotecas (units) que podem ser usadas tanto no espaço kernel quanto no espaço usuário, a única forma de fazê-lo sem complicações futuras é escrever tais bibliotecas já utilizando chamadas de sistema.
Para exemplificar melhor vou descrever, de forma sucinta, cada biblioteca/unit. Começarei pela maior e mais complexa no momento, ConsoleIO.
Como já citei em outros posts, pretendo utilizar algumas características dos sistemas LINUX/UNIX, tais como sistema de arquivos montado, dispositivos tratados como arquivos, e terminais. Pois acho interessante desta forma.
Um terminal/console possui diversas funcionalidades, como mudar a cor da fonte/fundo, reposicionar o cursor, limpar a tela, etc. Essas funcionalidades são providas pela biblioteca ConsoleIO, que fornece rotinas como CWrite, CWriteln, CGotoXY, CSetColor, CSetBackground. Tais rotinas facilitam a implementação de quaisquer programas pois todo o protocolo de terminal está resolvido dentro da própria biblioteca.
Como todo dispositivo é tratado como arquivo, o terminal também o é, desta forma ConsoleIO utiliza outra biblioteca para acessar o arquivo do terminal, StdIO, esta possui função semelhante à sua versão na linguagem C, ou seja, possui todos os procedimentos relacionados com entrada e saída.
StdIO, assim como StdLib, são bibliotecas padrão. Note que os nomes são de bibliotecas da linguagem C, mas não são bibliotecas padrão do compilador e sim do sistema. Será utilizando essa duas, e mais algumas, que qualquer programa rodando no sistema se comunicará com o kernel.
Voltando a StdIO, esta possui toda as funcionalidades de entrada e saída do sistema, ela fornece rotinas como FOpen, FClose, FRead e FWrite. Tais rotinas são utilizadas para abrir, fechar, ler e gravar qualquer arquivo.
StdLib, possuirá a maioria das funcionalidades do sistema, como Abort, Exit, Fork (para cria subprocessos), Exec, etc. No entanto somente Abort está implementada no momento.
A diferença entre Abort e Exit (não confundir com o Exit do Pascal, que sai do procedimento atual) é que Exit encerra o processo de forma normal e Abort termina o processo com depuração, ou seja, Exit termina o processo e não mantem quaisquer informações sobre o processo enquanto Abort fará um despejo de memória para um arquivo de depuração, de forma que o erro possa ser depurado. Quando Abort é invocada dentro do próprio kernel, ela provoca um KernelPanic.
Outra biblioteca grande é DebugInfo, esta como o nome sugere é responsável por coletar dados para a depuração.
As bibliotecas citadas até o momento podem tanto serem usadas por aplicativos quanto pelo próprio kernel, pois elas utilizam chamadas de sistema, através da biblioteca SysCalls.
SysCalls é responsável por interfacear as chamadas de sistema, ela provê rotinas que fazem as chamadas de sistema. Dessa forma, não importa como serão as chamadas de sistema, basta que SysCalls esteja atualizada para a versão atual das chamadas, que todas as bibliotecas que dependem dela funcionarão.
Dentro do kernel, SysCalls não faz qualquer chamada de sistema, ela somente encaminha os parâmetros para outra rotina, DirectCall, na unit SystemCalls.
SystemCalls é interface do lado kernel das chamadas de sistema, nela será implementado as rotinas de tratamento das chamadas. DirectCall possibilita ao próprio kernel utilizar tais chamadas, de forma que não é necessário ter rotinas independentes para aplicativos e kernel.
Tanto SysCalls quanto SystemCalls utilizam outra unit SysCallsDef. Esta possui somente a numeração das chamadas de sistema disponíveis.
Outras units "DEF" também são utilizadas no sistema, todas com a finalidade de compartilhar definições que são utilizadas em mais de um lugar.
ErrorsDef possui todos os códigos de erro de todas as bibliotecas, a variável ErrorNo que armazena o último erro ocorrido e a função GetErrorString que devolve uma string informativa do erro, atualmente o próprio identificador, mas que pode ser modificado para um texto mais explicativo.
SystemDef possui definições de tipos utilizados em diversas partes do sistema, como em chamadas de sistema. E por último TTYsDef que possui definições utilizadas em terminais, como cores e caracteres de controle.
Do lado kernel, agora há uma biblioteca principal, KernelLib, que possuirá todas as rotinas independentes utilizadas pelo kernel, ou seja, no kernel em si ficará somente a rotina de inicialização e alguma outra principal, todas as rotinas auxiliares estarão em KernelLib.
Temos também FileSystem que será responsável pelo sistema de arquivo (lógico né?), mas que no momento apenas fornece acesso a dois arquivos fictícios, "/dev/null" e "/dev/grosstty", um é um arquivo nulo e outro o "driver" de terminal.
GrossTTY é o driver de terminal que vem para substituir KrnlTTY. Isto porque inicialmente KrnlTTY seria somente usado para o kernel, mas como notei que seria demasiadamente trabalhoso ter dois "drivers" para a mesma função resolvi utilizar o meio citado acima (ConsoleIO => StdIO => SysCalls) também para o kernel.
GrossTTY já tem "a cara" de driver, pois possui apenas três procedimentos na interface, GrossTTYInit, GrossTTYRead e GrossTTYWrite. Init é chamada pelo kernel para inicializar o driver, enquanto Read e Write é utilizada pela FileSystem para ler e escrever no driver.
GrossCRT ficou agora "interna" a GrossTTY, pois não é mais utilizada diretamente por qualquer outra unit. Futuramente haverá dois drivers, um de terminal e outro de vídeo, nesse ponto já será possível ter diversos consoles no sistema.
Quando os drivers forem realmente drivers e não somente units, eles terão, possivelmente, somente quatro rotinas que deverão ser linkadas dinamicamente (no carregamento do driver), Init, Read, Write e IOCTL.
De mais, apenas houve algumas alterações nos arquivos de configuração, incluindo a seção /DISCARD/ no lugar de TRASH, no arquivo de configuração do linker. Agora realmente o que não é útil está sendo descartado.
Embora o post tenha ficado grande, é só isso que tenho para apresentar por enquanto e, a próxima postagem somente sairá em Novembro, pois vou aproveitar esse último mês para estudar mais para o Enem. Quem sabe na próxima já tenhamos o gerenciador de memória (Heap), assim poderemos a ter variáveis dinamicamente alocadas. Até mais pessoal. :D
Edit: Após organizar os repositórios no github, modifiquei a funcionalidade dos pacotes (seguindo os repositórios), assim o pacote "kernel" tem somente o kernel do SO, e o pacote "system" possui agora todas as partes necessárias para funcionamento do sistema (ex.: kernel, bootloader, shell, ...).
Próximo - Kernel, fase 4 - Limpando o caminho >>
<< Anterior - Kernel, fase 2 - Abastecendo o tinteiro
Voltar a Faça seu próprio sistema operacional.
Na versão anterior (0.3.1) eram 10 arquivos, com 1824 linhas de código em bruto (contando linhas em branco) e 1496 linhas efetivas (descontando linhas em branco, mas contando comentários).
Já nesta versão (0.4) são nada menos que 23 arquivos, com 6073 linhas em bruto e 4812 linhas efetivas. O tamanho do binário final também mudou, foi de 12 KB para 32 KB, com tamanho de imagem (contando a seção BSS) indo de 16 KB para 36K.
Mas o que mudou tanto? Como o título sugere, foi uma jornada dura, que pouca coisa ou nada aparece, mas a parte fundamental do "prédio" está bem definida agora. Visualmente nada mudou:
O que marcou esta versão foi a inclusão de algumas bibliotecas, a maioria terá funcionalidade tanto dentro do kernel, quanto em quaisquer programas que fizermos para o sistema, além da parte fundamental de qualquer SO, as chamadas de sistema. Talvez isto tenha sido o mais importante.
A chamada de sistema é a forma com que um aplicativo rodando em espaço de usuário requisita serviços do kernel, atualmente há diversas (algumas) formas de se fazer isso (Interrupções, Instruções específicas - SYSCALL, bibliotecas compartilhadas - DLLs). Cada sistema faz da sua maneira, mas a forma que acho mais simples é por interrupção, além de ser compatível com máquinas mais antigas, como um 486 por exemplo (eu tenho um!).
Talvez me perguntem, porque está preocupado com as chamadas de sistema agora, se ainda falta muita coisa para conseguir rodar um aplicativo no sistema?
A resposta é bem simples, como estou implementado diversas bibliotecas (units) que podem ser usadas tanto no espaço kernel quanto no espaço usuário, a única forma de fazê-lo sem complicações futuras é escrever tais bibliotecas já utilizando chamadas de sistema.
Para exemplificar melhor vou descrever, de forma sucinta, cada biblioteca/unit. Começarei pela maior e mais complexa no momento, ConsoleIO.
Como já citei em outros posts, pretendo utilizar algumas características dos sistemas LINUX/UNIX, tais como sistema de arquivos montado, dispositivos tratados como arquivos, e terminais. Pois acho interessante desta forma.
Um terminal/console possui diversas funcionalidades, como mudar a cor da fonte/fundo, reposicionar o cursor, limpar a tela, etc. Essas funcionalidades são providas pela biblioteca ConsoleIO, que fornece rotinas como CWrite, CWriteln, CGotoXY, CSetColor, CSetBackground. Tais rotinas facilitam a implementação de quaisquer programas pois todo o protocolo de terminal está resolvido dentro da própria biblioteca.
Como todo dispositivo é tratado como arquivo, o terminal também o é, desta forma ConsoleIO utiliza outra biblioteca para acessar o arquivo do terminal, StdIO, esta possui função semelhante à sua versão na linguagem C, ou seja, possui todos os procedimentos relacionados com entrada e saída.
StdIO, assim como StdLib, são bibliotecas padrão. Note que os nomes são de bibliotecas da linguagem C, mas não são bibliotecas padrão do compilador e sim do sistema. Será utilizando essa duas, e mais algumas, que qualquer programa rodando no sistema se comunicará com o kernel.
Voltando a StdIO, esta possui toda as funcionalidades de entrada e saída do sistema, ela fornece rotinas como FOpen, FClose, FRead e FWrite. Tais rotinas são utilizadas para abrir, fechar, ler e gravar qualquer arquivo.
StdLib, possuirá a maioria das funcionalidades do sistema, como Abort, Exit, Fork (para cria subprocessos), Exec, etc. No entanto somente Abort está implementada no momento.
A diferença entre Abort e Exit (não confundir com o Exit do Pascal, que sai do procedimento atual) é que Exit encerra o processo de forma normal e Abort termina o processo com depuração, ou seja, Exit termina o processo e não mantem quaisquer informações sobre o processo enquanto Abort fará um despejo de memória para um arquivo de depuração, de forma que o erro possa ser depurado. Quando Abort é invocada dentro do próprio kernel, ela provoca um KernelPanic.
Outra biblioteca grande é DebugInfo, esta como o nome sugere é responsável por coletar dados para a depuração.
As bibliotecas citadas até o momento podem tanto serem usadas por aplicativos quanto pelo próprio kernel, pois elas utilizam chamadas de sistema, através da biblioteca SysCalls.
SysCalls é responsável por interfacear as chamadas de sistema, ela provê rotinas que fazem as chamadas de sistema. Dessa forma, não importa como serão as chamadas de sistema, basta que SysCalls esteja atualizada para a versão atual das chamadas, que todas as bibliotecas que dependem dela funcionarão.
Dentro do kernel, SysCalls não faz qualquer chamada de sistema, ela somente encaminha os parâmetros para outra rotina, DirectCall, na unit SystemCalls.
SystemCalls é interface do lado kernel das chamadas de sistema, nela será implementado as rotinas de tratamento das chamadas. DirectCall possibilita ao próprio kernel utilizar tais chamadas, de forma que não é necessário ter rotinas independentes para aplicativos e kernel.
Tanto SysCalls quanto SystemCalls utilizam outra unit SysCallsDef. Esta possui somente a numeração das chamadas de sistema disponíveis.
Outras units "DEF" também são utilizadas no sistema, todas com a finalidade de compartilhar definições que são utilizadas em mais de um lugar.
ErrorsDef possui todos os códigos de erro de todas as bibliotecas, a variável ErrorNo que armazena o último erro ocorrido e a função GetErrorString que devolve uma string informativa do erro, atualmente o próprio identificador, mas que pode ser modificado para um texto mais explicativo.
SystemDef possui definições de tipos utilizados em diversas partes do sistema, como em chamadas de sistema. E por último TTYsDef que possui definições utilizadas em terminais, como cores e caracteres de controle.
Do lado kernel, agora há uma biblioteca principal, KernelLib, que possuirá todas as rotinas independentes utilizadas pelo kernel, ou seja, no kernel em si ficará somente a rotina de inicialização e alguma outra principal, todas as rotinas auxiliares estarão em KernelLib.
Temos também FileSystem que será responsável pelo sistema de arquivo (lógico né?), mas que no momento apenas fornece acesso a dois arquivos fictícios, "/dev/null" e "/dev/grosstty", um é um arquivo nulo e outro o "driver" de terminal.
GrossTTY é o driver de terminal que vem para substituir KrnlTTY. Isto porque inicialmente KrnlTTY seria somente usado para o kernel, mas como notei que seria demasiadamente trabalhoso ter dois "drivers" para a mesma função resolvi utilizar o meio citado acima (ConsoleIO => StdIO => SysCalls) também para o kernel.
GrossTTY já tem "a cara" de driver, pois possui apenas três procedimentos na interface, GrossTTYInit, GrossTTYRead e GrossTTYWrite. Init é chamada pelo kernel para inicializar o driver, enquanto Read e Write é utilizada pela FileSystem para ler e escrever no driver.
GrossCRT ficou agora "interna" a GrossTTY, pois não é mais utilizada diretamente por qualquer outra unit. Futuramente haverá dois drivers, um de terminal e outro de vídeo, nesse ponto já será possível ter diversos consoles no sistema.
Quando os drivers forem realmente drivers e não somente units, eles terão, possivelmente, somente quatro rotinas que deverão ser linkadas dinamicamente (no carregamento do driver), Init, Read, Write e IOCTL.
De mais, apenas houve algumas alterações nos arquivos de configuração, incluindo a seção /DISCARD/ no lugar de TRASH, no arquivo de configuração do linker. Agora realmente o que não é útil está sendo descartado.
Embora o post tenha ficado grande, é só isso que tenho para apresentar por enquanto e, a próxima postagem somente sairá em Novembro, pois vou aproveitar esse último mês para estudar mais para o Enem. Quem sabe na próxima já tenhamos o gerenciador de memória (Heap), assim poderemos a ter variáveis dinamicamente alocadas. Até mais pessoal. :D
Edit: Após organizar os repositórios no github, modifiquei a funcionalidade dos pacotes (seguindo os repositórios), assim o pacote "kernel" tem somente o kernel do SO, e o pacote "system" possui agora todas as partes necessárias para funcionamento do sistema (ex.: kernel, bootloader, shell, ...).
Próximo - Kernel, fase 4 - Limpando o caminho >>
<< Anterior - Kernel, fase 2 - Abastecendo o tinteiro
Voltar a Faça seu próprio sistema operacional.
Cara, sem comentários. Parabéns e obrigado
ResponderExcluir