FrancisBFTC / KiddieOS_Development

O KiddieOS é um sistema operacional open-source básico em desenvolvimento pelo curso gratuito D.S.O.S [Desenvolvendo Sistemas Operacionais Simples]. A intenção deste sistema será: Criar, editar ou excluir arquivos, codificar em uma linguagem própria do sistema, criar objetos visuais e automatizados (desenhos) através desta linguagem, utilizar uma interface simples e intuitiva, criar novas interfaces gráficas, como: Janelas, botões, campos, etc... e estimular crianças, jovens e adultos a programar numa linguagem simples dentro do sistema operacional KiddieOS. A intenção do curso D.S.O.S é dá início ao desenvolvimento de sistemas operacionais utilizando a linguagem Assembly e entender a fundo sobre diversos conceitos internos deste tipo de sistema. Aqui neste repositório serão armazenados arquivos de APIs do KiddieOS, a imagem de disco para teste e futuramente - todo o sistema operacional completo. Visite o link abaixo para nos acompanhar no curso do Youtube, se inscreva neste canal para se manter atualizado e siga-me no GitHub. Vejo vocês lá:
MIT License
46 stars 5 forks source link

Bug na interface de comandos: travamento após o ENTER [Resolvido] #13

Closed arthur-cas closed 7 months ago

arthur-cas commented 8 months ago

Quando insiro nenhum comando e aperto enter na interface de comandos, o KiddieOS trava.

FrancisBFTC commented 8 months ago

Olá amigo, como vai? Sim esse aí é outro erro que vou ter resolver no Shell16. Na próxima versão vou fazer as finais no Shell e corrigir isso também. Só me desculpe se eu estive afastado, ainda não tive tempo de mexer no KiddieOS, mas resolver tudo isso nesse mês.

FrancisBFTC commented 7 months ago

Quando insiro nenhum comando e aperto enter na interface de comandos, o KiddieOS trava.

Vou começar a procurar sobre esse bug agora.

FrancisBFTC commented 7 months ago

Quando insiro nenhum comando e aperto enter na interface de comandos, o KiddieOS trava.

Acabei de resolver aqui, foi rápido! Agora não trava mais. É porque após as várias atualizações no Shell, nem tinha chegado a testar a situação em que o usuário não insere nada na linha de comando, então vi que as rotinas processam mesmo quando o buffer é igual a 0 e isso não podia, então até mesmo pra gente evitar muito processamento desnecessário, decidi incluir uma condicional bem no início do Shell_Interpreter verificando se o byte[es:di] é igual a 0, se for então ele volta pra Cursor_Commands que vai dá uma quebra de linha, e como Cursor.CheckToRollEditor já foi executado antes da condicional, então ele vai dá mais uma quebra verificando os limites do editor, o que vai fazer com que o Editor role caso necessário. Logo, cada enter que você der darão duas quebras de linha no Editor, como se fosse um "echo" vazio. Também coloquei uma condicional em outra parte que é o Os_Intern_Shell, porém ele não verifica es:di, e sim, ds:si, pois ds:si aponta para a String fora do Shell, caso o usuário decida executar algum comando porém ele passar um buffer vazio para SI (Tudo zerado ou com apenas o 1ª byte zerado). Então o buffer estando zerado, ele cai em Error_Zero que vai definir AX para 0xFF, e assim o usuário pode identificar no programa se houve algum erro, se AX = 0xFF então houve erro de buffer zerado, porém se AX = 0, então o comando/programa foi executado com sucesso pelo Shell. Vamos agora pro bug do Write, esse eu creio que vai demorar mais um pouco, mas assim que eu resolver ele, eu vou criar as outras funções planejadas pra próxima versão, e aí eu fecho as duas issues e posto a nova versão.

arthur-cas commented 7 months ago

Falando em interface de comandos, estou planejando fazer uma em meu sistema. Para entrar no desktop é só pressionar alguma tecla na tela ou digitar "init". A tela de espera de tecla vai ser assim:

menuf2

E a tela do shell vai ser assim:

menuf2

arthur-cas commented 7 months ago

Agora eu estou tentando decidir se eu coloco os drivers separados ou coloco como módulos no kernel. Estou pensando em colocar eles em arquivos mas o problema é que eu decido por mim aonde deve carregar driver (estou pensando no endereço 0x900).

FrancisBFTC commented 7 months ago

Muito maneiro! Estas telas ficaram boas. É um sistema mais minimalista, isso me lembra os shells de alguns sistemas open-source. Então, sobre os Drivers eu acharia melhor separado por arquivos, por que você poderia carregar eles em qualquer endereço e poder alterar depois os endereços. A gente pode falar sobre uma forma de inserir estes drivers depois, porque eu tenho algumas ideias. Uma delas é criar uma tabela de endereços para drivers, onde o usuário poderia instalar separadamente por um comando, e aí no arquivo de driver teria algum número da interrupção de hardware, então o comando identificaria este número e salvaria o endereço do arquivo em uma posição da tabela, esta posição faria com que uma IRQ específica fosse acionada pra chamar o driver.

FrancisBFTC commented 7 months ago

Um exemplo da ideia que falei em partes de códigos:

Número no Driver

driver de timer (timer.asm)

irq_num   db 0    ; esta é a IRQ do TIMER
......
......

driver de keyboard (keyboard.asm)

irq_num   db 1    ; esta é a IRQ do teclado
......
......

Linha de Comando no Shell

K:\> loaddrv KiddieOS\Drivers\timer.drv K:\> loaddrv KiddieOS\Drivers\keyboard.drv

Tabela de Endereços

ADDR_TABLE:
     dd 0x00000000   ; Endereço da IRQ 0 (TIMER)
     dd 0x00000000   ; Endereço da IRQ 1 (KEYBOARD)
     ......
     dd 0x00000000   ; Endereço da IRQ 15

O programa "loaddrv.exe" ele pegaria o número que estará em irq_num no início de todo driver, e ele usaria este número pra identificar a posição da tabela ADDR_TABLE que ele colocaria o novo endereço do driver, Exemplo: Se o Driver que está sendo carregado é o de teclado, então ele pegaria o número 1 lá. E calcularia o endereço ADDR_TABLE que estaria em syscmng.asm:

mov bl, [irq_num]
mov ax, 0x3000
mov es, ax
mov ax, ADDR_TABLE
shl bx, 2       ; Multiplicação rápida por 4, BX contém o número de irq_num
add ax, bx    ; Soma a posição onde irá o endereço de keyboard na tabela

Aí digamos que o Driver de teclado foi carregado no endereço 0x3000:0xB0AA. Então na Tabela ficaria assim:

ADDR_TABLE:
     dd 0x00000000   ; Endereço da IRQ 0 (TIMER)
     dd 0x3000B0AA   ; Endereço da IRQ 1 (KEYBOARD)
     ......
     dd 0x00000000   ; Endereço da IRQ 15

Logo, teríamos cada IRQ pegando cada um destes endereços, vou dá um exemplo breve e simples da IRQ do TIMER e do KEYBOARD chamando estes endereços:

TIMER_IRQ:
    mov eax, [ADDR_TABLE+(0*4)]
    call eax
ret
KEYBOARD_IRQ:
    mov eax, [ADDR_TABLE+(1*4)]
    call eax
ret

Essa multiplicação de um número (Da IRQ) por 4 é que o vai resultar no valor de deslocamento para a soma, assim ele pega o endereço correto carregado pelo "loaddrv.exe". E aí, no início do kernel, os Drivers essenciais pro sistema funcionar seriam carregados usando o próprio programa, como:

mov   si, Scripts
call     Script.Execute
jmp    LoadMenu

Scripts:
     db "loaddrv.exe KiddieOS\Drivers\ata.drv"
     db "loaddrv.exe KiddieOS\Drivers\hal.drv"
     db "loaddrv.exe KiddieOS\Drivers\mouse.drv"
     db "loaddrv.exe KiddieOS\Drivers\timer.drv",0

Ou talvez estes Drivers sejam carregados só mesmo quando formos pro modo protegido no gerenciador gráfico, antes de migrar pro gerenciador, já que em modo real a gente usa mais a BIOS e não precisa de Drivers. Aí o próprio programa "winmng.osf" que carrega o gerenciador poderia chamar o loaddrv no código acima. E aí se o usuário quiser programar seus próprios Drivers pra colaborar com o sistema, ele pode seguir um padrão (além do número de IRQ no início do código) e sempre carregar com loaddrv pelo Shell, até o dia que a gente transformar este mero programinha em um sistema de instalação de Drivers na interface gráfica, que aliás poderia chamar este mesmo programa só que adaptado pro modo protegido. Aí tendo um sistema de instalação no futuro, o padrão poderia se extensificar, pra outros tipos de arquivos que contém informações de configurações e instalação, tipo um .inf... e uma destas informações, adivinha? O próprio número de IRQ que antes era colocado dentro do binário do Driver, e aí o "loaddrv.exe" interpretaria o próprio arquivo .INF, ao invés do binário diretamente, mas o carregamento ainda será do binário, como:

keyboard.inf (informações de drivers pro loaddrv)

[INF]
IRQ = 1
PATH = "K:\KiddieOS\Drivers\keyboard.drv"
VERSION = 1.0.0
// Entre outras informações importantes

Então essa é a minha ideia de início, o que você acha?

arthur-cas commented 7 months ago

Achei uma ideia boa até! Eu acho que fazer isso deve ser uma boa ideia. Os drivers funcionarão com apenas dois arquivos: o .sys e .cfg

O .cfg contém as funções do driver e seus endereços. Já o .sys contém o código do driver em si. Exemplo de driver VESA:

VESA.C

/ VESA driver for Arnix Version 1 /

int vesa_addr = 0x00000000; int width = 0;

void init_vesa(int address, int w) { vesa_addr = address; width = w; }

int read_pixel(int x, int y) { int pxcla = vesa_addr + convxy(x, y); int pxcl = (int)pxcla;

return *pxcl;

}

int convxy(int x, int y) { return y * width + x; }

VESA.CFG

init_vesa 0x100 read_pixel 0x900 convxy 0x1234

FrancisBFTC commented 7 months ago

Sim, exatamente, no meu caso eu usaria outras extensões como .INF e .DRV, e o .INF teria informações mais básicas pro carregamento, como: Número de IRQ, caminho do binário pra carregar e versão, claro que no futuro poderia adicionar outras informações, no seu caso você usaria .CFG e .SYS, mudaria as extensões e informações, achei sua ideia legal também. Vi que você pretende carregar cada função do driver em endereços diferentes e estáticos através do CFG. Eu pensei nisso, mas acho que pra mim iria complicar um pouco por causa do formato do meu sistema. Pois todas as funções do Driver estaria em um único arquivo e seria carregado no mesmo endereço pra facilitar, digo no meu caso, e aí pretendo ao invés de usar endereços estáticos, usar endereços dinâmicos via malloc, que o próprio sistema decida escolher os endereços disponíveis pra carregamento, o porém é que alguns drivers open-source na internet considera configurar a IRQ por ele mesmo (Assim como usar seus próprios endereços), e no meu sistema pretendo que esta configuração do IRQ e Endereços seja automática do próprio KiddieOS, sem o programador de drivers precisar se preocupar com isso. No caso, o programador se preocuparia mais em criar as funções de I/O e deixar ali um Handler pra inicializar o Driver ou operar de alguma maneira, ou seja, ele se preocuparia apenas com as operações do driver, e deixar as configurações pro KiddieOS se responsabilizar, por isso o .INF teria apenas informações básicas pra facilitar para o programador e pro kernel. É o que esta ideia que mostrei faz.

FrancisBFTC commented 7 months ago

Ah e outro detalhe que eu penso é sobre os próprios endereços dos Drivers, Eu acho que eu vou usar um malloc específico pra Kernel. Então no meu sistema terá dois mallocs diferentes: Um pros endereços baixos do Kernel e outro pros endereços de programas do usuário. O usuário utilizará este segundo tipo de alocação de memória, assim como os loaders de aplicações do usuário. Já no primeiro tipo, apenas eu que vou utilizar durante a programação do sistema, no entanto, enquanto o sistema estiver em modo real, e o usuário poder programar aplicações do DOS, ele também vai poder utilizar o primeiro tipo de malloc (um privilégio a mais pra ele). Eu penso nisso por que eu quero que os endereços dos drivers estejam próximo ao Kernel, nos endereços mais baixos, mesmo que seja em modo protegido na memória alta, porém que os drivers estejam após os códigos do kernel (seja em modo real ou em modo protegido). E aí eu desenvolvendo os Rings, tanto os drivers como o kernel será Ring 0, independente se estes códigos estiver na memória baixa e/ou na memória alta. Então, os endereços de carregamento serão dinâmicos e escolhidos pelo sistema, no entanto, dentro de certos intervalos de memória.

FrancisBFTC commented 7 months ago

Essa multiplicação de um número (Da IRQ) por 4 é que o vai resultar no valor de deslocamento para a soma, assim ele pega o endereço correto carregado pelo "loaddrv.exe". E aí, no início do kernel, os Drivers essenciais pro sistema funcionar seriam carregados usando o próprio programa, como:

mov   si, Scripts
call     Script.Execute
jmp    LoadMenu

Scripts:
     db "loaddrv.exe KiddieOS\Drivers\ata.drv"
     db "loaddrv.exe KiddieOS\Drivers\hal.drv"
     db "loaddrv.exe KiddieOS\Drivers\mouse.drv"
     db "loaddrv.exe KiddieOS\Drivers\timer.drv",0

Falando sério, acho que vou implementar isso nas próximas versões hein, não vou esperar. Por que eu já quero desenvolver o interpretador de AUTORUN.INI também (já tem é anos que penso isso) e planejei isso pra próxima versões. E como o AUTORUN.INI será um arquivo de configurações do Kernel, contendo ali uma tag de configuração de inicialização, então será mais prática e sofisticado se eu incluir este código acima da execução dos Scripts de instalação de Drivers essenciais dentro da tag de inicialização do Autorun.ini. Ou seja, a partir daí o próprio usuário pode automatizar a instalação de Drivers. Fechou, vou fazer isso na próxima versão. Só terminar o Write lá e subir as correções. Ah, eu deixei umas considerações lá na outra Issue do WRITE, pra você acompanhar as resoluções.

arthur-cas commented 7 months ago

Falando sobre o Arnix, o segundo estágio do bootloader está aproximadamente 80% concluído porque ainda falta alternar para o modo protegido (definir GDT, ativar A20), carregar drivers (o kernel será carregado depois dos drivers) e terminar a rotina de carregamento de arquivos (o código está certo, mas está dando erro de leitura de setor logo quando vai carregar clusters).

Por enquanto a rotina de carregamento de arquivos do segundo estágio do bootloader está assim:

LoadFile:
    push bx
    mov bx, 0x1000
    call LoadFAT
    pop bx
    push si
    mov si, StringLoad
    call Print
    pop si
    push bx
    LOAD_IMAGE:
        mov ax, [Cluster]
        call ClusterLBA
        pop bx
        xor cx, cx
        mov cl, [bpbSectorsPerCluster]
        call ReadSector

        push bx
        mov     ax, WORD [Cluster]    ; identify current cluster
        add     ax, ax                    ; 16 bit(2 byte) FAT entry
        mov     bx, 0x1000                ; location of FAT in memory
        add     bx, ax                    ; index into FAT    
        mov     dx, WORD [es:bx]          ; read two bytes from FAT
        mov     WORD [Cluster], dx   ; DX está com o próximo Cluster

        cmp dx, 0xFFF8
        je RET_LOAD_IMAGE
        cmp dx, 0xFFFF
        je RET_LOAD_IMAGE
        jmp LOAD_IMAGE
RET_LOAD_IMAGE:
pop bx
ret 
arthur-cas commented 7 months ago

Estou tentando resolver este erro de leitura no código ainda. Nem sei o porque disso acontecer.

arthur-cas commented 7 months ago

Inclusive usei um código seu de ajuda para fazer a parte do cálculo porque é o que mais se encaixa no meu caso

FrancisBFTC commented 7 months ago

Ah man, entendo, seu código ta ficando legal, calma aí um pouquinho que se você ainda não tiver resolvido eu posso te ajudar! Mano, assim, o negócio do Write lá tive muita dor de cabeça viu, ooh negócio difícil do caramba kkk Tive que criar mais alguns códigos, porque tinha vários outros erros, agora acredito que resolvi todos! Só teve uma forma de resolver, mas vou falar melhor quando subir o Pull Request. Aí assim, acho que vou fazer mais algumas coisas no Write, como processamento de setas direcionais no editor, pra deslocar o cursor em caracteres específicos e editar no meio do texto (Isso vai ser muito complicado de fazer porque tenho que deslocar textos tanto no buffer quanto na tela). Mas okay. Então, dá uma lida depois lá na Issue do Write o que eu escrevi porque eu já estou quase fechando lá e aqui, e você precisa saber das considerações pra testar no seu PC corretamente.

FrancisBFTC commented 7 months ago

Estou tentando resolver este erro de leitura no código ainda. Nem sei o porque disso acontecer.

Eu vou olhar as operações do seu código com calma e comparar com aqui. Sempre tem algum detalhe a mais ou a menos.

FrancisBFTC commented 7 months ago

Falando sobre o Arnix, o segundo estágio do bootloader está aproximadamente 80% concluído porque ainda falta alternar para o modo protegido (definir GDT, ativar A20)

Aí assim, tu pretende usar só o modo protegido? E daí pra frente utilizar Drivers?

FrancisBFTC commented 7 months ago
> LoadFile:
>     push bx
>     mov bx, 0x1000
>     call LoadFAT
>     pop bx
>     push si
>     mov si, StringLoad
>   call Print
>   pop si
>   push bx
>     LOAD_IMAGE:
>       mov ax, [Cluster]
>       call ClusterLBA
>       pop bx
>       xor cx, cx
>       mov cl, [bpbSectorsPerCluster]
>       call ReadSector
> 
>       push bx
>       mov     ax, WORD [Cluster]    ; identify current cluster
>       add     ax, ax                    ; 16 bit(2 byte) FAT entry
>       mov     bx, 0x1000                ; location of FAT in memory
>       add     bx, ax                    ; index into FAT    
>       mov     dx, WORD [es:bx]          ; read two bytes from FAT
>       mov     WORD [Cluster], dx   ; DX está com o próximo Cluster
> 
>       cmp dx, 0xFFF8
>       je RET_LOAD_IMAGE
>       cmp dx, 0xFFFF
>       je RET_LOAD_IMAGE
>       jmp LOAD_IMAGE
> RET_LOAD_IMAGE:
> pop bx
> ret

Então, olhando aqui, eu não sei se você chegou a fazer algumas coisas antes desse código, porque o LoadFile ele vem depois de algumas operações, como eu estou vendo aqui no meu fat16, porém não dá pra comparar muito porque eu já fiz muitas mudanças e adicionei muitas coisas no meio. Só que assim, tenho umas perguntas que talvez possa te ajudar:

arthur-cas commented 7 months ago

Falando sobre o Arnix, o segundo estágio do bootloader está aproximadamente 80% concluído porque ainda falta alternar para o modo protegido (definir GDT, ativar A20)

Aí assim, tu pretende usar só o modo protegido? E daí pra frente utilizar Drivers?

Eu pretendo usar apenas o modo protegido e usar drivers. Os drivers serão carregados no bootloader ao segundo estágio. Em breve quando eu fazer o driver ATA e FAT16 em C daí eu vou apenas carregar o ATA e FAT16 depois deixar meu kernel carregar o resto.

FrancisBFTC commented 7 months ago

Tente usar a depuração do VirtualBox passo a passo desde o início de LoadFile:, aí o que você faz: Você coloca um jmp $ antes de push bx abaixo de LoadFile:. E aí você executa normal no VirtualBox como modo depuração (Se você usa o Autogen.bat, então o BAT já faz isso). E aí quando seu código cair nessa rotina, o sistema vai travar no jmp $, aí você abre o terminal do depurador, digita r e em IP vai encontrar o endereço de memória do jmp $, então você copia este endereço completo e cola no notepad. Você fecha o VirtualBox, volta lá no código onde tem o jmp $ e substitui esta instrução por int3. É a instrução pra depuração. Então você recompila novamente o código abrindo o VirtualBox igual na primeira vez, e aí antes de executar o LoadFile você digita no depurador bp e na frente do comando bp o endereço que você colou no notepad. Ele vai criar um Breakpoint neste endereço. Talvez você não consiga controlar a execução do LoadFile, ele pode executar automaticamente, então talvez seja preciso você incluir uma espera do teclado usando INT 16h antes de executar o LoadFile, pra dá tempo de você colocar o bp ENDEREÇO. E aí quando executar o LoadFile, vai dá um BreakPoint na instrução int3, daí pra frente você só digita bc 0 pra excluir o BreakPoint, e agora você vai poder depurar passo a passo digitando p pra dar um Step Over em cada instrução. É só ir acompanhando os registradores e calculando em sua calculadora pra ver se ta tudo correto. O p dá Step Over, então ele vai saltar a execução das chamadas do CALL, então é provavel que você face o mesmo processo que eu expliquei agora pra cada rotina como o readsectors, loadfat, ClustersLBA, etc. Só assim é possível encontrar o seu erro de forma mais rápida, e provavelmente encontrar outros problemas.

Pra você não ficar precisando reinicializar pra cada rotina que for depurar, basta você você ir depurando normal com "p" e quando você chega em alguma instrução que tem call, você pega o endereço depois da instrução, por exemplo, se for call 0xAAAA então você pega o 0xAAAA e coloca no depurador assim u 3000:AAAA, caso seu segmento de kernel seja 0x3000. Aí o depurador vai exibir o código assembly pra você daquela rotina que estará sendo chamada. Aí basta dar um breakpoint neste endereço usando bp 3000:AAAA e quando cair lá, excluir com bc 0. Lembrando que, a cada breakpoint não excluído, esse número 0 vai acumulando, tipo, 1, 2, 3.. então se você não excluiu o breakpoint anterior, com bc 0, o próximo breakpoint pra excluir será bc 1, e etc.

arthur-cas commented 7 months ago
> LoadFile:
>     push bx
>     mov bx, 0x1000
>     call LoadFAT
>     pop bx
>     push si
>     mov si, StringLoad
>     call Print
>     pop si
>     push bx
>     LOAD_IMAGE:
>         mov ax, [Cluster]
>         call ClusterLBA
>         pop bx
>         xor cx, cx
>         mov cl, [bpbSectorsPerCluster]
>         call ReadSector
> 
>         push bx
>         mov     ax, WORD [Cluster]    ; identify current cluster
>         add     ax, ax                    ; 16 bit(2 byte) FAT entry
>         mov     bx, 0x1000                ; location of FAT in memory
>         add     bx, ax                    ; index into FAT    
>         mov     dx, WORD [es:bx]          ; read two bytes from FAT
>         mov     WORD [Cluster], dx   ; DX está com o próximo Cluster
> 
>         cmp dx, 0xFFF8
>         je RET_LOAD_IMAGE
>         cmp dx, 0xFFFF
>         je RET_LOAD_IMAGE
>         jmp LOAD_IMAGE
> RET_LOAD_IMAGE:
> pop bx
> ret

Então, olhando aqui, eu não sei se você chegou a fazer algumas coisas antes desse código, porque o LoadFile ele vem depois de algumas operações, como eu estou vendo aqui no meu fat16, porém não dá pra comparar muito porque eu já fiz muitas mudanças e adicionei muitas coisas no meio. Só que assim, tenho umas perguntas que talvez possa te ajudar:

  • Você chegou a configurar o registrador ES, GS e FS corretamente?
  • Vejo que você utiliza ES como segmento da tabela FAT mas e o segmento da área de diretórios? Você usa em qual registrador? FS ou GS?
  • E o segmento do Kernel também?
  • E vejo que você usa uma variável "StringLoad" em SI, e creio eu que esta seja o nome do arquivo que você quer carregar, ou não, mas se for, você considerou procurar este arquivo primeiro na área de diretórios? Antes de rodar o LoadFile?
  • E sobre a formatação dessa String? Você está usando no padrão 8.3? Como FILE TXT. Este é o padrão do FAT16. A menos que você crie uma rotina de formatação pra conseguir ler "file.txt", que você pode encontrar no Shell do KiddieOS.

Os registrador ES é configurado pelo próprio bootloader neste trecho:

;=======================;
; Main routine          ;
;=======================;

ARXLDR_MAIN:
    push cs
    pop ds

    xor ax, ax
    mov es, ax

Já os GS e FS não foram configurados pelo bootloader (no segundo estágio) e nem usados no bootloader. Sobre a formatação da string e a string do arquivo, saiba que StringLoad é uma string que não tem o nome do arquivo e sim que avisa o usuário que está carregando o sistema operacional (usei para conseguir saber onde fica erros). Está definido as strings aqui:

;=======================;
; Strings               ;
;=======================;
KernelImg: db "KERNEL  SYS"
StringSearch: db "Searching operating system kernel.",0x0D,0x0A,0x00
SearchComplete: db "Operating system kernel exists. Search complete.",0x0D,0x0A,0x00
StringLoad: db "Loading operating system kernel...",0x0D,0x0A, 0x00
ErrorPrefix: db "**** ERROR: ",0 
ErrorDisk: db "Error while loading disk sectors.",0x0D,0x0A,0x00
ErrorFile: db "Kernel file not found.",0x0D,0x0A,0x00
ErrorVESA: db "Getting VESA mode info failed.",0x0D,0x0A,0x00
StringLoadingRoot: db "Loading FAT root directory...",0x0D,0x0A,0x00
StringLoadedRoot: db "FAT root directory loaded.",0x0D,0x0A,0x00
StringLoadingFAT: db "Loading FAT allocation table...",0x0D,0x0A,0x00
StringLoadedFAT: db "FAT allocation table loaded.",0x0D,0x0A,0x00
PressKey: db 0x0D,0x0A,"Press any key to continue...",0x00
ArnixBoot: db "Arnix Bootloader (ARXLDR)",0x0D,0x0A,0x0D,0x0A,0x00
CRLF: db 0x0D,0x0A,0x00

A chamada de LoadFile está localizada aqui:

mov si, ArnixBoot
    call Print
    call SearchFile
    mov si, KernelImg
    mov bx, 0x4000
    call LoadFile
    mov si, PressKey
    call Print

    call WaitKey
    push word es
    push word bx
    retf

SearchFile procura o arquivo na área de diretóriios especificado em SI.

arthur-cas commented 7 months ago

Sobre usar VirtualBox, agora pensei em migrar para ele ao rodar meu sistema operacional porque estou usando o QEMU para emular: (arxldr.sys é o bootloader segundo estágio)

:: build.cmd

@echo off
del arxdisk.img
nasm -f bin src/arxldr/arxldr.asm -o bin/arxldr.sys
nasm -f bin src/kernel/test.asm -o bin/kernel.sys
dd if=/dev/zero of=arxdisk.img bs=1M count=4
dd if=bin/boot16.bin of=arxdisk.img
imdisk -a -m Z: -f arxdisk.img
copy bin\arxldr.sys Z:
copy bin\kernel.sys Z:
imdisk -D -m Z:
qemu-system-x86_64 -hda arxdisk.img -m 512M
FrancisBFTC commented 7 months ago

A chamada de LoadFile está localizada aqui:

mov si, ArnixBoot
  call Print
  call SearchFile
  mov si, KernelImg
  mov bx, 0x4000
  call LoadFile
  mov si, PressKey
  call Print

  call WaitKey
  push word es
  push word bx
  retf

SearchFile procura o arquivo na área de diretóriios especificado em SI.

Entendi agora, então se SearchFile procura o arquivo KERNEL SYS na área de diretórios, antes de executar call SearchFile, você deve passar "KernelImg" para SI, eu vi que você está passando depois da execução de call SearchFile. Ou seja, o SI antes está com "ArnixBoot".

FrancisBFTC commented 7 months ago

Sobre usar VirtualBox, agora pensei em migrar para ele ao rodar meu sistema operacional porque estou usando o QEMU para emular: (arxldr.sys é o bootloader segundo estágio)

:: build.cmd

@echo off
del arxdisk.img
nasm -f bin src/arxldr/arxldr.asm -o bin/arxldr.sys
nasm -f bin src/kernel/test.asm -o bin/kernel.sys
dd if=/dev/zero of=arxdisk.img bs=1M count=4
dd if=bin/boot16.bin of=arxdisk.img
imdisk -a -m Z: -f arxdisk.img
copy bin\arxldr.sys Z:
copy bin\kernel.sys Z:
imdisk -D -m Z:
qemu-system-x86_64 -hda arxdisk.img -m 512M

Ah sim, então eu já assumo que você não usa o Autogen.bat do KiddieOS, você fez a Build do zero para o QEMU. O Autogen também executa o QEMU, só que eu não uso o QEMU pra depurar, porque ainda não peguei as manhas.

FrancisBFTC commented 7 months ago

Sobre usar VirtualBox, agora pensei em migrar para ele ao rodar meu sistema operacional porque estou usando o QEMU para emular: (arxldr.sys é o bootloader segundo estágio)

:: build.cmd

@echo off
del arxdisk.img
nasm -f bin src/arxldr/arxldr.asm -o bin/arxldr.sys
nasm -f bin src/kernel/test.asm -o bin/kernel.sys
dd if=/dev/zero of=arxdisk.img bs=1M count=4
dd if=bin/boot16.bin of=arxdisk.img
imdisk -a -m Z: -f arxdisk.img
copy bin\arxldr.sys Z:
copy bin\kernel.sys Z:
imdisk -D -m Z:
qemu-system-x86_64 -hda arxdisk.img -m 512M

Ah sim, então eu já assumo que você não usa o Autogen.bat do KiddieOS, você fez a Build do zero para o QEMU. O Autogen também executa o QEMU, só que eu não uso o QEMU pra depurar, porque ainda não peguei as manhas.

E você está usando imagem de disquete IMG né? Olha, eu mexi muito com isso mas pra executar o FAT16 deu muito problema, até que eu abandonei completamente o IMG, agora só uso o VHD, porque ele tem todo o suporte, tanto pra FAT16, quanto pra máquina virtual. Ah e outro detalhe importante é que eu não vi você alocando no binário IMG a tabela FAT, onde você aloca essa tabela? Eu uso um arquivo chamado FAT.bin com 32 MB de alocação pro FAT16 e carrego ele usando DD no VHD. Na verdade o FAT.bin tem todas as alocações, tanto da tabela FAT, área de diretórios e área de dados, está tudo nele. Então é o FAT.bin que garante a formatação do disco (Seja ele um pendrive, um IMG, um VHD, etc.). Se você não usa um arquivo estático pra formatar, de alguma forma você deve realizar esta formatação, mesmo que seja dinamicamente na inicialização (Meio que copiar toneladas de bytes pro seu disco pelo código).

arthur-cas commented 7 months ago

Sobre usar VirtualBox, agora pensei em migrar para ele ao rodar meu sistema operacional porque estou usando o QEMU para emular: (arxldr.sys é o bootloader segundo estágio)

:: build.cmd

@echo off
del arxdisk.img
nasm -f bin src/arxldr/arxldr.asm -o bin/arxldr.sys
nasm -f bin src/kernel/test.asm -o bin/kernel.sys
dd if=/dev/zero of=arxdisk.img bs=1M count=4
dd if=bin/boot16.bin of=arxdisk.img
imdisk -a -m Z: -f arxdisk.img
copy bin\arxldr.sys Z:
copy bin\kernel.sys Z:
imdisk -D -m Z:
qemu-system-x86_64 -hda arxdisk.img -m 512M

Ah sim, então eu já assumo que você não usa o Autogen.bat do KiddieOS, você fez a Build do zero para o QEMU. O Autogen também executa o QEMU, só que eu não uso o QEMU pra depurar, porque ainda não peguei as manhas.

E você está usando imagem de disquete IMG né? Olha, eu mexi muito com isso mas pra executar o FAT16 deu muito problema, até que eu abandonei completamente o IMG, agora só uso o VHD, porque ele tem todo o suporte, tanto pra FAT16, quanto pra máquina virtual. Ah e outro detalhe importante é que eu não vi você alocando no binário IMG a tabela FAT, onde você aloca essa tabela? Eu uso um arquivo chamado FAT.bin com 32 MB de alocação pro FAT16 e carrego ele usando DD no VHD.

Acho que vou formatar o FAT usando um bin mas tinha usado uma técnica que é deixar o arquivo vazio com apenas o bootloader VBR. Mas também acho que deve ser melhor formatar o disco com um FAT feito porque já vai estar configurado.

FrancisBFTC commented 7 months ago

Já os GS e FS não foram configurados pelo bootloader (no segundo estágio) e nem usados no bootloader. Sobre a formatação da string e a string do arquivo, saiba que StringLoad é uma string que não tem o nome do arquivo e sim que avisa o usuário que está carregando o sistema operacional (usei para conseguir saber onde fica erros).

Maneiro, consegui agora identificar todas as Strings. Já sobre o GS e FS, como você conseguiu fazer tudo sem utilizar eles? kkkk Eu não consegui encontrar essa forma, porque eu tenho que controlar vários endereços (segmentos) diferentes ao mesmo tempo, porque assim: O meu GS uso o segmento do FAT, meu FS uso o segmento da área de diretórios, meu ES utilizo o segmento do Kernel (igual DS), mas ES é o único que fica livre pra se alternar quando necessário pra outros segmentos extras (Por exemplo: Os próprios dados que vão pra área de dados, é outro segmento diferente). Usando segmentos diferentes, eu garanto que eu tenha espaço suficiente para alocar muitos arquivos no FAT16.

arthur-cas commented 7 months ago

Eu usei apenas ES para controlar segmento. É porque eu coloquei tudo no mesmo segmento.

FrancisBFTC commented 7 months ago

Eu usei apenas ES para controlar segmento. É porque eu coloquei tudo no mesmo segmento.

Ah sim, entendi. Legal, facilita mais mesmo.

FrancisBFTC commented 7 months ago

Acho que vou formatar o FAT usando um bin mas tinha usado uma técnica que é deixar o arquivo vazio com apenas o bootloader VBR. Mas também acho que deve ser melhor formatar o disco com um FAT feito porque já vai estar configurado.

Ah maneiro, e não é uma má ideia essa técnica viu kkk Porque aí abre margens pra você criar sistemas de instalação/formatação, igual os OSes modernos fazem, claro, se você conhece toda a estrutura do FAT e consegue organizar ela manualmente, obviamente fica mais fácil usar a técnica pra copiar tudo pro disco em tempo real. Mesmo assim, deixar a estrutura pronto em um .bin é mais fácil e rápido, por isso optei por isso, mas depois quero criar a instalação em tempo real.

arthur-cas commented 7 months ago

Inclusive estou com essa BPB que o ChatGPT me sugeriu kkkkkkk

bpbBytesPerSector       DW      512               ; Bytes Per Sector (0x0B)
bpbSectorsPerCluster    DB      8                 ; Sectors Per Cluster (0x0D)
bpbReservedSectors      DW      1                 ; Reserved Sectors (0x0E)
bpbNumberOfFATs         DB      2                 ; Number of FATs (0x10)
bpbRootEntries          DW      512               ; Root Entries (0x11)
bpbTotalSectors         DW      8192              ; Total Sectors (0x13)
bpbMedia                DB      0xF8              ; Media Descriptor Type (0x15)
bpbSectorsPerFAT        DW      8                 ; Sectors Per FAT (0x16)
bpbSectorsPerTrack      DW      63                ; Sectors Per Track (0x18)
bpbHeadsPerCylinder     DW      16                ; Number of Heads (0x1A)
bpbHiddenSectors        DD      0                 ; Hidden Sectors (0x1C)
bpbTotalSectorsBig      DD      0                 ; Large Total Sectors (0x20)
arthur-cas commented 7 months ago

Outra coisa sobre o Arnix é que ele veio de Arthur + Unix inspirado na ideia de Linus torvalds de usar Linus + Unix que resultou em Linux. Sobre modo protegido estou planejando fazer uma ferramenta do Arnix que consegue executar programas 16-bit. (igual o NTDVM do Windows)

FrancisBFTC commented 7 months ago

Inclusive estou com essa BPB que o ChatGPT me sugeriu kkkkkkk

bpbBytesPerSector       DW      512               ; Bytes Per Sector (0x0B)
bpbSectorsPerCluster    DB      8                 ; Sectors Per Cluster (0x0D)
bpbReservedSectors      DW      1                 ; Reserved Sectors (0x0E)
bpbNumberOfFATs         DB      2                 ; Number of FATs (0x10)
bpbRootEntries          DW      512               ; Root Entries (0x11)
bpbTotalSectors         DW      8192              ; Total Sectors (0x13)
bpbMedia                DB      0xF8              ; Media Descriptor Type (0x15)
bpbSectorsPerFAT        DW      8                 ; Sectors Per FAT (0x16)
bpbSectorsPerTrack      DW      63                ; Sectors Per Track (0x18)
bpbHeadsPerCylinder     DW      16                ; Number of Heads (0x1A)
bpbHiddenSectors        DD      0                 ; Hidden Sectors (0x1C)
bpbTotalSectorsBig      DD      0                 ; Large Total Sectors (0x20)

Pra início, o ChatGPT até que não errou muito, mas acho que você precisa rever esses números. Quebrei a cabeça igual um maluco pra fazer o sistema funcionar só por causa destes números. Dá uma olhada lá wiki.osdev, na parte de FAT16. Lá tem a explicação completa de cada variável da BPB e a EBPB. Ainda ta faltando +6 variáveis no final. Assim, meu FAT16 está super completo, você encontra tudo e mais um pouco, a MBR, Partição, VBR, o Driver, as Estruturas, As funções Shell que chamam as operações, as rotinas do DOS que usa estas operações, tudo mesmo. Vai ver um dos problemas que você esteja enfrentando pode estar aí nesses números (passei por isso milhares de vezes),... pegar um pouco de cada SO pra colocar em um só dá uma trabalhadeira danada, é muita dor de cabeça pra encontrar os problemas, porque cada sistema é único e tem suas próprias características e métodos. Aí muitas coisas não se encaixam. Estes números eles dependem de como as suas estruturas do FS estão organizadas, então até eles podem mudar dinamicamente, aí estando tudo sincronizado, seu FS se torna reconhecido pelo Windows e Linux quando você copia para um Pendrive ou um HD.

FrancisBFTC commented 7 months ago

Outra coisa sobre o Arnix é que ele veio de Arthur + Unix inspirado na ideia de Linus torvalds de usar Linus + Unix que resultou em Linux. Sobre modo protegido estou planejando fazer uma ferramenta do Arnix que consegue executar programas 16-bit. (igual o NTDVM do Windows)

Ah sim, a ideia do nome combinou certinho. Os programas de 16 bits podem ser executados pelo modo protegido usando o modo virtual 8086 do processador. Tenho um código desse modo no syscmng.asm, mas acabei desistindo de concertar ele, antes ele funcionava.

FrancisBFTC commented 7 months ago

Dá uma olhada lá na Issue do comando Write quando puder, se já tiver lido, confirma lá pra mim saber porque em breve já marco lá como concluída.

arthur-cas commented 7 months ago

Inclusive estou com essa BPB que o ChatGPT me sugeriu kkkkkkk

bpbBytesPerSector       DW      512               ; Bytes Per Sector (0x0B)
bpbSectorsPerCluster    DB      8                 ; Sectors Per Cluster (0x0D)
bpbReservedSectors      DW      1                 ; Reserved Sectors (0x0E)
bpbNumberOfFATs         DB      2                 ; Number of FATs (0x10)
bpbRootEntries          DW      512               ; Root Entries (0x11)
bpbTotalSectors         DW      8192              ; Total Sectors (0x13)
bpbMedia                DB      0xF8              ; Media Descriptor Type (0x15)
bpbSectorsPerFAT        DW      8                 ; Sectors Per FAT (0x16)
bpbSectorsPerTrack      DW      63                ; Sectors Per Track (0x18)
bpbHeadsPerCylinder     DW      16                ; Number of Heads (0x1A)
bpbHiddenSectors        DD      0                 ; Hidden Sectors (0x1C)
bpbTotalSectorsBig      DD      0                 ; Large Total Sectors (0x20)

Pra início, o ChatGPT até que não errou muito, mas acho que você precisa rever esses números. Quebrei a cabeça igual um maluco pra fazer o sistema funcionar só por causa destes números. Dá uma olhada lá wiki.osdev, na parte de FAT16. Lá tem a explicação completa de cada variável da BPB e a EBPB. Ainda ta faltando +6 variáveis no final. Assim, meu FAT16 está super completo, você encontra tudo e mais um pouco, a MBR, Partição, VBR, o Driver, as Estruturas, As funções Shell que chamam as operações, as rotinas do DOS que usa estas operações, tudo mesmo. Vai ver um dos problemas que você esteja enfrentando pode estar aí nesses números (passei por isso milhares de vezes),... pegar um pouco de cada SO pra colocar em um só dá uma trabalhadeira danada, é muita dor de cabeça pra encontrar os problemas, porque cada sistema é único e tem suas próprias características e métodos. Aí muitas coisas não se encaixam. Estes números eles dependem de como as suas estruturas do FS estão organizadas, então até eles podem mudar dinamicamente, aí estando tudo sincronizado, seu FS se torna reconhecido pelo Windows e Linux quando você copia para um Pendrive ou um HD.

Sobre o tamanho da BPB é que eu só coloquei a BPB e não a EBPB porque eu peguei do meu arquivo Fat16.inc. Até que nesta configuração está funcionando bem. Estou pensando em reescrever o bootloader segundo estágio em C para tentar acessar endereços melhor, o que acha?

__asm__("jmpl $bootmain\n");

void bootmain()
{
for(;;);
}
arthur-cas commented 7 months ago

Acho que vou formatar o FAT usando um bin mas tinha usado uma técnica que é deixar o arquivo vazio com apenas o bootloader VBR. Mas também acho que deve ser melhor formatar o disco com um FAT feito porque já vai estar configurado.

Ainda estou fazendo o FAT mas por enquanto está assim:

[BITS 16]

; ============================== ;
; Directives
; ============================== ;
SECTOR_SIZE         equ 512
ROOT_ENTRY_SIZE     equ 32
NUM_FATS            equ 2
FAT_SECTORS         equ 8      ; bpbSectorsPerFAT

; ============================== ;
; FAT table                      ;
; ============================== ;
db 0xF0, 0xFF, 0xFF, 0xFF
times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

db 0xF0, 0xFF, 0xFF, 0xFF
times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0
arthur-cas commented 7 months ago

Terminei o FAT:

[BITS 16]

; ============================== ;
; Directives
; ============================== ;
SECTOR_SIZE         equ 512
FAT_SECTORS         equ 8

; ============================== ;
; FAT table                      ;
; ============================== ;
dw 0xFFF0, 0xFFFF
times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

dw 0xFFF0, 0xFFFF
times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

Usarei DD com seek=1 para colocar o FAT

arthur-cas commented 7 months ago

Terminei o FAT:

[BITS 16]

; ============================== ;
; Directives
; ============================== ;
SECTOR_SIZE         equ 512
FAT_SECTORS         equ 8

; ============================== ;
; FAT table                      ;
; ============================== ;
dw 0xFFF0, 0xFFFF
times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

dw 0xFFF0, 0xFFFF
times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

Usarei DD com seek=1 para colocar o FAT

Tentei usar este FAT de várias formas e não deu. Pois é. Acho que irei continuar com minha técnica

arthur-cas commented 7 months ago

Agora eu consigo depurar melhor. É que eu estava usando o QEMU e ele usava o GDB que é meio complicado. Daí decidi migrar para o VirtualBox e coloquei um footer de VHD:

:: build.cmd

@echo off
del bin /q
del obj /q
del arxdisk.vhd
gcc -o obj/arxldr.o -c src/arxldr/arxldr.c -m32 -nostartfiles -nostdlib -nodefaultlibs -Wall -Werror
gcc -o bin/arxldr.exe obj/arxldr.o -m32 -nostartfiles -nostdlib -nodefaultlibs 
objcopy -O binary bin/arxldr.exe bin/arxldr.sys
del bin\arxldr.exe
nasm -f bin src/disk/bootvbr.asm -o bin/bootvbr.bin
nasm -f bin src/disk/footvhd.asm -o bin/footvhd.bin
nasm -f bin src/kernel/test.asm -o bin/kernel.sys
dd if=/dev/zero of=arxdisk.vhd bs=1M count=4
dd if=bin/bootvbr.bin of=arxdisk.vhd
dd if=bin/footvhd.bin of=arxdisk.vhd bs=512 seek=8191
imdisk -a -m Z: -f arxdisk.vhd
copy bin\arxldr.sys Z:
copy bin\kernel.sys Z:
imdisk -D -m Z:
"C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" startvm  --putenv VBOX_GUI_DBG_ENABLED=true Arnix
FrancisBFTC commented 7 months ago

Agora eu consigo depurar melhor. É que eu estava usando o QEMU e ele usava o GDB que é meio complicado. Daí decidi migrar para o VirtualBox e coloquei um footer de VHD:

:: build.cmd

@echo off
del bin /q
del obj /q
del arxdisk.vhd
gcc -o obj/arxldr.o -c src/arxldr/arxldr.c -m32 -nostartfiles -nostdlib -nodefaultlibs -Wall -Werror
gcc -o bin/arxldr.exe obj/arxldr.o -m32 -nostartfiles -nostdlib -nodefaultlibs 
objcopy -O binary bin/arxldr.exe bin/arxldr.sys
del bin\arxldr.exe
nasm -f bin src/disk/bootvbr.asm -o bin/bootvbr.bin
nasm -f bin src/disk/footvhd.asm -o bin/footvhd.bin
nasm -f bin src/kernel/test.asm -o bin/kernel.sys
dd if=/dev/zero of=arxdisk.vhd bs=1M count=4
dd if=bin/bootvbr.bin of=arxdisk.vhd
dd if=bin/footvhd.bin of=arxdisk.vhd bs=512 seek=8191
imdisk -a -m Z: -f arxdisk.vhd
copy bin\arxldr.sys Z:
copy bin\kernel.sys Z:
imdisk -D -m Z:
"C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" startvm  --putenv VBOX_GUI_DBG_ENABLED=true Arnix

Aí agora sim, de IMG para VHD, e ainda com o Footer, agora dá certo.

FrancisBFTC commented 7 months ago

Terminei o FAT:

[BITS 16]

; ============================== ;
; Directives
; ============================== ;
SECTOR_SIZE         equ 512
FAT_SECTORS         equ 8

; ============================== ;
; FAT table                      ;
; ============================== ;
dw 0xFFF0, 0xFFFF
times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

dw 0xFFF0, 0xFFFF
times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

Usarei DD com seek=1 para colocar o FAT

Tentei usar este FAT de várias formas e não deu. Pois é. Acho que irei continuar com minha técnica

Já tentou usar 2 setores por cluster? kkk 8 ta meio grandinho né. Quem costuma usar 8 é o ntfs, com 4.096 bytes de tamanho de disco pra cada arquivo, mas ntfs é outros 500. FAT16 acho meio foda. Pra falar a verdade eu uso 1 setor por cluster e ta de bom tamanho kk Usei sim outros tamanhos só pra testar, dá certo também mas para um sistema pequeno como o meu, é muito desperdício de memória.

FrancisBFTC commented 7 months ago

Tentei usar este FAT de várias formas e não deu. Pois é. Acho que irei continuar com minha técnica

Se sua técnica der mais certo, melhor ainda, porque é mais dinâmico. É o que eu quero fazer também em breve, por enquanto achei mais fácil de forma estática, em arquivos. No seu caso, pode não ta dando certo porque você tem que ir comparando os números da BPB e ver se os parâmetros do DD estão condizentes. Mas acho que talvez também seja outra coisa, você fez 2 alocações diferentes e tem que fazer 4: FAT1, FAT2 (Porque existe a cópia de backup), Diretórios e Dados. Vou mostrar como é que eu organizei minhas tabelas do FAT inteiro e funciona direitinho:

[BITS 16]

FAT_SECTORS EQU 245    ; Quantidade de setores da tabela FAT
ENTRY_SIZE  EQU 32        ; Quantidade de bytes de cada entrada em diretórios
SECTOR_SIZE EQU 512     ; Tamanho do setor

Boot_MBR: 

; Aloca a primeira tabela FAT para 246 setores
FAT1: 
    _FirstSector1:
        db 0xf8, 0xff, 0xff, 0xff
        times (SECTOR_SIZE) - (4) db 0
    _RestSector1:
        times (FAT_SECTORS*SECTOR_SIZE) db 0  ;245

; Aloca a segunda tabela FAT sendo ela um Backup de mesmo tamanho
FAT2:
    _FirstSector2:
        db 0xf8, 0xff, 0xff, 0xff
        times (SECTOR_SIZE) - (4) db 0
    _RestSector2:
        times (FAT_SECTORS*SECTOR_SIZE) db 0  ;245

; Aloca 16.384 bytes = 512 entradas no diretório raiz = 512 arquivos
FAT_ROOTDIRECTORY:
    ;; ## Volume1 entry ##

    ;; Label (Metafile)
    db 0x20, "V",  "O",  "L",  "U",  "M",  "Y",  0x20
    db 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00 
    db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, "Š",  "=" 
    db "Ô",  "R",  0x00, 0x00, 0x00, 0x00, 0x00, 0x00

    times (SECTOR_SIZE * ENTRY_SIZE) - (ENTRY_SIZE * 1) db 0 

; Reserva espaço pra área de dados (onde vai os dados de arquivos)
; Será 33.554.432 bytes no total (32MB), no entanto, temos que calcular a diferença
; Das tabelas anteriores, pra ter o restante pros dados, totalizando 32 MB ao todo  
Data_Area:                                                                                         
    times  (1024 * 1024 * ENTRY_SIZE) - (Data_Area - Boot_MBR) - (512) - (4) db 0 

; Simbolo pra representar o final de todas as tabelas
.end_of_disk:   
    db '*EOD'    ;; ## END OF DISK ##
FrancisBFTC commented 7 months ago

A partir do momento que você tem estas tabelas armazenadas sequencialmente na memória, os números que estão na BPB vão servir pra fazer algum cálculo na VBR e identificar cada região de memória que tem cada uma destas tabela, o inicio e final de cada uma. E aí é recomendável que salve estes valores após calculados, pra você conseguir acessar por outros binários, ao invés de ficar calculando sempre. Você calcula uma vez e salva os valores pra usar depois. E aí você terá as coordenadas de todas estas tabelas que você pode usar e abusar a vontade no driver fat16. Aí assim, a partir do momento que seu disco (VHD, Pendrive, etc), está bem estruturado com estas tabelas, o Windows vai reconhecer o seu disco como FAT16 e isso tem que acontecer, porque se não você não consegue copiar arquivos pro seu disco usando os métodos tradicionais. Depois que o Windows/Linux reconheceu, basta copiar normalmente qualquer arquivo pro seu disco, até usando mouse mesmo, ou comandos copy pelo Windows/Linux, e o sistema vai garantir que sua área de dados, de diretórios e de FAT sejam preenchidos com os dados corretos. A única coisa que você vai ter que fazer é só ler estas tabelas sequencialmente usando os números calculados que foram salvos antes no seu OS.

arthur-cas commented 7 months ago

Terminei o FAT:


[BITS 16]

; ============================== ;

; Directives

; ============================== ;

SECTOR_SIZE         equ 512

FAT_SECTORS         equ 8

; ============================== ;

; FAT table                      ;

; ============================== ;

dw 0xFFF0, 0xFFFF

times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

dw 0xFFF0, 0xFFFF

times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

Usarei DD com seek=1 para colocar o FAT

Tentei usar este FAT de várias formas e não deu. Pois é. Acho que irei continuar com minha técnica

Já tentou usar 2 setores por cluster? kkk 8 ta meio grandinho né. Quem costuma usar 8 é o ntfs, com 4.096 bytes de tamanho de disco pra cada arquivo, mas ntfs é outros 500. FAT16 acho meio foda. Pra falar a verdade eu uso 1 setor por cluster e ta de bom tamanho kk Usei sim outros tamanhos só pra testar, dá certo também mas para um sistema pequeno como o meu, é muito desperdício de memória.

Esse FAT_SECTORS armazena o número de setores por FAT. Mas realmente na tabela antiga 8 setores por cluster é grandão kkkkk. Já tinha alterado para 1 setor porque 8 é grande demais. Agora vou tá experimentando outros valores como 2.

Também agora comecei a fazer a VBR para parar de preguiça. Não carregou ARXLDR aparentemente mas não houve erros. (sofrendo no debug kkkk) Também comecei a fazer o ARXLDR em C para conseguir manusear os endereços melhor.

arthur-cas commented 7 months ago

Tentei usar este FAT de várias formas e não deu. Pois é. Acho que irei continuar com minha técnica

Se sua técnica der mais certo, melhor ainda, porque é mais dinâmico. É o que eu quero fazer também em breve, por enquanto achei mais fácil de forma estática, em arquivos. No seu caso, pode não ta dando certo porque você tem que ir comparando os números da BPB e ver se os parâmetros do DD estão condizentes. Mas acho que talvez também seja outra coisa, você fez 2 alocações diferentes e tem que fazer 4: FAT1, FAT2 (Porque existe a cópia de backup), Diretórios e Dados. Vou mostrar como é que eu organizei minhas tabelas do FAT inteiro e funciona direitinho:

[BITS 16]

FAT_SECTORS EQU 245    ; Quantidade de setores da tabela FAT
ENTRY_SIZE  EQU 32        ; Quantidade de bytes de cada entrada em diretórios
SECTOR_SIZE EQU 512     ; Tamanho do setor

Boot_MBR: 

; Aloca a primeira tabela FAT para 246 setores
FAT1: 
  _FirstSector1:
      db 0xf8, 0xff, 0xff, 0xff
      times (SECTOR_SIZE) - (4) db 0
  _RestSector1:
      times (FAT_SECTORS*SECTOR_SIZE) db 0  ;245

; Aloca a segunda tabela FAT sendo ela um Backup de mesmo tamanho
FAT2:
  _FirstSector2:
      db 0xf8, 0xff, 0xff, 0xff
      times (SECTOR_SIZE) - (4) db 0
  _RestSector2:
      times (FAT_SECTORS*SECTOR_SIZE) db 0  ;245

; Aloca 16.384 bytes = 512 entradas no diretório raiz = 512 arquivos
FAT_ROOTDIRECTORY:
    ;; ## Volume1 entry ##

    ;; Label (Metafile)
    db 0x20, "V",  "O",  "L",  "U",  "M",  "Y",  0x20
    db 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00 
    db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, "Š",  "=" 
    db "Ô",  "R",  0x00, 0x00, 0x00, 0x00, 0x00, 0x00

    times (SECTOR_SIZE * ENTRY_SIZE) - (ENTRY_SIZE * 1) db 0 

; Reserva espaço pra área de dados (onde vai os dados de arquivos)
; Será 33.554.432 bytes no total (32MB), no entanto, temos que calcular a diferença
; Das tabelas anteriores, pra ter o restante pros dados, totalizando 32 MB ao todo    
Data_Area:                                                                                         
    times  (1024 * 1024 * ENTRY_SIZE) - (Data_Area - Boot_MBR) - (512) - (4) db 0 

; Simbolo pra representar o final de todas as tabelas
.end_of_disk:   
    db '*EOD'    ;; ## END OF DISK ##

Não alocava as outras tabelas porque para mim não precisou por causa de que eu iria deixar o root vazio e as outras tabelas também. Eu só criava o arquivo arxdisk.img e colocava o FAT no setor 2. O FAT meu só não tinha dado certo porque o sistema preenchia com outros valores por algum motivo.

arthur-cas commented 7 months ago

Terminei o FAT:

[BITS 16]

; ============================== ;

; Directives

; ============================== ;

SECTOR_SIZE equ 512

FAT_SECTORS equ 8

; ============================== ;

; FAT table ;

; ============================== ;

dw 0xFFF0, 0xFFFF

times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

dw 0xFFF0, 0xFFFF

times (FAT_SECTORS*SECTOR_SIZE) - 4 db 0

Usarei DD com seek=1 para colocar o FAT

Tentei usar este FAT de várias formas e não deu. Pois é. Acho que irei continuar com minha técnica

Já tentou usar 2 setores por cluster? kkk 8 ta meio grandinho né. Quem costuma usar 8 é o ntfs, com 4.096 bytes de tamanho de disco pra cada arquivo, mas ntfs é outros 500. FAT16 acho meio foda. Pra falar a verdade eu uso 1 setor por cluster e ta de bom tamanho kk Usei sim outros tamanhos só pra testar, dá certo também mas para um sistema pequeno como o meu, é muito desperdício de memória.

Esse FAT_SECTORS armazena o número de setores por FAT. Mas realmente na tabela antiga 8 setores por cluster é grandão kkkkk. Já tinha alterado para 1 setor porque 8 é grande demais. Agora vou tá experimentando outros valores como 2.

Também agora comecei a fazer a VBR para parar de preguiça. Não carregou ARXLDR aparentemente mas não houve erros. (sofrendo no debug kkkk) Também comecei a fazer o ARXLDR em C para conseguir manusear os endereços melhor.

Consegui fazer o ARXLDR rodar. É que o ARXLDR gerado pelo objcopy era muito grande daí resolvi com uns parâmetros. Agora pensei em voltar pro assembly mesmo e usar C no kernel.

FrancisBFTC commented 7 months ago

Esse FAT_SECTORS armazena o número de setores por FAT. Mas realmente na tabela antiga 8 setores por cluster é grandão kkkkk. Já tinha alterado para 1 setor porque 8 é grande demais. Agora vou tá experimentando outros valores como 2.

Também agora comecei a fazer a VBR para parar de preguiça. Não carregou ARXLDR aparentemente mas não houve erros. (sofrendo no debug kkkk) Também comecei a fazer o ARXLDR em C para conseguir manusear os endereços melhor.

Não alocava as outras tabelas porque para mim não precisou por causa de que eu iria deixar o root vazio e as outras tabelas também. Eu só criava o arquivo arxdisk.img e colocava o FAT no setor 2. O FAT meu só não tinha dado certo porque o sistema preenchia com outros valores por algum motivo.

Consegui fazer o ARXLDR rodar. É que o ARXLDR gerado pelo objcopy era muito grande daí resolvi com uns parâmetros. Agora pensei em voltar pro assembly mesmo e usar C no kernel.

Ah sim, entendi, eu vi só duas tabelas, então você fez a cópia de backup do FAT tudo certinho tendo 8 setores cada porém não fez a de diretórios e a de dados né, entendi. Realmente, 8 por cluster é bem grande, acredito que seja melhor quando for no FAT32, e o sistema já tiver maior, aí sim. Modo real nem vale a pena esquentar com isso kkk.

Debug realmente sofre, mas acho que encontra o erro mais rápido do que no olho. Legal no caso do ARXLDR, tipo, o que você planeja fazer no arxldr, talvez eu já faço no Autogen.bat, pra calcular os endereços, antes da inicialização do sistema, porém pra gerenciamento de memória eu vou usar outro método, que é o controle da GDT e rotinas malloc, realloc e free.

Ah sim, deixaria o Root e a área de dados vazios, assim, usando a técnica de carregamento dinâmico, beleza, contanto que você tenha esse código pra reservar espaço da área de diretórios e da áreas de dados, mesmo que dinamicamente pelo código, aí beleza. No meu caso eu realmente não vi outra forma de funcionar além de ter tudo definidinho ali a área de diretórios e área de dados, com valores fixos. Só foi dessa forma que o Windows reconheceu meu pendrive com o KiddieOS como FAT16, e que me deixou adicionar arquivos no mouse também. Mas eu quero fazer tudo isso dinamicamente, sem precisar ter essas tabelas fixas, mas estas tabelas serem criadas na instalação do sistema, aí sim, vai ser outro nível. :D Até porque a área de diretórios o Windows/Linux coloca dados de arquivos lá, e Área de dados também, então tem que ter o espaço reservado ali sabe.

Ta, só um exemplinho aqui pra fechar: Na sua BPB você colocou na variável bpbRootEntries que tem 512 entradas, certo? Cada entrada tem 32 bytes e é de um arquivo diferente. Você tem as tabelas do FAT tudo certinho, cada uma contendo 512 * 8 = 4.096 bytes de tamanho, já que são duas, então 8192 bytes. Okay, digamos que você carregou seu FAT no setor 1 do disco, ele vai até o setor 8, o próximo FAT fica no setor 9 e vai até o setor 16, aí dá exatamente 8192 bytes e você deve garantir isso. A partir do setor 17 você deve garantir que tenha espaço reservado para a área de diretórios, pois já que você definiu na BPB que tem 512 entradas, qualquer sistema operacional (Windows, Linux, Mac, etc..) que for ler o seu disco (VHD, IMG, Pendrive, CD-ROM, etc.) esse sistema operacional vai tentar ler o setor 17 onde fica sua área de diretórios (Vai conter arquivos e pastas, um diretório raiz deve existir, para os outros existirem também, os outros não necessariamente fica na mesma região do disco). E aí quando este sistema for ler o setor 17 e procurar procurar e não encontrar nada, ele não reconhece o seu sistema de arquivos, ou dá vários outros problemas lá. E outra coisa também, se tem 512 entradas e cada entrada tem 32 bytes, então tem 16384 bytes sua área de diretório raiz reservada no disco, logo o seu sistema e todos os outros sistemas vão saber que sua área de dados (onde vão os dados brutos dos arquivos) fica a partir do setor (17 + (16384 / 512)), ou seja, no setor 49. E eles sabendo dessa informação, é a partir daí que ele vai tentar procurar os dados de arquivos pra carregar (Inclusive pastas, propriedades de pastas e arquivos também ficam na área de dados, contanto que a pasta raiz esteja no diretório raiz, no setor 17). Ou seja, a sua BPB vai ser um manual de instrução pra quando qualquer SO (inclusive o seu) quiser compreender como trabalhar com seu sistema de arquivos, o SO saber como. Logo, sua área de diretórios a partir do setor 17 na suposição não pode de forma alguma ficar vazia, ela pode estar reservada, tipo zerada, porém tem que tem no mínimo 3 entradas lá: A 1ª entrada padrão, uma entrada que representa o próprio diretório com atributo/tipo "DIRETÓRIO" e +1 entrada de um arquivo binário, que pode um kernel ou qualquer outro, daí 32 bytes cada, então 96 bytes. Se não tiver nenhuma destas entradas, ou tiver faltando uma, realmente seu sistema não vai funcionar por completo. Mas beleza, o que vai valer também é sua VBR, se ela tiver carregando direitinho na memória algum binário usando os métodos tradicionais de cálculos do FAT16, aí ta tudo certo.

FrancisBFTC commented 7 months ago

Pois é man, já fechei a issue do write, já resolvi tudo lá e fiz novas atualizações, a descrição está no pull request, que vou realizar o merge agora. Vou fechar essa issue agora neste comentário. Foi bom falar contigo, vou abrir outra issue relacionado a outro bug que devo resolver do comando del.