209 lines
No EOL
7.2 KiB
NASM
209 lines
No EOL
7.2 KiB
NASM
; =============================================================================
|
||
; Project : Custom BIOS / ROM
|
||
; File : generic.asm
|
||
; Author : frater
|
||
;
|
||
; License : GNU General Public License v3.0 or later (GPL-3.0+)
|
||
;
|
||
; This program is free software: you can redistribute it and/or modify
|
||
; it under the terms of the GNU General Public License as published by
|
||
; the Free Software Foundation, either version 3 of the License, or
|
||
; (at your option) any later version.
|
||
;
|
||
; This program is distributed in the hope that it will be useful,
|
||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
; GNU General Public License for more details.
|
||
;
|
||
; You should have received a copy of the GNU General Public License
|
||
; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
;
|
||
; =============================================================================
|
||
|
||
; ---------------------------------------------------------------------------
|
||
; Détection RAM conventionnelle
|
||
; Teste la RAM de MEM_SEG_DEB -> MEM_SEG_END (0xA000, 640KB), par pas de 1KB.
|
||
; Méthode: sauvegarde 1 mot, écrit 2 patterns, relit, restaure.
|
||
;
|
||
; Résultats:
|
||
; AX = taille détectée en Ko (KB) à partir de 0 jusqu’au “top conventionnel”
|
||
; DX = top_segment (segment du premier Ko NON valide) (optionnel)
|
||
;
|
||
; Précautions:
|
||
; - Ne testez PAS une zone où se trouve votre pile / variables.
|
||
; - Si votre pile est à 0000:7C00 (phys 0x7C00), commencez au moins à 0x0800.
|
||
; - Ne testez pas au-delà de MEM_SEG_END (0xA000: début VGA/vidéo).
|
||
; ---------------------------------------------------------------------------
|
||
ram_setup:
|
||
xor ax, ax ; AX = compteur KB trouvés
|
||
mov dx, MEM_SEG_DEB ; DX = segment courant testé
|
||
mov cx, MEM_SEG_END ; CX = segment fin (exclu)
|
||
xor di, di ; tester au début du bloc 1KB: ES:0000
|
||
|
||
.loop_seg:
|
||
cmp dx, cx
|
||
jae .done
|
||
mov es, dx
|
||
|
||
; sauvegarder le mot existant
|
||
mov bx, [es:di]
|
||
|
||
; pattern 1
|
||
mov word [es:di], 0x55AA
|
||
cmp word [es:di], 0x55AA
|
||
jne .fail_restore
|
||
|
||
; pattern 2 (inverse)
|
||
mov word [es:di], 0xAA55
|
||
cmp word [es:di], 0xAA55
|
||
jne .fail_restore
|
||
|
||
; restaurer
|
||
mov [es:di], bx
|
||
|
||
; OK: avancer d’1KB
|
||
inc ax ; +1KB valide
|
||
add dx, MEM_SEG_STEP
|
||
jmp .loop_seg
|
||
|
||
.fail_restore:
|
||
; restaurer avant de sortir
|
||
mov [es:di], bx
|
||
|
||
.done:
|
||
; AX contient le nb de KB valides *à partir de MEM_SEG_DEB*.
|
||
; Si vous voulez une taille “depuis 0KB”, ajoutez MEM_SEG_DEB*16/1024 = MEM_SEG_DEB/64.
|
||
;
|
||
; base_kb = MEM_SEG_DEB / 0x0040 (car 1KB = 0x40 segments)
|
||
mov bx, MEM_SEG_DEB
|
||
shr bx, 6 ; /64 = /0x40 => KB de base
|
||
add ax, bx ; AX = taille conventionnelle totale en KB (approx. 0..640)
|
||
; DX = segment du premier bloc NON valide (top)
|
||
; DX est déjà positionné (segment courant)
|
||
|
||
; stocker l'information dans le BDA
|
||
mov bx, BDA_SEGMENT
|
||
mov ds, bx
|
||
mov [BDA_INFO_MEM_SIZE], ax
|
||
mov [BDA_INFO_MEM_SEG],dx
|
||
|
||
ret
|
||
|
||
; ---------------------------------------------------------------------------
|
||
; Détection les ROM supplementaires
|
||
; Teste la RAM de 0xC000 jusqu’à 0xE000, par pas de 2KB.
|
||
;
|
||
; Si une ROM est détectée, le code de la ROM sera appelé.
|
||
; ---------------------------------------------------------------------------
|
||
setup_load_rom:
|
||
mov bx, 0xC000
|
||
.scanloop:
|
||
mov ds, bx
|
||
cmp word[0x0000],0xAA55 ; ROM signature
|
||
jne .norom
|
||
|
||
; Debug
|
||
mov al,'.'
|
||
call debug_putc
|
||
|
||
; appel le code (en 0x0003) de la ROM
|
||
push cs
|
||
push word .norom ; address de retour
|
||
|
||
push ds
|
||
push 0x0003
|
||
retf ; call far ds:0x0003
|
||
.norom:
|
||
add bx, 0x80 ; add 2kb
|
||
cmp bx, 0xE000
|
||
jbe .scanloop
|
||
.end:
|
||
ret
|
||
|
||
; ---------------------------------------------------------------------------
|
||
; Test si le vecteur INT 10h à été modifié (par la ROM)
|
||
;
|
||
; Si le vecteur n'a pas été modifiée, on considère que la ROM video n'a pas
|
||
; été chargée.
|
||
; ---------------------------------------------------------------------------
|
||
setup_check_vga:
|
||
; vérification de l'offset 0x0000:0x0040 qui DOIT etre différent de @default_isr
|
||
xor ax,ax
|
||
mov es,ax
|
||
; Lire INT10: offset+segment depuis 0000:0040
|
||
mov bx, [es:0x0040] ; BX = offset INT10
|
||
mov cx, [es:0x0042] ; CX = segment INT10
|
||
mov ax, cs
|
||
|
||
; Comparer avec default_isr (offset) et CS (segment)
|
||
mov dx, default_isr ; DX = offset default_isr (dans notre CS)
|
||
cmp bx, dx
|
||
jne .init_ok ; vecteur different, bios initialisé
|
||
cmp cx, ax
|
||
jne .init_ok
|
||
|
||
mov ax,cs ; vecteur identique, sans doute pas d'initialisation
|
||
mov ds,ax
|
||
|
||
mov si, err_vganok
|
||
call debug_puts
|
||
.init_ok:
|
||
ret
|
||
|
||
|
||
; ---------------------------------------------------------------------------
|
||
; IVT install (8088, mode réel) - remplit les 256 vecteurs avec un handler IRET
|
||
; ---------------------------------------------------------------------------
|
||
ivt_setup:
|
||
; installation de la table d'interrupts
|
||
xor ax, ax
|
||
mov es, ax ; ES = 0000h -> base IVT
|
||
xor di, di ; DI = 0000h -> offset IVT
|
||
|
||
mov ax, default_isr ; offset du handler
|
||
mov dx, cs ; segment du handler (ROM)
|
||
|
||
mov cx, 256 ; 256 vecteurs
|
||
.fill:
|
||
stosw ; write offset (AX) -> [ES:DI], DI += 2
|
||
xchg ax, dx ; AX = segment, DX = offset
|
||
stosw ; write segment (AX) -> [ES:DI], DI += 2
|
||
xchg ax, dx ; AX = offset, DX = segment
|
||
loop .fill
|
||
; fin de la table d'interrupt
|
||
ret
|
||
|
||
; ---------------------------------------------------------------------------
|
||
; IVT install (8088, mode réel) - installe un handler a une interrupt calculée
|
||
;
|
||
; ax = int id
|
||
; dx = segment handler
|
||
; bx = offset handler
|
||
; ---------------------------------------------------------------------------
|
||
ivt_setvector:
|
||
push es
|
||
push di
|
||
|
||
shl ax,2 ; ax=id *4
|
||
mov di,ax
|
||
|
||
xor ax,ax
|
||
mov es, ax ; ES = 0000h -> base IVT
|
||
|
||
mov ax, bx ; offset du handler
|
||
cli
|
||
stosw ; write offset (AX) -> [ES:DI], DI += 2
|
||
xchg ax, dx ; AX = segment, DX = offset
|
||
stosw ; write segment (AX) -> [ES:DI], DI += 2
|
||
sti
|
||
|
||
pop di
|
||
pop es
|
||
ret
|
||
|
||
; ---------------------------------------------------------------------------
|
||
; Handler par défaut: fait juste IRET
|
||
; IMPORTANT: doit être FAR (appelé par le CPU via IVT), et terminer par IRET
|
||
; ---------------------------------------------------------------------------
|
||
default_isr:
|
||
iret |