# Procedimentos do BIOS

BIOS — *Basic Input/Output System* — é o firmware da placa-mãe responsável pela inicialização do hardware. Ele quem começa o processo de *boot* do sistema além de anteriormente fazer um teste rápido (POST — *Power-On Self Test*) para verificar se o hardware está funcionando apropriadamente.

{% hint style="info" %}
BIOS é um sistema legado de *boot*, sistemas mais modernos usam [UEFI](https://pt.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface) para o processo de *boot* do sistema.
{% endhint %}

Mas além de fazer essa tarefa de inicialização do PC ele também define algumas interrupções que podem ser usadas pelo software em *real mode* para tarefas básicas. E é daí que vem seu nome, já que essas tarefas são operações básicas de entrada e saída de dados para o hardware.

Cada interrupção não faz um procedimento único mas sim vários procedimentos relacionados à um determinado hardware. Qual procedimento especificamente será executado é, na maioria das vezes, definido no registrador `AH` ou `AX`.

## INT 0x10

Essa interrupção tem procedimentos relacionados ao vídeo, como a escrita de caracteres na tela ou até mesmo alterar o modo de vídeo.

### AH 0x0E

O procedimento INT 0x10 / AH 0x0E simplesmente escreve um caractere na tela em modo *teletype*, que é um nome chique para dizer que o caractere é impresso na posição atual do cursor e atualiza a posição do mesmo. É algo bem semelhante ao que a gente vê sob um sistema operacional usando uma função como `putchar()` em C.

Esse procedimento recebe como argumento no registrador `AL` o caractere a ser impresso e em `BH` o número da página.

O número da página varia entre 0 e 7. São 8 páginas diferentes que podem ser apresentadas para o monitor como o conteúdo da tela. Por padrão é usada a página 0 mas você pode alternar entre as páginas fazendo com que conteúdo diferente seja apresentado na tela sem perder o conteúdo da outra página.

Se você já usou o MS-DOS deve ter visto programas, como editores de código, que imprimiam uma interface de texto (TUI) mas depois que finalizava o conteúdo do prompt voltava para a tela. Esses programas basicamente alternavam de página.

{% code title="exemplo.asm" %}

```nasm
mov ah, 0x0E
mov al, 'H'
int 0x10

mov al, 'i'
int 0x10

ret
```

{% endcode %}

No exemplo acima usamos a interrupção duas vezes para imprimir dois caracteres diferentes, fazendo assim um "Hello World" de míseros 11 bytes.

Poderíamos fazer um procedimento para escrever uma *string* inteira usando um *loop*. Ficaria assim:

{% code title="hello.asm" %}

```nasm
bits 16
org  0x100

mov si, string
call echo

ret

string: db "Hello World!", 0

; SI = ASCIIZ string
; BH = Página
echo:
  mov ah, 0x0E

.loop:
  lodsb
  test al, al
  jz .stop
  
  int 0x10
  jmp .loop
  
  
.stop:
  ret
```

{% endcode %}

### AH 0x02

| AH   | BH     | DH    | DL     |
| ---- | ------ | ----- | ------ |
| 0x02 | Página | Linha | Coluna |

Esse procedimento seta a posição do cursor em uma determinada página.

### AH 0x03

| AH   | BH     |
| ---- | ------ |
| 0x03 | Página |

Pega a posição atual do cursor na página especificada. Retornando:

| CH                 | CL               | DH    | DL     |
| ------------------ | ---------------- | ----- | ------ |
| *Scanline* inicial | *Scanline* final | Linha | Coluna |

### AH 0x05

| AH   | AL     |
| ---- | ------ |
| 0x05 | Página |

Alterna para a página especificada por AL que deve ser um número entre 0 e 7.

### AH 0x09

| AH   | AL        | BH     | BL       | CX                              |
| ---- | --------- | ------ | -------- | ------------------------------- |
| 0x09 | Caractere | Página | Atributo | Vezes para imprimir o caractere |

Imprime o caractere AL na posição atual do cursor CX vezes, sem atualizar o cursor. BL é o atributo do caractere que será explicado mais embaixo.

### AH 0x0A

| AH   | AL        | BH     | CX                  |
| ---- | --------- | ------ | ------------------- |
| 0x0A | Caractere | Página | Vezes para imprimir |

Mesma coisa que o procedimento anterior porém mudando somente que não é especificado um atributo para o caractere.

### AH 0x13

| Registrador | Parâmetro                                                   |
| ----------- | ----------------------------------------------------------- |
| AL          | Modo de escrita                                             |
| BH          | Página                                                      |
| BL          | Atributo                                                    |
| CX          | Tamanho da *string (número de caracteres a serem escritos)* |
| DH          | Linha                                                       |
| DL          | Coluna                                                      |
| ES:BP       | Endereço da *string*                                        |

Esse procedimento imprime uma *string* na tela podendo ser especificado um atributo. O modo de escrita pode variar entre 0 e 3, se trata de 2 bits especificando duas informações diferentes:

| Bit | Informação                                                                                 |
| --- | ------------------------------------------------------------------------------------------ |
| 0   | Se ligado atualiza a posição do cursor.                                                    |
| 1   | Se desligado BL é usado para definir o atributo. Se ligado, o atributo é lido da *string*. |

No caso do segundo bit, se estiver ligado então o procedimento irá ler a *string* considerando que se trata de uma sequência de caractere e atributo. Assim cada caractere pode ter um atributo diferente. Conforme exemplo abaixo:

```c
str: db 'A', 0x05, 'B', 0x0C, 'C', 0x0A
```

#### Caracteres de ação

Os procedimentos 0x0E e 0x13 interpretam caracteres especiais como determinadas ações que devem ser executadas ao invés de imprimir o caractere na tela. Cada caractere faz uma ação diferente conforme tabela abaixo:

| Caractere | Nome            | Seq. de escape | Ação                                              |
| --------- | --------------- | -------------- | ------------------------------------------------- |
| 0x07      | Bell            | \a             | Emite um beep.                                    |
| 0x08      | Backspace       | \b             | Retorna o cursor uma posição.                     |
| 0x09      | Horizontal TAB  | \t             | Avança o cursor 4 posições.                       |
| 0x0A      | Line feed       | \n             | Move o cursor verticalmente para a próxima linha. |
| 0x0D      | Carriage return | \r             | Move o cursor para o início da linha.             |

{% hint style="info" %}
Você pode combinar 0x0D e 0x0A para fazer uma quebra de linha.
{% endhint %}

## INT 0x16

Os procedimentos definidos nessa interrupção são todos relacionados à entrada do teclado. Toda vez que o usuário pressiona uma tecla ela é lida e armazenada no *buffer* do teclado. Se você tentar ler do *buffer* sem haver dados lá, então o sistema irá ficar esperando o usuário inserir uma entrada.

### AH 0x00

Lê um caractere do *buffer* do teclado e o remove de lá. Retorna os seguintes valores:

| Registrador | Valor                     |
| ----------- | ------------------------- |
| AL          | Código ASCII do caractere |
| AH          | *Scancode* da tecla.      |

*Scancode* é um número que identifica a tecla e não especificamente o caractere inserido.

### AH 0x01

Verifica se há um caractere disponível no *buffer* sem removê-lo de lá. Se houver caractere disponível, retorna:

| Registrador | Valor        |
| ----------- | ------------ |
| AL          | Código ASCII |
| AH          | *Scancode*   |

O procedimento também modifica a *Zero Flag* para especificar se há ou não caractere disponível. A define para 0 se houver, caso contrário para 1.

{% hint style="info" %}
Você pode usar em seguida o AH 0x00 para remover o caractere do *buffer*, se assim desejar. Desse jeito é possível pegar um caractere sem fazer uma pausa.
{% endhint %}

### AH 0x02

Pega *status* relacionados ao teclado. É retornado em AL 8 *flags* diferentes, cada uma especificando informações diferentes sobre o estado atual do teclado. Conforme tabela:

| Bit | Flag                                    |
| --- | --------------------------------------- |
| 0   | Tecla *shift* direita está pressionada. |
| 1   | Tecla *shift* esquerda está pressiona.  |
| 2   | Tecla *ctrl* está pressionada.          |
| 3   | Tecla *alt* está pressionada.           |
| 4   | *Scroll lock* está ligado.              |
| 5   | *Num lock* está ligado.                 |
| 6   | *Caps lock* está ligado.                |
| 7   | Modo *Insert* está ligado.              |

## Memória de Vídeo em *Text Mode*

Quando o sistema está em modo texto a memória onde se armazena os caracteres começa no endereço 0xb800:0x0000 e ela é estruturada da seguinte forma:

```c
// Em modo de texto 80x25, padrão do MS-DOS

struct character {
    uint8_t ascii;
    uint8_t attribute;
};

struct character vmem[8][25][80];
```

Ou seja começando em 0xb800:0x0000 as páginas estão uma atrás da outra na memória como uma grande *array*.

### Atributo

O caractere nada mais é que o código ASCII do mesmo, já o atributo é um valor usado para especificar informações de cor e *blink* do caractere.

Os 4 bits (*nibble*) mais significativo indicam o atributo do fundo e os 4 bits menos significativos o atributo do texto, gerando uma cor na escala RGB. Caso não conheça essa é a escala de cor da luz onde as cores primárias *Red* (vermelo), *Green* (verde) e *Blue* (azul) são usadas em conjunto para formar qualquer outra cor. Conforme figura abaixo podemos ver qual bit significa o quê:

![Bits de um atributo e seus significados](/files/-M39JajI7AOa0f4fkAs8)

O bit de intensidade no atributo de texto, caso ligado, faz com que a cor do texto fique mais viva enquanto desligado as cores são mais escuras. Já o bit de *blink* especifica se o texto deve permanecer piscando. Caso ativo o texto ficará aparecendo e desaparecendo da tela constantemente.

## Olá Mundo

Um exemplo de "Hello World" usando alguns conceitos apresentados aqui:

```nasm
bits 16
org  0x100

%macro puts 2
  mov bx, %1
  mov bp, %2
  call puts
%endmacro


puts 0x000A, str1
puts 0x000C, str2

ret

str1: db `Hello World!\r\n`, 0
str2: db "Second message.", 0

; BL = Atributo
; BH = Página
; BP = ASCIIZ String
puts:
  mov ah, 0x03
  int 0x10

  mov  di, bp
  call strlen
  mov  cx, ax
  
  mov al, 0b01
  mov ah, 0x13
  int 0x10

  ret


; DI = ASCIIZ String
; Retorna o tamanho da string
strlen:
  mov cx, -1
  xor ax, ax

  repnz scasb

  mov ax, -2
  sub ax, cx
  ret
```

{% hint style="info" %}
Para uma lista completa de todas as interrupções definidas pelo BIOS, sugiro a leitura:

<http://vitaly_filatov.tripod.com/ng/asm/asm_001.html>
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mentebinaria.gitbook.io/assembly/aprofundando-em-assembly/procedimentos-do-bios.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
