Em conexão com as análises negativas do artigo de teste “Desenvolvendo um OC do Microkernel Unix - Scheduler”, decidi
reiniciar a série de artigos, levando em consideração alguns comentários. Agora, tendo percebido meu público-alvo, fui capaz de mudar o foco da minha espécie para aqueles que realmente precisam.
Respostas aos comentários do artigo anterior.
Observação 1. O agendador é muito simples.
Desde a publicação do artigo anterior, o código mudou muito. Um núcleo de pleno direito foi formado, que deixou de ser micronuclear. Há suporte para o disco ram inicial (sistema de arquivos do kernel), suporte para memória virtual (MMU). Tornou-se possível para o kernel escrever programas personalizados. Havia chamadas do sistema e a biblioteca do clib (stdio, string). Portanto, o shell /initrd/sh.elf é um programa separado que é analisado pelo gerenciador de inicialização elf e é executado como um processo.
Lista de comandos do shell: exec <file.elf>, ps, kill, exit. Nesse caso, o shell pode ser iniciado a partir do próprio shell (demonstrando multitarefa).
Nota 2. Muita mágica nos bastidores nos tutoriais em vídeo.
Decidi destacar o texto que estou explicando atualmente. Ele também foi para iniciantes que precisam de esclarecimentos e das coisas mais simples. Honestamente, fiquei surpreso que os recém-chegados que não têm experiência em programação estejam interessados em um tópico tão complexo, embora seja um pecado esconder, comecei a partir daí. Mudei o viés de explicar meu sistema operacional para explicar como escrever seu OC.
Observação 3. Onde está o link para o
github ?
Agora ela é Na
descrição do vídeo no YouTube (sim, quero que você não passe pelos meus tutoriais em vídeo, pelo menos dê uma olhada).
Observação 4. Devemos começar com a montagem primeiro.
É isso que faremos.
Observação 5. Você não escreve nada, apenas comenta.
Sim, foi um erro falar sobre algo grande imediatamente. Agora vamos avançar passo a passo, gradualmente, começando com o kernel Hello world mais simples. As aulas em vídeo permitirão que você crie uma imagem holística do mundo, e o código-fonte no github o envolverá nos detalhes.
Sumário
1. Construa o sistema (marca, gcc, gás). Inicialização inicial (inicialização múltipla). Iniciar (qemu). Biblioteca C (strcpy, memcpy, strext).
2. Biblioteca C (sprintf, strcpy, strcmp, strtok, va_list ...). Construindo a biblioteca no modo kernel e no modo de aplicativo do usuário.
3. O log do sistema do kernel. Memória de vídeo Saída para o terminal (kprintf, kpanic, kassert).
4. Memória dinâmica, um monte (kmalloc, kfree).
6. Organização da memória e manipulação de interrupções (GDT, IDT, PIC, syscall). Exceções
5. Memória virtual (diretório e tabela de páginas).
6. O processo. Planejador Multitarefa. Chamadas do sistema (interrupção, saída, ps).
7. O sistema de arquivos do kernel (initrd), elf e seus internos. Chamadas do sistema (exec).
8. Drivers de dispositivo de caracteres. Chamadas do sistema (ioctl, fopen, fread, fwrite). Biblioteca C (fopen, fclose, fprintf, fscanf).
9. O shell como um programa completo para o kernel.
10. Modo de proteção do usuário (anel3). Segmento de status da tarefa (tss).
Vamos lá Parte 1. Construa o sistema e inicie
No artigo, listarei apenas as
principais etapas . Para uma explicação detalhada, consulte o tutorial em vídeo deste artigo.
Você precisa do Linux. Vamos coletar boa e velha marca. Para compilar o arquivo executável do kernel, são necessários os seguintes sinalizadores:
CC_FLAGS=-g -m32 -isystem $(IDIR) -I include -DKERNEL=1 -fno-stack-protector -Wall -Werror -fno-pie AS_FLAGS=-g --32 LD_FLAGS=-m elf_i386
Como um emulador de hardware, instale o emulador qemu no Linux. Vamos rodar nosso kernel assim:
qemu-system-i386 -kernel ./bin/kernel.elf
Também será necessário um pequeno script para o vinculador. É necessário para carregar seções no endereço correto e na ordem correta. Também nele indicaremos o ponto de entrada:
OUTPUT_FORMAT(elf32-i386) ENTRY(start) SECTIONS { . = 0x100000; .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } }
Como o kernel será carregado de acordo com a especificação de inicialização múltipla, o cabeçalho será necessário no início da seção de código:
.code32 .text # multiboot spec .align 4 multiboot: .long 0x1BADB002 # magic .long 0x00 # flags .long -(0x1BADB002 + 0x00) # checksum. m+f+c should be zero
É recomendável que você alterne imediatamente para sua própria pilha e configure uma tabela de descritor global. Defina nossa própria pilha:
.bss .fill 8192,1 # 8Kb stack:
Escreva um ponto de entrada. Você pode achar a sintaxe do assembler do gnu incomum. Uma vez eu também preferi a sintaxe da Intel, depois de a ter experimentado, investigando o código fonte do Linux, preferi completamente a sintaxe da AT&T para mim. O principal a lembrar é que eles têm operandos opostos. O resto será intuitivo.
start: cli movl $stack,%esp push %esp push %ebx /* address of struct multiboot_t */ call kernel_start /* should never return */ hlt
Isso completa o código padrão. A diversão começa. Agora podemos escrever o código em C. E antes de tudo, definiremos a mensagem de saudação.
char *hello = "Hello world!"; int screen_size = 80 * 25;
Em seguida, escrevemos o próprio ponto de entrada para o qual o código do assembler transferirá o controle:
/* * Api - Kernel entry point */ extern void kernel_start(struct multiboot_t* multiboot, void* kstack) { char *video = (char*)0xB8000; char buff[screen_size + 1]; video[screen_size] = '\0'; memset(buff, ' ', screen_size); strext(video, buff, 0x7); strext(video, hello, 0x7); }
Aqui, simplesmente exibimos a mensagem na tela. Em princípio, você pode copiar completamente o código da primeira lição, pois é um modelo e nunca será alterado. Para exibir algo na tela, basta gravá-lo diretamente na memória de vídeo, complementando cada caractere com um símbolo de atributo. Para fazer isso, você precisará de sua própria biblioteca C, que nós mesmos escreveremos para nossas necessidades. Portanto, será mais fácil controlar o processo. Por exemplo, hoje temos à nossa disposição 2 funções familiares (strcpy, memcpy) e uma de nossas próprias strext para inserir o atributo byte após cada caractere.
Conclusão
Isso é tudo por hoje. Assista ao tutorial em vídeo e tente fazer o mesmo por conta própria. Se não der certo, você pode procurar nas fontes da lição no github. Link para o
github na descrição do tutorial em vídeo:Literatura
1. James Molloy. Role seu próprio sistema operacional clone do UNIX de brinquedo.
2. Dentes. Assembler para DOS, Windows, Unix
3. Kalashnikov. Assembler é fácil!
4. Tanenbaum. Sistemas operacionais. Implementação e desenvolvimento.
5. Robert Love. Kernel Linux Descrição do processo de desenvolvimento.