Closed arthur-cas closed 7 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.
Quando insiro nenhum comando e aperto enter na interface de comandos, o KiddieOS trava.
Vou começar a procurar sobre esse bug agora.
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.
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:
E a tela do shell vai ser assim:
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).
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.
Um exemplo da ideia que falei em partes de códigos:
irq_num db 0 ; esta é a IRQ do TIMER
......
......
irq_num db 1 ; esta é a IRQ do teclado
......
......
K:\> loaddrv KiddieOS\Drivers\timer.drv
K:\> loaddrv KiddieOS\Drivers\keyboard.drv
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:
[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?
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 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; }
init_vesa 0x100 read_pixel 0x900 convxy 0x1234
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.
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.
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.
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
Estou tentando resolver este erro de leitura no código ainda. Nem sei o porque disso acontecer.
Inclusive usei um código seu de ajuda para fazer a parte do cálculo porque é o que mais se encaixa no meu caso
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.
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.
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?
> 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:
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.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.
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.
> 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.
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
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".
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.
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).
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.
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.
Eu usei apenas ES para controlar segmento. É porque eu coloquei tudo no mesmo segmento.
Eu usei apenas ES para controlar segmento. É porque eu coloquei tudo no mesmo segmento.
Ah sim, entendi. Legal, facilita mais mesmo.
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.
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)
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)
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.
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.
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.
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(;;);
}
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
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
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
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
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.
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.
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 ##
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.
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.
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.
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.
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.
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
.
Quando insiro nenhum comando e aperto enter na interface de comandos, o KiddieOS trava.