Linux-0.11
Curso da teoria: https://www.bilibili.com/video/bv1d4411v7u7
Referências úteis (versão comentada do Linux-0.11 ): https://github.com/beride/linux0.11-1
A filial principal é o código-fonte Linux-0.11
Veja a diferença de código: Pull Solicy Selecione a filial correspondente e compare -a com a principal
✔️ Boot do sistema operacional LAB0 (Branch Lab0)
Reescrevendo Bootsect.S completa principalmente as seguintes funções:
- Bootsect.s pode imprimir uma mensagem "xxx está inicializando ..." na tela.
Reescrever o Setup.s conclui principalmente as seguintes funções:
- O BootSect.s pode concluir o carregamento do Setup.s e saltar para a configuração. Inicie o endereço de execução. e o Setup.s produz uma linha "Agora estamos na configuração" na tela. O Setup.S pode obter pelo menos um parâmetro básico de hardware (como parâmetros de memória, parâmetros da placa gráfica, parâmetros de disco rígido etc.), armazenam -o em um endereço específico na memória e produzi -o para a tela. O Setup.S não carrega mais o kernel Linux, apenas mantenha as informações acima exibidas na tela.
Livro de instruções experimentais: https://www.lanqiao.cn/courses/115/labs/568/document/
✔️ Lab1 implementa chamadas do sistema (Branch Lab1)
- O número total de chamadas do sistema modificadas no kernel/system_call.s é 74.
- Adicione uma macro em incluir/unistd.h para indicar o posicionamento da tabela da função de chamada.
- Escreva duas funções (sys_iam, sys_whoami) definições de função em incluir/linux/sys.h. E adicione duas novas funções à tabela de funções depois dela.
- Adicionado kernel/who.c para implementar duas chamadas do sistema.
- Modificar makefile
- OBJS aumenta a dependência da OMS (Who.O)
- Adicione condições de geração de dependência para quem.
- Faça executar ./run para entrar no subsistema Linux e adicione as definições macro de iam e whoami em /usr/include/unistd.h (o mesmo que o ponto 2).
- Escrever um programa de teste no estado do usuário testa se ele é bem -sucedido.
Livro de instruções experimentais: https://www.lanqiao.cn/courses/115/labs/569/document/
✔️ Lab2 implementa o rastreamento da trajetória de operação do processo (Branch Lab2)
- O Process.c implementa um cenário que simula uma computação híbrida de CPU e computação de IO e a executa de maneira multipinosa.
- Imprima vários estados de troca de processos do kernel (tempo de status PID) para /var/process.log.
- Após a função init () init/main insere a instrução do estado do usuário, o Descritor de arquivo associado 3 para /var/process.log.
- Implemente a função fprintk () no kernel/printk para imprimir a saída para o processo do processo.log.
- Encontre o ponto de comutação de estado e adicione fprintk () para gravar logs.
- Processo Iniciar Kernel/System_Call.S -> SYS_FORK (Call Copy_Process)
- Executar, bloquear o kernel de troca de estado/sched.c -> agendar sys_pause sleep_on interrompible_sleep_on wake_up
- Saia do kernel/exit.c -> do_exit sys_waitpid
- Nota: O GCC no Linux-0.11 não pode ser compilado // comentado.
Livro de instruções experimentais: https://www.lanqiao.cn/courses/115/labs/570/document/
✔️ Lab3 substitui o processo TSS original no Linux0.11 para mudar para a comutação da pilha (Branch Lab3)
O método de comutação original é através do TSS, o que equivale a um instantâneo do registro. É substituído diretamente no local através das instruções fornecidas pela Intel, que é mais lenta. A troca de pilha é mais eficiente.
kernel/sched.c
- O método Switch_to original é baseado no switch TSS e queremos comentar no arquivo de cabeçalho.
- New switch_to, requer dois parâmetros (1: ponteiro para o próximo PCB 2: a posição da próxima tarefa na matriz é usada para alternar o LDT).
kernel/system_call.s
- Gravar switch_to montagem implementação
- Comutação de PCB
- Reescreva a posição da pilha do kernel do TSS (o TSS é retido no momento, mas há apenas um TSS no mundo e não é usado para fazer a troca de processos.)
- Mudar a pilha do kernel
- Switch LDT
kernel/fork.c
- Faça logon das configurações do TSS no PCB.
- Adicione uma nova variável de membro - pilha de kernel ao PCB, que é usado para armazenar informações da pilha do kernel.
- Escreva informações da pilha aqui e deixe o PCB a variável de membro apontar para o ponteiro.
Livro de instruções experimentais: https://www.lanqiao.cn/courses/115/labs/571/document/
Referência: https://blog.csdn.net/qq_42518941/article/details/119182097
✔️ Lab4 implementa o sistema semáforo chamadas no Linux0.11 (Branch Lab4)
Pontos de conhecimento pré-chave
- kernel/sched.c sleep_on Passe o cabeçalho da fila de espera, defina o estado de bloqueio e execute ativamente o cronograma (). O TMP armazena a fila de bloqueio original. Quando despertado, as filas de bloqueio estão todas definidas como executadas.
- kernel/sched.c wake_up acorda todos os PCBs bloqueados. Somente o líder da equipe de despertar pode ser visto no programa, mas deve ser lido em combinação com o Sleep_on. Uma vez combinado, você descobrirá que a cabeça de despertar acordará tudo posteriormente.
Escreva o aplicativo "PC.C" para resolver o problema clássico do produtor-consumidor e concluir as seguintes funções:
- Estabelecer um processo de produtor, n Processos de Consumidor (n> 1)
- Crie um buffer compartilhado com arquivos
- O processo do produtor escreve números inteiros 0, 1, 2,…, m, m> = 500 para o buffer, por sua vez
- O processo do consumidor lê do buffer, lê um de cada vez e exclui os números de leitura do buffer e, em seguida, produz o ID do processo e os números + para a saída padrão
- O buffer só pode economizar até 10 números ao mesmo tempo
Implementar semáforo
sem_t * sem_open ( const char * name , unsigned int value );
int sem_wait ( sem_t * sem );
int sem_post ( sem_t * sem );
int sem_unlink ( const char * name );
- sem_open abre um semáforo
- Se o semáforo for atualmente igual a zero, bloqueando o processo
- Adicione um semáforo
- Desligue um semáforo
O foco de espera e postagem
- espere
- Ligue para o kernel/sched.c sleep_on para esperar o bloqueio
- Use a interrupção do Linux (Linux0.11 Core único) para proteger a zona crítica
- menos um valor de SEM
- publicar
- Adicione um ao valor do SEM. Se o valor for maior que 0, ligue para o kernel/sched.c wake_up para acordar o processo bloqueado por este semáforo.
- Use a interrupção do Linux (Linux0.11 Core único) para proteger a zona crítica
Livro de instruções experimentais: https://www.lanqiao.cn/courses/115/labs/572/document/
✔️ Mapeamento e compartilhamento de endereços Lab5 (Branch Lab5)
Endereço lógico -> GDT -> LDT -> Página Tabela -> Endereço físico
Conhecimento da teoria dos instrumentos
Seletor de segmento
O acesso à tabela do descritor global por GDTR é feito através do "seletor de segmento" (registro do segmento no modo real)
15 3 2 1 0
| índice | | Rpl |
- 3-15 é o índice do descritor, que indica o descritor do segmento necessário na tabela do descritor.
- 2 para indicar se o seletor é selecionado no GDT ou no LDT (0 representa o GDT 1 representa LDT).
- 0-1 é o nível de privilégio para selecionar.
O seletor de segmento inclui três partes: Índice de descritores (índice), Ti e Nível de Privilégio de solicitação (RPL). Seu índice (índice descritor) indica o descritor do segmento necessário na posição da tabela do descritor. A partir desta posição, o descritor correspondente pode ser encontrado com base no endereço base da tabela do descritor armazenado no GDTR. Em seguida, o endereço base do segmento na tabela do descritor mais o endereço lógico (SEL: Offset) pode ser convertido em um endereço linear. O valor de Ti no seletor de segmento é apenas um 0 ou 1. 0 significa que o seletor é selecionado no GDT e 1 significa que o seletor é selecionado no LDT. O nível de privilégio de solicitação (RPL) representa o nível de privilégio do seletor e existem 4 níveis de privilégio (Nível 0, Nível 1, Nível 2 e Nível 3).
Nota no nível de privilégio: cada segmento na tarefa tem um nível específico. Sempre que um programa tenta acessar um segmento, o nível de privilégio que o programa possui é comparado com o nível de privilégio a ser acessado para determinar se o segmento pode ser acessado. A Convenção do Sistema é que a CPU pode acessar apenas segmentos do mesmo nível de privilégio ou em um nível de privilégio mais baixo.
Por exemplo, dê o endereço lógico: 21h: 12345678h convertido em endereço linear
um. Seletor SEL = 21h = 0000000000100 0 01 (b) significa: o índice do seletor = 4, ou seja, 0100, e o quarto descritor no GDT é selecionado; Ti = 0 significa que o seletor é selecionado no GDT; O último 01 significa nível de privilégio rpl = 1.
b. Deslocamento = 12345678h Se o endereço base do segmento descrito no quarto descritor do GDT no momento for 1111111H, o endereço linear = 111111H + 12345678H = 23456789h.
Visite GDT
- Primeiro, obtenha o endereço base do GDT no registro GDTR.
- Então, no GDT, o descritor do segmento é avaliado no seletor de seletor de alto índice de posição de 13 bits.
- Obtenha o endereço base, adicione o deslocamento para obter o endereço linear.
Access Ldt
- Primeiro, obtenha o endereço base do GDT no registro GDTR.
- Obtenha o índice de posição do segmento em que o LDT está localizado no registro LDTR (LDTR é 13 bits mais altos).
- O descritor do segmento LDT é obtido no GDT com este índice de posição para obter o endereço base do segmento LDT.
- Use o seletor de segmento para obter o descritor do segmento do segmento LDT.
- Obtenha o endereço base, adicione o deslocamento para obter o endereço linear.
Livro de instruções experimentais: https://www.lanqiao.cn/courses/115/labs/573/document/
✔️ Lab6 Controle do dispositivo do terminal (Branch Lab6)
- Quando a interrupção do teclado ocorre, o código de varredura do teclado é removido e o código de varredura é processado de acordo com a tabela key_table.
- Preencha a escrita de funções para a tecla F12.
- Após o processamento, coloque os caracteres com o código de varredura correspondente em put_queue.
- Ligue para o do_TTY_INTERRUPE para o processamento final, onde copy_to_cooked faz o pré -processamento final e, em seguida, ligue para o CON_WRITE para a saída da placa gráfica.
- Escreva -> sys_write -> tty_write -> con_write.
Livro de instruções experimentais: https://www.lanqiao.cn/courses/115/labs/574/document/
✔️ Implementação do Sistema de arquivos Lab7 Proc (Branch Lab7)
Conhecimento teórico
disco
Ler e escrever discos mecânicos requer três parâmetros para localizar
- Cilindro (C)
- Cabeça (h)
- Setor (s)
block = C * ( H * S ) + H * S + S ;
Dividindo vários setores em um bloco para melhorar a eficiência do IO do disco (Linux0.11 dividindo 2 setores em um bloco). Para um nível mais alto, você só precisa inserir o número do bloco de leitura e gravação para executar o disco IO.
Divisão: Bloco de inicialização | Super bloco | inode bitmap | Dados bitmap | Bloco inode | Bloco de dados
documento
Use FCB (inode no Linux0.11) para armazenar informações de arquivo, incluindo diferentes tipos de arquivos (por exemplo: arquivos de dispositivo, arquivos de diretório ...).
struct m_inode
{
unsigned short i_mode ; // 文件类型和属性(rwx 位)。
unsigned short i_uid ; // 用户id(文件拥有者标识符)。
unsigned long i_size ; // 文件大小(字节数)。
unsigned long i_mtime ; // 修改时间(自1970.1.1:0 算起,秒)。
unsigned char i_gid ; // 组id(文件拥有者所在的组)。
unsigned char i_nlinks ; // 文件目录项链接数。
unsigned short i_zone [ 9 ]; // 直接(0-6)、间接(7)或双重间接(8)逻辑块号。
/* these are in memory also */
struct task_struct * i_wait ; // 等待该i 节点的进程。
unsigned long i_atime ; // 最后访问时间。
unsigned long i_ctime ; // i 节点自身修改时间。
unsigned short i_dev ; // i 节点所在的设备号。
unsigned short i_num ; // i 节点号。
unsigned short i_count ; // i 节点被使用的次数,0 表示该i 节点空闲。
unsigned char i_lock ; // 锁定标志。
unsigned char i_dirt ; // 已修改(脏)标志。
unsigned char i_pipe ; // 管道标志。
unsigned char i_mount ; // 安装标志。
unsigned char i_seek ; // 搜寻标志(lseek 时)。
unsigned char i_update ; // 更新标志。
}; O número de bloco do arquivo no disco é armazenado no inode e em algumas outras informações de descrição do arquivo. Pode haver vários níveis de orientação de posição do bloco de disco, que são divididos em índice direto e índice indiretos para obter a posição do bloco.
Índice
Encontre os dados no número de bloco de disco de dados correspondente de acordo com o diretório inode, que contém o número de bloco de disco inode do subdiretório que existe no diretório. Camada de pesquisa por camada e você pode encontrar a localização do diretório de destino final.
Livro de instruções experimentais: https://www.lanqiao.cn/courses/115/labs/575/document/