📝 Como instalar um .AppImage no Linux

A seguir, um tutorial completo sobre como instalar o Todoist no Linux:

1 – Acesse o site oficial do Todoist em https://todoist.com/pt-BR/downloads e baixe o arquivo .AppImage.

2 – Abra o terminal e navegue até o local onde o arquivo .AppImage foi baixado. Por exemplo, se o arquivo foi baixado para a pasta “Downloads”, você pode usar o comando “cd Downloads” para acessar essa pasta.

3 – Mova o arquivo .AppImage para o diretório /usr/local/bin com o seguinte comando:

sudo mv Todoist-1.0.9.AppImage /usr/local/bin/

4 – Conceda permissão de execução ao arquivo com o comando:

sudo chmod +x /usr/local/bin/Todoist-1.0.9.AppImage

5 – Crie um atalho para o aplicativo no menu “pesquisar” do Ubuntu criando um arquivo .desktop no diretório ~/.local/share/applications. Você pode usar o editor de texto “vim” para criar o arquivo:

vim ~/.local/share/applications/todoist.desktop

6 – Adicione as seguintes informações ao arquivo .desktop:

[Desktop Entry]
Name=Todoist
Comment=Organize seu trabalho e vida, finalmente.
Exec=/usr/local/bin/Todoist-1.0.9.AppImage
Terminal=false
Type=Application
Categories=Organização;Escritório

7 – Salve o arquivo e fecha o editor de texto. O ícone do Todoist deve aparecer no menu “pesquisar” do Ubuntu na próxima vez que você abri-lo.

🍒 Cheerio Dicas

  • $(“*”) — Seleciona Todos os elementos
  • $(“#first”) — Seleciona o elemento com o id=”first”
  • $(“.intro”) — Seleciona o elemento com a class="intro"
  • $(“div”) — Seleciona todos os elementos <div>
  • $(“h2, div, p”) — Seleciona todos os elementos <h2>, <div> e <p>

Referencias:

[1] – https://zetcode.com/javascript/cheerio/

Como criar um sistema operacional – parte 1

Montei esse material primeiro no Google Docs, se você quiser acessar o link é esse:

https://docs.google.com/document/d/1EOBcsNWKiI_1xxRNhtYrfWt6DNZcIhDe1Z2cLzVoasM/edit?usp=sharing

Antes de aprendermos a como criar um bootloader, primeiro temos que entender o que acontece com o computador ao pressionarmos o botão de Ligar.

Quando pressionamos o botão de Ligar, a energia é enviada para a CPU e a mesma trata de carregar um pequeno programa armazenado em um chip que fica localizado na placa mãe do computador.

O programa armazenado é chamado de BIOS (Basic Input/Output System), ou seja, Sistema Básico de Entrada e Saída, em placa mães mais recentes esse sistema é chamado de UEFI (Unified Extensible Firmware Interface) ou Interface de Firmware Extensível Unificada. O nosso foco será no desenvolvimento em cima da BIOS ou também chamada de LEGACY BIOS.

Quando executada, a BIOS carrega as configurações iniciais e inicializa o sistema do hardware, permitindo assim realizar as mais diversas operações, como por exemplo: acessar o disco, imprimir na tela, acessar o teclado e etc.

Também é feito uma verificação se todos os componentes do computador estão funcionando corretamente, esse procedimento é chamado de POST (Power on Self Test) Autoteste ao ligar.

    Uma vez inicializada corretamente, a BIOS será responsável por encontrar o Bootloader (Carregador de inicialização) e executá-lo. Discutiremos a respeito mais a frente.

Ambiente e Ferramentas

    Neste artigo, estaremos utilizando uma máquina baseada em Linux, essa escolha se deu pelo fato de que a maioria das ferramentas que utilizaremos já estão nativas nesse tipo de sistema operacional. As ferramentas utilizadas foram:

Essenciais:

  1. NASM version 2.14.02 [1]
  2. ld 2.3 [2]
  3. QEMU emulator version 4.0.0 [3]
  4. gcc 9.2.1

Opcionais:

  1. hexdump [4]
  2. vim
  3. gdb 8.3

Caso esteja em um sistema operacional baseado em linux que não tem essas ferramentas basta executar o código abaixo para instalar:

$ sudo apt-get install nasm gcc qemu

Meu primeiro bootloader

O bootloader é um pequeno programa de inicialização do sistema que deve estar situado nos primeiros 512 bytes do disco, sendo que no seu final deverá estar escrito o Magic Number 0xAA55, que é uma ‘assinatura’ pelo qual a BIOS reconhece que se trata de um dispositivo válido ou não [5]. Basicamente o bootloader tem como objetivo principal fazer 3 coisas:

  1. Carregar o kernel para a memória
  2. Passar para o modo protegido
  3. Passar o controle para o kernel

Ele é o responsável por direcionar o fluxo de execução para o kernel do sistema operacional, agindo assim como um intermediador. A Figura 1 demonstra o processo simplificado.

Figura 1 – Processo de Boot Simplificado

Layout da memória física

    O espaço de endereçamento do computador é dividido em 2 principais regiões.

A primeira região está abaixo de 1MB, conhecida como lower memory, na qual corresponde todo o endereçamento disponível possível para o chamado modo real, tal modo trabalha no máximo com 20 bits de endereçamento.

Já a segunda região é situada acima de 1MB, também conhecida como high memory que só poderá ser acessada no modo protegido, com endereçamentos 32/64 bits.

 A BIOS é responsável por carregar o bootloader que terá como destino o endereço de memória 0x7c00 que corresponde a área chamada Boot Sector Area, percebe-se que esta área vai de 0x7c00 até 0x7E00, correspondendo a 512 bytes, como pode ser visto na Figura 2.

Figura 2 – Organização da memória de um computador

Criando o arquivo

    Agora que sabemos como funciona, podemos prosseguir. Estarei utilizando o editor de texto vim do linux, mas pode ser empregado qualquer outro editor da sua escolha.

    Crie um arquivo de texto em branco chamado bootloader.asm e salve. No terminal iremos compilar esse arquivo com o programa nasm.

$ nasm bootloader.asm -o bootloader.bin

    Nomearemos esse trecho acima como Comando 1. Desse jeito gerando um arquivo de saída bootloader.bin, agora iremos executar o qemu com o seguinte comando:

$ qemu-system-x86_64 bootloader.bin

Nomearemos esse trecho acima como Comando 2. O resultado pode ser visto na Figura 3.

Figura 3 – Resultado do qemu

    Um dos erros ocorrido foi o Boot failed: could not read the boot disk quando tentou fazer o boot pelo Hard Disk no sistema, isso se deu pelo fato de que o arquivo está vazio e a BIOS não encontrou o Magic Number.

    Para resolver isso iremos abrir  novamente o arquivo bootloader.asm e digitar:

    times 512 db 0

    Depois de escrito, salve o arquivo e execute o Comando 1 e 2  respectivamente. O resultado pode ser observado na Figura 4. 

Figura 4 – Resultado do qemu

Agora a mensagem de erro no Hard Disk mudou para Boot failed: not a bootable disk.

 Isso significa que foi encontrado um dispositivo, mas não um que seja válido, pois lembrando, necessita que no final tenha a assinatura 0xAA55 para ser reconhecido como um dispositivo válido.

Entendo o binário

Para ter um outro ponto de vista do arquivo binário, iremos utilizar o seguinte comando:

$ hexdump -Cv bootloader.bin

Nomearemos esse trecho acima como Comando 3. A saída do programa você poderá ver na Figura 5.

Figura 5 – Resultado do comando hexdump

Está preenchido com apenas 0 pois no arquivo só existe uma repetição para incluir o 0 em 512 bytes. Agora Iremos abrir de novo nosso arquivo bootloader.asm e acrescentar:

    times 510 db 0

    dw 0XAA55

Observe que de 512 foi para 510 pois o comando 0XAA55 corresponde a 2 bytes, sendo 1 byte 0xAA, e outro para 0x55, 510 bytes + 2 bytes totalizando os 512 bytes necessários para o Boot Sector Area. Execute o Comando 1 e 2 respectivamente e a saída deverá ser como na Figura 6.

Figura 6 – Boot realizado

Se a mensagem que apareceu no qemu foi Booting from Hard Disk, isso indica que foi realizado o boot corretamente, ou seja, agora temos um dispositivo válido. Se executarmos o Comando 3 a saída deverá ser igual a da Figura 7.

Figura 7 – Resultado do Comando 3

    Agora a BIOS já consegue encontrar o Magic Number, pois observa-se que o 0xAA55 está  no final do Figura 7, na área onde fica os hexadecimais, em forma de 55 aa, está ao contrário por causa de alguns aspectos peculiares da arquitetura, que pode ser little endian ou big endian.

Escrevendo na Tela

A próxima etapa a ser feita é escrever um texto na tela, ou melhor, escrever

caracteres na tela. Para que isso ocorra você primeiro deverá conhecer o conceito de interrupções[6].

Como a leitura e escrita é fundamental para o funcionamento de um sistema, as interrupções vieram para nos auxiliar nisso, fazendo a ponte entre o hardware e o software.

Como demonstra a Figura 2 e com mais detalhes a Figura 8, a memória tem uma região que se chama IVT (Interrupt Vector Table) ou tabela de vetores de interrupção, que armazena os endereços onde estão as rotinas de tratamento de cada interrupção chamadas de  ISR (Interrupt Service Routine) ou Rotina dos serviços de interrupção.

Figura 8 – Visualização do IVT na memória

Figura 9 – Fluxo de Execução de uma Interrupção

Ao se chamar a interrupção int 0x10, ocorre o seguinte:

  1. A interrupção 0x10 é a décima interrupção, então este número é multiplicado por 4, pois cada elemento do vetor possui 4 bytes.
  2. O endereço 0x40 é acessado na memória do IVT, e o conteúdo existente neste endereço será um novo endereço onde se encontra o código dessa interrupção no ISR.
  3. Pula-se para esse novo endereço.
  4. A rotina de tratamento é executada.
  5. O controle é retornado para o programa.

## TODO – Registradores

## TODO – ASCII TABLE

Todo esse fluxo pode ser visto na Figura 9. Iremos implementar uma chamada de sistema no nosso arquivo, então abra o bootloader.asm e digite:

mov ah, 0X0E

mov al, 4Fh

int 10h

times 510-($-$$) db 0

dw 0xAA55

Salve o arquivo e execute o Comando 1 e 2. Deverá aparecer na tela a letra “O” como na Figura 10. 

Pense nos código mov ah, 0X0E e mov al, 4Fh como parâmetros para função de interrupção int 10h, função está responsável pelos procedimentos relacionados ao vídeo, como a escrita de caracteres na tela ou até mesmo alterar o modo de vídeo. 

O valor 0x0E tem que ir para o registrador ah e significa que queremos entrar em modo texto, já 4Fh é o valor da letra “O” em hexadecimal da tabela ASCII e tem que ir no registrador al. Essas 3 primeiras linhas poderá ser feito uma analogia em C assim:

void int10(char tipo, char character);

    Onde o resultado final é um caractere escrito na tela, ou também similar a função putchar() já existente do C.

    Já a penúltima linha teve que ser modificada, pois como foi inserido mais bytes, se continuasse a usar 510 bytes provavelmente iria ultrapassar a região do Boot Sector Area, para resolver esse problemas adicionamos -($-$$) onde o $ significa o endereço de memória atual e o  $$ o endereço do início da seção atual, que no caso é o endereço inicial do arquivo.

    Por exemplo, se as 3 primeiras linhas ocupam 5 bytes e o programa chegar no comando  -($-$$) esse comando irá retornar 5 bytes, logo, 510 – 5 = 505 bytes para preencher com 0 + 2 bytes do Magic Number completando assim os 512 bytes. 

Figura 10 – Saída do programa depois da chamada da Interrupção 

Se quiser escrever mais caracteres é só repetir o mov al, 4Fh e int 10h no código, trocando o conteúdo de al pela hexadecimal do caractere correspondente na tabela ASCII, e depois sempre chamando a interrupção, como por exemplo:

mov ah, 0x0E

;; O

mov al, 4Fh

int 10h

;; l

mov al, 6Ch

int 10h

;; a

mov al, 61h

int 10h

times 510-($-$$) db 0

dw 0xAA55

Referências

[1] – “O que é nasm?” https://assembly-area55.github.io/nasm

[2] – “Utilizando o linker ld” https://www.ic.unicamp.br/~edson/disciplinas/mc404/2016-2s/abef/labs/lab01/lab01.html

[3] – “qemu” https://www.qemu.org/

[4] –  “Exemplos de usos do hexdump ” https://www.geeksforgeeks.org/hexdump-command-in-linux-with-examples/

[5] – “Explicando o MBR” http://mbrwizard.com/thembr.php

[6] – “Interrupções Básicas” https://www.cin.ufpe.br/~eaa3/Arquivos/Assembly/interrupcoes_pc.pdf

http://www.brackeen.com/vga/