Essa foi uma ótima curva de aprendizado que aparentemente me ajudou a promover mais idéias teóricas e conceituais em torno das teorias/leis sobre os mistérios subjacentes dos sistemas operacionais e dos kernels. Presumi que tive uma boa ideia de como os OSS funcionava. No entanto, criar meu próprio sistema operacional foi absolutamente muito mais definitivo em comparação com apenas ler sobre. Na minha opinião, opinião honesta. Essa foi uma maneira de ter uma melhor compreensão do software com o qual eu gostaria de mexer no modo de kernel e no modo de usuário.
Antes de começarmos, mesmo que o kernel e o sistema operacional sejam de 32 bits. Também explicarei conceitos em 64 bits, evidentemente um deles sendo o modo longo.
Modos
Interrompe
Descritores
Paginação
Leia mais sobre o modo protegido no Intel® 64 e IA-32 Architecture Software Developer Volume 3A: Guia de Programação do Sistema, Parte 1; Capítulo 3 *
O que são interrupções
Você pode pensar nas interrupções como um sinal ou dados que estão sendo enviados por um dispositivo como teclado, unidade de estado sólido, driver duro ou mouse e software que dizem à CPU que um evento aconteceu e precisa interromper imediatamente o que está fazendo atualmente, para prosseguir com o que o enviou a interrupção.
Por exemplo, quando você mover/clicar em um mouse, o controlador do mouse enviará uma interrupção para o controlador de interrupção para a CPU, a atenção da CPU irá imediatamente para a interrupção do mouse e prosseguirá para executar uma rotina (movimento do mouse ou clicar). Depois que o mouse interromper a CPU continuará fazendo o que fosse antes da interrupção ou irá gerenciar outra interrupção, se tiver sido sinal.
+------------------------+ +------------+
| TYPES OF INTERRUPTS |------------| Exceptions |
+------------------------+ +------------+
/
/
/
+------------+ +------------+
| HARDWARE | | SOFTWARE |
| INTERRUPTS | | INTERRUPTS |
+------------+ +------------+
Linhas de IRQ, ou IRQs baseados em pinos: elas são tipicamente roteadas estaticamente no chipset. Fios ou linhas são executadas dos dispositivos no chipset para um controlador IRQ que serializa as solicitações de interrupção enviadas pelos dispositivos, enviando -os para a CPU um por um para evitar corridas. Em muitos casos, um controlador IRQ enviará vários IRQs para a CPU de uma só vez, com base na prioridade do dispositivo. Um exemplo de um controlador IRQ muito conhecido é a cadeia de controladores Intel 8259, que está presente em todos os chipsets compatíveis com IBM-PC, encadeando dois controladores, cada um fornecendo 8 pinos de entrada para um total de 16 pinos de sinalização IRQ usáveis no Legacy IBM-PC.
Interrupções baseadas em mensagens: elas são sinalizadas escrevendo um valor para um local de memória reservado para obter informações sobre o dispositivo de interrupção, a própria interrupção e as informações de vetoramento. O dispositivo recebe um local ao qual grava por firmware ou pelo software Kernel. Em seguida, um IRQ é gerado pelo dispositivo usando um protocolo de arbitragem específico para o barramento do dispositivo. Um exemplo de um barramento que fornece funcionalidade de interrupção baseada em mensagens é o barramento PCI. Por wiki.osdev - https://wiki.osdev.org/Interrupts
Entrada - A entrada define uma região na memória onde iniciar, juntamente com o limite da região e os privilégios de acesso associados à entrada. Privilégio de acesso como processador de contar se o sistema operacional estiver em execução no sistema (anel 0) ou aplicação (anel 3). Ele impede que as aplicações ou o Usermode tenham acesso a determinados registros/operandos e mnemônicos. Como registros de CR e CLI/STI, respectivamente.
Limite - O tamanho do descritor do segmento
Seletor de segmento - eles são registros que mantêm o índice dos descritores
Para ser mais explícito, um índice não é um seletor
Coisas que um registro de segmento possui:
Acesso A tabela do descritor também possui privilégios, isso é chamado RPL (nível de privilégio de solicitação) para cada registro, mas para o cs é chamado CPL (nível atual de privilégio). Ambos estão servindo propósitos diferentes, que você pode descobrir nos manuais Intel ou AMD.
A tabela para usar para analisar. Uma tabela é a GDT que a outra é o LDT.
Uma regra informal para imaginar conceitualmente o uso do seletor: então a regra informal é:
Selector = índice + tabela_to_use + privilégio tabela_to_use + index = descritor = todas as informações sobre o segmento de memória a ser usado
onde o sinal de plus não é uma operação aritmética
Campo de bit de registro de seletor de segmento:
15 3 2 0
+--------------------------------------------------+----+--------+
| Index | TI | RPL |
+--------------------------------------------------+----+--------+
TI = Table Indicator: 0 = GDT, 1 = LDT
The TI specify if the Descriptor were dealing with is a GDT or LDT
IF(TI == 0) THEN
... THE DESCRIPTOR IS A GDT
ELSEIF(TI == 1) THEN
... THE DESCRIPTOR IS A LDT
O GDT é 1: 1 com endereço lógico, um exemplo do GDT que trabalha com o seletor:
<---- Selector ----> +----- Segment Selector Register
+-------+----+-----+ v
| Index | TI | RPL | = DS
+-------+----+-----+ GDT LDT
| | +---------------------+ +---------------------+
| +------------>| Null Descriptor | | Null Descriptor |
| +---------------------+ +---------------------+
| | Descriptor 1 | | Descriptor 1 |
| +---------------------+ +---------------------+
| | | | |
| ... ... ... ... ... ... ... ...
| | |
| +---------------------+
+------------------->| Descriptor K |
+---------------------+
| |
... ... ... ...
RPL (Request Privilege Level) describes the privilege for accessing the descriptor
Armazenamos toda a base do GDT (endereço) e limite (tamanho do nosso GDT) no GDTR. O GDTR aponta para todas as nossas entradas do GDT na memória, começando na base. Depois disso, é então carregado com o lgdt Mnemonic:
typedef union _gdt_descriptor
{
struct
{
uint64_t limit_low : 16 ;
uint64_t base_low : 16 ;
uint64_t base_middle : 8 ;
uint64_t access : 8 ;
uint64_t granularity : 8 ;
uint64_t base_high : 8 ;
};
} __attribute__((packed)) gdt_entry_t ;
gdt_entry_t gdt_entrys[ 256 ];
/* The GDTR (GDT Register) */
struct gdtr
{
uint16_t limit;
uint32_t base;
} __attribute__((packed)) gdtr;
...
gdtr.base = &gdt_entrys;
gdtr.limit = ( sizeof (gdt_descr) * 256 ) - 1 )
Leia mais sobre ele no Manual do Programador de Arquitetura AMD64, Volume 2, Seção 4.7 (pág. 84 - 90 {+})
referência a isso e em diante. https://notes.shichao.io/utlk/ch2/#paging-in-hardware Este foi de longe o mais divertido que eu tive, fiquei extremamente empolgado quando o entendi.
X86 OS Legacy-PAGING VIRTUAL ENDEREÇO COM PÁGINAS DE 4KB:
X86 OS CR4.PAE PAGE VIRTUAL ENDEREÇO COM PÁGINA DE 4KB:
x86_64 (IA-32E) OS CR4.LME/CR4.PAE PAGE VIRTUAL ENDEREÇO COM PÁGINA DE 4KB:
• Os sinalizadores WP e PG no registro de controle CR0 (bit 16 e 31, respectivamente).
• As bandeiras PSE, PAE, PGE, PCIDE, SMEP, SMAP e PKE no registro de controle CR4 (bit 4, bit 5, bit 7, bit 17, bit 20, bit 21 e bit 22, respectivamente).
• Os sinalizadores LME e NXE no IA32_EFER MSR (BIT 8 e BIT 11, respectivamente). • A bandeira CA no registro EFLAGS (bit 18). Pelo capítulo 4 do Intel® 64 e IA-32 Architecture Software Developer Volume 3A: Guia de Programação do Sistema, Parte 1; Capítulo 4
• Os sinalizadores LME e NXE no IA32_EFER MSR (BIT 8 e BIT 11, respectivamente). • A bandeira CA no registro EFLAGS (bit 18). Capítulo 4 dos Intel® 64 e IA-32 Architecture Developer Volume Manual 3A: Guia de Programação do Sistema, Parte 1; Capítulo 4
Se Cr4.Pae e/ou CR4.lme for definido como 1, o PSE será completamente desconsiderado.
Nenhum terminal adicionado
cd smkrnl; make run
Para a centelha de inspiração/apoio em meu esforço contínuo neste projeto e por me ajudar a entender certos conceitos no desenvolvimento do kernel/SO. =)