CTAOS v3
This commit is contained in:
16
SysBoot/makeall.bat
Normal file
16
SysBoot/makeall.bat
Normal file
@@ -0,0 +1,16 @@
|
||||
@echo off
|
||||
set nasm_path=C:\nasm
|
||||
set djgpp_path=C:\DJGPP\bin
|
||||
|
||||
@echo ***************** CTA Bootloader *****************
|
||||
@echo.
|
||||
|
||||
:Stage1
|
||||
cd stage1
|
||||
call make.bat
|
||||
cd..
|
||||
|
||||
:Stage2
|
||||
cd stage2
|
||||
call make.bat
|
||||
cd..
|
BIN
SysBoot/stage1/BOOTLOAD.BIN
Normal file
BIN
SysBoot/stage1/BOOTLOAD.BIN
Normal file
Binary file not shown.
314
SysBoot/stage1/bootload.asm
Normal file
314
SysBoot/stage1/bootload.asm
Normal file
@@ -0,0 +1,314 @@
|
||||
|
||||
;*********************************************
|
||||
; Boot1.asm
|
||||
; - A Simple Bootloader
|
||||
;
|
||||
; Operating Systems Development Series
|
||||
;*********************************************
|
||||
|
||||
bits 16 ; we are in 16 bit real mode
|
||||
|
||||
org 0 ; we will set regisers later
|
||||
|
||||
start: jmp main ; jump to start of bootloader
|
||||
|
||||
;*********************************************
|
||||
; BIOS Parameter Block
|
||||
;*********************************************
|
||||
|
||||
; BPB Begins 3 bytes from start. We do a far jump, which is 3 bytes in size.
|
||||
; If you use a short jump, add a "nop" after it to offset the 3rd byte.
|
||||
|
||||
bpbOEM db "CTA OS " ; OEM identifier (Cannot exceed 8 bytes!)
|
||||
bpbBytesPerSector: DW 512
|
||||
bpbSectorsPerCluster: DB 1
|
||||
bpbReservedSectors: DW 1
|
||||
bpbNumberOfFATs: DB 2
|
||||
bpbRootEntries: DW 224
|
||||
bpbTotalSectors: DW 2880
|
||||
bpbMedia: DB 0xf8 ;; 0xF1
|
||||
bpbSectorsPerFAT: DW 9
|
||||
bpbSectorsPerTrack: DW 18
|
||||
bpbHeadsPerCylinder: DW 2
|
||||
bpbHiddenSectors: DD 0
|
||||
bpbTotalSectorsBig: DD 0
|
||||
bsDriveNumber: DB 0
|
||||
bsUnused: DB 0
|
||||
bsExtBootSignature: DB 0x29
|
||||
bsSerialNumber: DD 0xa0a1a2a3
|
||||
bsVolumeLabel: DB "CTA FLOPPY "
|
||||
bsFileSystem: DB "FAT12 "
|
||||
|
||||
;************************************************;
|
||||
; Prints a string
|
||||
; DS=>SI: 0 terminated string
|
||||
;************************************************;
|
||||
Print:
|
||||
lodsb ; load next byte from string from SI to AL
|
||||
or al, al ; Does AL=0?
|
||||
jz PrintDone ; Yep, null terminator found-bail out
|
||||
mov ah, 0eh ; Nope-Print the character
|
||||
int 10h
|
||||
jmp Print ; Repeat until null terminator found
|
||||
PrintDone:
|
||||
ret ; we are done, so return
|
||||
|
||||
;************************************************;
|
||||
; Reads a series of sectors
|
||||
; CX=>Number of sectors to read
|
||||
; AX=>Starting sector
|
||||
; ES:BX=>Buffer to read to
|
||||
;************************************************;
|
||||
|
||||
ReadSectors:
|
||||
.MAIN:
|
||||
mov di, 0x0005 ; five retries for error
|
||||
.SECTORLOOP:
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
call LBACHS ; convert starting sector to CHS
|
||||
mov ah, 0x02 ; BIOS read sector
|
||||
mov al, 0x01 ; read one sector
|
||||
mov ch, BYTE [absoluteTrack] ; track
|
||||
mov cl, BYTE [absoluteSector] ; sector
|
||||
mov dh, BYTE [absoluteHead] ; head
|
||||
mov dl, BYTE [bsDriveNumber] ; drive
|
||||
int 0x13 ; invoke BIOS
|
||||
jnc .SUCCESS ; test for read error
|
||||
xor ax, ax ; BIOS reset disk
|
||||
int 0x13 ; invoke BIOS
|
||||
dec di ; decrement error counter
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
jnz .SECTORLOOP ; attempt to read again
|
||||
int 0x18
|
||||
.SUCCESS:
|
||||
mov si, msgProgress
|
||||
call Print
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
add bx, WORD [bpbBytesPerSector] ; queue next buffer
|
||||
inc ax ; queue next sector
|
||||
loop .MAIN ; read next sector
|
||||
ret
|
||||
|
||||
;************************************************;
|
||||
; Convert CHS to LBA
|
||||
; LBA = (cluster - 2) * sectors per cluster
|
||||
;************************************************;
|
||||
|
||||
ClusterLBA:
|
||||
sub ax, 0x0002 ; zero base cluster number
|
||||
xor cx, cx
|
||||
mov cl, BYTE [bpbSectorsPerCluster] ; convert byte to word
|
||||
mul cx
|
||||
add ax, WORD [datasector] ; base data sector
|
||||
ret
|
||||
|
||||
;************************************************;
|
||||
; Convert LBA to CHS
|
||||
; AX=>LBA Address to convert
|
||||
;
|
||||
; absolute sector = (logical sector / sectors per track) + 1
|
||||
; absolute head = (logical sector / sectors per track) MOD number of heads
|
||||
; absolute track = logical sector / (sectors per track * number of heads)
|
||||
;
|
||||
;************************************************;
|
||||
|
||||
LBACHS:
|
||||
xor dx, dx ; prepare dx:ax for operation
|
||||
div WORD [bpbSectorsPerTrack] ; calculate
|
||||
inc dl ; adjust for sector 0
|
||||
mov BYTE [absoluteSector], dl
|
||||
xor dx, dx ; prepare dx:ax for operation
|
||||
div WORD [bpbHeadsPerCylinder] ; calculate
|
||||
mov BYTE [absoluteHead], dl
|
||||
mov BYTE [absoluteTrack], al
|
||||
ret
|
||||
|
||||
;*********************************************
|
||||
; Bootloader Entry Point
|
||||
;*********************************************
|
||||
|
||||
main:
|
||||
|
||||
;----------------------------------------------------
|
||||
; code located at 0000:7C00, adjust segment registers
|
||||
;----------------------------------------------------
|
||||
|
||||
cli ; disable interrupts
|
||||
mov ax, 0x07C0 ; setup registers to point to our segment
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
;----------------------------------------------------
|
||||
; create stack
|
||||
;----------------------------------------------------
|
||||
|
||||
mov ax, 0x0000 ; set the stack
|
||||
mov ss, ax
|
||||
mov sp, 0xFFFF
|
||||
sti ; restore interrupts
|
||||
|
||||
;----------------------------------------------------
|
||||
; Display loading message
|
||||
;----------------------------------------------------
|
||||
|
||||
mov si, msgLoading
|
||||
call Print
|
||||
|
||||
;----------------------------------------------------
|
||||
; Load root directory table
|
||||
;----------------------------------------------------
|
||||
|
||||
LOAD_ROOT:
|
||||
|
||||
; compute size of root directory and store in "cx"
|
||||
|
||||
xor cx, cx
|
||||
xor dx, dx
|
||||
mov ax, 0x0020 ; 32 byte directory entry
|
||||
mul WORD [bpbRootEntries] ; total size of directory
|
||||
div WORD [bpbBytesPerSector] ; sectors used by directory
|
||||
xchg ax, cx
|
||||
|
||||
; compute location of root directory and store in "ax"
|
||||
|
||||
mov al, BYTE [bpbNumberOfFATs] ; number of FATs
|
||||
mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
|
||||
add ax, WORD [bpbReservedSectors] ; adjust for bootsector
|
||||
mov WORD [datasector], ax ; base of root directory
|
||||
add WORD [datasector], cx
|
||||
|
||||
; read root directory into memory (7C00:0200)
|
||||
|
||||
mov bx, 0x0200 ; copy root dir above bootcode
|
||||
call ReadSectors
|
||||
|
||||
;----------------------------------------------------
|
||||
; Find stage 2
|
||||
;----------------------------------------------------
|
||||
|
||||
; browse root directory for binary image
|
||||
mov cx, WORD [bpbRootEntries] ; load loop counter
|
||||
mov di, 0x0200 ; locate first root entry
|
||||
.LOOP:
|
||||
push cx
|
||||
mov cx, 0x000B ; eleven character name
|
||||
mov si, ImageName ; image name to find
|
||||
push di
|
||||
rep cmpsb ; test for entry match
|
||||
pop di
|
||||
je LOAD_FAT
|
||||
pop cx
|
||||
add di, 0x0020 ; queue next directory entry
|
||||
loop .LOOP
|
||||
jmp FAILURE
|
||||
|
||||
;----------------------------------------------------
|
||||
; Load FAT
|
||||
;----------------------------------------------------
|
||||
|
||||
LOAD_FAT:
|
||||
|
||||
; save starting cluster of boot image
|
||||
|
||||
mov dx, WORD [di + 0x001A]
|
||||
mov WORD [cluster], dx ; file's first cluster
|
||||
|
||||
; compute size of FAT and store in "cx"
|
||||
|
||||
xor ax, ax
|
||||
mov al, BYTE [bpbNumberOfFATs] ; number of FATs
|
||||
mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
|
||||
mov cx, ax
|
||||
|
||||
; compute location of FAT and store in "ax"
|
||||
|
||||
mov ax, WORD [bpbReservedSectors] ; adjust for bootsector
|
||||
|
||||
; read FAT into memory (7C00:0200)
|
||||
|
||||
mov bx, 0x0200 ; copy FAT above bootcode
|
||||
call ReadSectors
|
||||
|
||||
; read image file into memory (0050:0000)
|
||||
|
||||
mov ax, 0x0050
|
||||
mov es, ax ; destination for image
|
||||
mov bx, 0x0000 ; destination for image
|
||||
push bx
|
||||
|
||||
;----------------------------------------------------
|
||||
; Load Stage 2
|
||||
;----------------------------------------------------
|
||||
|
||||
LOAD_IMAGE:
|
||||
|
||||
mov ax, WORD [cluster] ; cluster to read
|
||||
pop bx ; buffer to read into
|
||||
call ClusterLBA ; convert cluster to LBA
|
||||
xor cx, cx
|
||||
mov cl, BYTE [bpbSectorsPerCluster] ; sectors to read
|
||||
call ReadSectors
|
||||
push bx
|
||||
|
||||
; compute next cluster
|
||||
|
||||
mov ax, WORD [cluster] ; identify current cluster
|
||||
mov cx, ax ; copy current cluster
|
||||
mov dx, ax ; copy current cluster
|
||||
shr dx, 0x0001 ; divide by two
|
||||
add cx, dx ; sum for (3/2)
|
||||
mov bx, 0x0200 ; location of FAT in memory
|
||||
add bx, cx ; index into FAT
|
||||
mov dx, WORD [bx] ; read two bytes from FAT
|
||||
test ax, 0x0001
|
||||
jnz .ODD_CLUSTER
|
||||
|
||||
.EVEN_CLUSTER:
|
||||
|
||||
and dx, 0000111111111111b ; take low twelve bits
|
||||
jmp .DONE
|
||||
|
||||
.ODD_CLUSTER:
|
||||
|
||||
shr dx, 0x0004 ; take high twelve bits
|
||||
|
||||
.DONE:
|
||||
|
||||
mov WORD [cluster], dx ; store new cluster
|
||||
cmp dx, 0x0FF0 ; test for end of file
|
||||
jb LOAD_IMAGE
|
||||
|
||||
DONE:
|
||||
push WORD 0x0050
|
||||
push WORD 0x0000
|
||||
retf
|
||||
|
||||
FAILURE:
|
||||
|
||||
mov si, msgFailure
|
||||
call Print
|
||||
mov ah, 0x00
|
||||
int 0x16 ; await keypress
|
||||
int 0x19 ; warm boot computer
|
||||
|
||||
absoluteSector db 0x00
|
||||
absoluteHead db 0x00
|
||||
absoluteTrack db 0x00
|
||||
|
||||
datasector dw 0x0000
|
||||
cluster dw 0x0000
|
||||
ImageName db "STAGE2 CTA"
|
||||
msgLoading db 0x0D, "CTA OS v0.1", 0x0A, 0x0D, "(c) CTA 2010", 0x0A, 0x0D, "Loading", 0x00
|
||||
msgProgress db ".", 0x00
|
||||
msgFailure db 0x0D, 0x0A, "Error: Could not find stage2.bin. Press any key to reboot.", 0x0A, 0x00
|
||||
|
||||
TIMES 510-($-$$) db 0
|
||||
DW 0xAA55
|
23
SysBoot/stage1/make.bat
Normal file
23
SysBoot/stage1/make.bat
Normal file
@@ -0,0 +1,23 @@
|
||||
@echo off
|
||||
set nasm_path=C:\nasm
|
||||
set djgpp_path=C:\DJGPP\bin
|
||||
|
||||
goto build
|
||||
|
||||
:error
|
||||
@echo.
|
||||
@echo There have been build errors. Building halted.
|
||||
@pause
|
||||
exit
|
||||
|
||||
:build
|
||||
@echo Compiling stage 1...
|
||||
del bootload.bin
|
||||
%nasm_path%\nasm.exe -f bin bootload.asm -o bootload.bin
|
||||
|
||||
:check
|
||||
if not exist bootload.bin goto error
|
||||
|
||||
:copy
|
||||
@echo Writing stage 1 to floppy boot sector...
|
||||
debug bootload.bin <..\..\scripts\stage1d >nul
|
24
SysBoot/stage2/MAKE.BAT
Normal file
24
SysBoot/stage2/MAKE.BAT
Normal file
@@ -0,0 +1,24 @@
|
||||
@echo off
|
||||
set nasm_path=C:\nasm
|
||||
set djgpp_path=C:\DJGPP\bin
|
||||
|
||||
goto build
|
||||
|
||||
:error
|
||||
@echo.
|
||||
@echo There have been build errors. Building halted.
|
||||
@pause
|
||||
exit
|
||||
|
||||
:build
|
||||
|
||||
@echo Compiling stage 2...
|
||||
del stage2.cta
|
||||
%nasm_path%\nasm.exe -f bin stage2.asm -o stage2.cta
|
||||
|
||||
:test
|
||||
if not exist stage2.cta goto error
|
||||
|
||||
:copy
|
||||
@echo Copying stage 2 to floppy...
|
||||
copy stage2.cta A:\stage2.cta >nul
|
BIN
SysBoot/stage2/STAGE2.CTA
Normal file
BIN
SysBoot/stage2/STAGE2.CTA
Normal file
Binary file not shown.
55
SysBoot/stage2/a20.inc
Normal file
55
SysBoot/stage2/a20.inc
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
|
||||
;********************************************
|
||||
; Enable A20 address line
|
||||
;
|
||||
; OS Development Series
|
||||
;********************************************
|
||||
|
||||
bits 16 ; real mode 16 bit code
|
||||
|
||||
_EnableA20:
|
||||
|
||||
cli
|
||||
|
||||
call a20wait
|
||||
mov al,0xAD
|
||||
out 0x64,al
|
||||
|
||||
call a20wait
|
||||
mov al,0xD0
|
||||
out 0x64,al
|
||||
|
||||
call a20wait2
|
||||
in al,0x60
|
||||
push eax
|
||||
|
||||
call a20wait
|
||||
mov al,0xD1
|
||||
out 0x64,al
|
||||
|
||||
call a20wait
|
||||
pop eax
|
||||
or al,2
|
||||
out 0x60,al
|
||||
|
||||
call a20wait
|
||||
mov al,0xAE
|
||||
out 0x64,al
|
||||
|
||||
call a20wait
|
||||
sti
|
||||
ret
|
||||
|
||||
a20wait:
|
||||
in al,0x64
|
||||
test al,2
|
||||
jnz a20wait
|
||||
ret
|
||||
|
||||
|
||||
a20wait2:
|
||||
in al,0x64
|
||||
test al,1
|
||||
jz a20wait2
|
||||
ret
|
40
SysBoot/stage2/bootinfo.inc
Normal file
40
SysBoot/stage2/bootinfo.inc
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
;*******************************************************
|
||||
;
|
||||
; bootinfo.inc
|
||||
; multiboot information structure
|
||||
;
|
||||
; OS Development Series
|
||||
;*******************************************************
|
||||
|
||||
%ifndef __BOOTINFO_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
%define __BOOTINFO_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
|
||||
struc multiboot_info
|
||||
.flags resd 1
|
||||
.memoryLo resd 1
|
||||
.memoryHi resd 1
|
||||
.bootDevice resd 1
|
||||
.cmdLine resd 1
|
||||
.mods_count resd 1
|
||||
.mods_addr resd 1
|
||||
.syms0 resd 1
|
||||
.syms1 resd 1
|
||||
.syms2 resd 1
|
||||
.mmap_length resd 1
|
||||
.mmap_addr resd 1
|
||||
.drives_length resd 1
|
||||
.drives_addr resd 1
|
||||
.config_table resd 1
|
||||
.bootloader_name resd 1
|
||||
.apm_table resd 1
|
||||
.vbe_control_info resd 1
|
||||
.vbe_mode_info resd 1
|
||||
.vbe_mode resw 1
|
||||
.vbe_interface_seg resw 1
|
||||
.vbe_interface_off resw 1
|
||||
.vbe_interface_len resw 1
|
||||
endstruc
|
||||
|
||||
|
||||
%endif
|
17
SysBoot/stage2/common.inc
Normal file
17
SysBoot/stage2/common.inc
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
%ifndef _COMMON_INC_INCLUDED
|
||||
%define _COMMON_INC_INCLUDED
|
||||
|
||||
; where the kernel is to be loaded to in protected mode
|
||||
%define IMAGE_PMODE_BASE 0x100000
|
||||
|
||||
; where the kernel is to be loaded to in real mode
|
||||
%define IMAGE_RMODE_BASE 0x3000
|
||||
|
||||
; kernel name (Must be 11 bytes)
|
||||
ImageName db "KERNEL CTA"
|
||||
|
||||
; size of kernel image in bytes
|
||||
ImageSize db 0
|
||||
|
||||
%endif
|
246
SysBoot/stage2/fat12.inc
Normal file
246
SysBoot/stage2/fat12.inc
Normal file
@@ -0,0 +1,246 @@
|
||||
|
||||
;*******************************************************
|
||||
;
|
||||
; Fat12.inc
|
||||
; FAT12 filesystem for 3-1/2 floppies
|
||||
;
|
||||
; OS Development Series
|
||||
;*******************************************************
|
||||
|
||||
%ifndef __FAT12_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
%define __FAT12_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
|
||||
bits 16
|
||||
|
||||
%include "Floppy16.inc" ; the erm.. floppy driver
|
||||
|
||||
%define ROOT_OFFSET 0x2e00
|
||||
%define FAT_SEG 0x2c0
|
||||
%define ROOT_SEG 0x2e0
|
||||
|
||||
;*******************************************
|
||||
; LoadRoot ()
|
||||
; - Load Root Directory Table to 0x7e00
|
||||
;*******************************************
|
||||
|
||||
LoadRoot:
|
||||
|
||||
pusha ; store registers
|
||||
push es
|
||||
|
||||
; compute size of root directory and store in "cx"
|
||||
|
||||
xor cx, cx ; clear registers
|
||||
xor dx, dx
|
||||
mov ax, 32 ; 32 byte directory entry
|
||||
mul WORD [bpbRootEntries] ; total size of directory
|
||||
div WORD [bpbBytesPerSector] ; sectors used by directory
|
||||
xchg ax, cx ; move into AX
|
||||
|
||||
; compute location of root directory and store in "ax"
|
||||
|
||||
mov al, BYTE [bpbNumberOfFATs] ; number of FATs
|
||||
mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
|
||||
add ax, WORD [bpbReservedSectors]
|
||||
mov WORD [datasector], ax ; base of root directory
|
||||
add WORD [datasector], cx
|
||||
|
||||
; read root directory into 0x7e00
|
||||
|
||||
push word ROOT_SEG
|
||||
pop es
|
||||
mov bx, 0 ; copy root dir
|
||||
call ReadSectors ; read in directory table
|
||||
pop es
|
||||
popa ; restore registers and return
|
||||
ret
|
||||
|
||||
;*******************************************
|
||||
; LoadFAT ()
|
||||
; - Loads FAT table to 0x7c00
|
||||
;
|
||||
; Parm/ ES:DI => Root Directory Table
|
||||
;*******************************************
|
||||
|
||||
LoadFAT:
|
||||
|
||||
pusha ; store registers
|
||||
push es
|
||||
|
||||
; compute size of FAT and store in "cx"
|
||||
|
||||
xor ax, ax
|
||||
mov al, BYTE [bpbNumberOfFATs] ; number of FATs
|
||||
mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
|
||||
mov cx, ax
|
||||
|
||||
; compute location of FAT and store in "ax"
|
||||
|
||||
mov ax, WORD [bpbReservedSectors]
|
||||
|
||||
; read FAT into memory (Overwrite our bootloader at 0x7c00)
|
||||
|
||||
push word FAT_SEG
|
||||
pop es
|
||||
xor bx, bx
|
||||
call ReadSectors
|
||||
pop es
|
||||
popa ; restore registers and return
|
||||
ret
|
||||
|
||||
;*******************************************
|
||||
; FindFile ()
|
||||
; - Search for filename in root table
|
||||
;
|
||||
; parm/ DS:SI => File name
|
||||
; ret/ AX => File index number in directory table. -1 if error
|
||||
;*******************************************
|
||||
|
||||
FindFile:
|
||||
|
||||
push cx ; store registers
|
||||
push dx
|
||||
push bx
|
||||
mov bx, si ; copy filename for later
|
||||
|
||||
; browse root directory for binary image
|
||||
|
||||
mov cx, WORD [bpbRootEntries] ; load loop counter
|
||||
mov di, ROOT_OFFSET ; locate first root entry at 1 MB mark
|
||||
cld ; clear direction flag
|
||||
|
||||
.LOOP:
|
||||
push cx
|
||||
mov cx, 11 ; eleven character name. Image name is in SI
|
||||
mov si, bx ; image name is in BX
|
||||
push di
|
||||
rep cmpsb ; test for entry match
|
||||
pop di
|
||||
je .Found
|
||||
pop cx
|
||||
add di, 32 ; queue next directory entry
|
||||
loop .LOOP
|
||||
|
||||
.NotFound:
|
||||
pop bx ; restore registers and return
|
||||
pop dx
|
||||
pop cx
|
||||
mov ax, -1 ; set error code
|
||||
ret
|
||||
|
||||
.Found:
|
||||
pop ax ; return value into AX contains entry of file
|
||||
pop bx ; restore registers and return
|
||||
pop dx
|
||||
pop cx
|
||||
ret
|
||||
|
||||
;*******************************************
|
||||
; LoadFile ()
|
||||
; - Load file
|
||||
; parm/ ES:SI => File to load
|
||||
; parm/ EBX:BP => Buffer to load file to
|
||||
; ret/ AX => -1 on error, 0 on success
|
||||
;*******************************************
|
||||
|
||||
LoadFile:
|
||||
|
||||
xor ecx, ecx ; size of file in sectors
|
||||
push ecx
|
||||
|
||||
.FIND_FILE:
|
||||
|
||||
push bx ; BX=>BP points to buffer to write to; store it for later
|
||||
push bp
|
||||
call FindFile ; find our file. ES:SI contains our filename
|
||||
cmp ax, -1
|
||||
jne .LOAD_IMAGE_PRE
|
||||
pop bp
|
||||
pop bx
|
||||
pop ecx
|
||||
mov ax, -1
|
||||
ret
|
||||
|
||||
.LOAD_IMAGE_PRE:
|
||||
|
||||
sub edi, ROOT_OFFSET
|
||||
sub eax, ROOT_OFFSET
|
||||
|
||||
; get starting cluster
|
||||
|
||||
push word ROOT_SEG ;root segment loc
|
||||
pop es
|
||||
mov dx, WORD [es:di + 0x001A] ; DI points to file entry in root directory table. Refrence the table...
|
||||
mov WORD [cluster], dx ; file's first cluster
|
||||
pop bx ; get location to write to so we dont screw up the stack
|
||||
pop es
|
||||
push bx ; store location for later again
|
||||
push es
|
||||
call LoadFAT
|
||||
|
||||
.LOAD_IMAGE:
|
||||
|
||||
; load the cluster
|
||||
|
||||
mov ax, WORD [cluster] ; cluster to read
|
||||
pop es ; bx:bp=es:bx
|
||||
pop bx
|
||||
call ClusterLBA
|
||||
xor cx, cx
|
||||
mov cl, BYTE [bpbSectorsPerCluster]
|
||||
|
||||
call ReadSectors
|
||||
|
||||
pop ecx
|
||||
inc ecx
|
||||
push ecx
|
||||
|
||||
push bx
|
||||
push es
|
||||
|
||||
mov ax, FAT_SEG ;start reading from fat
|
||||
mov es, ax
|
||||
xor bx, bx
|
||||
|
||||
; get next cluster
|
||||
|
||||
mov ax, WORD [cluster] ; identify current cluster
|
||||
mov cx, ax ; copy current cluster
|
||||
mov dx, ax ; copy current cluster
|
||||
shr dx, 0x0001 ; divide by two
|
||||
add cx, dx ; sum for (3/2)
|
||||
|
||||
mov bx, 0 ;location of fat in memory
|
||||
add bx, cx
|
||||
mov dx, WORD [es:bx]
|
||||
test ax, 0x0001 ; test for odd or even cluster
|
||||
jnz .ODD_CLUSTER
|
||||
|
||||
.EVEN_CLUSTER:
|
||||
|
||||
and dx, 0000111111111111b ; take low 12 bits
|
||||
jmp .DONE
|
||||
|
||||
.ODD_CLUSTER:
|
||||
|
||||
shr dx, 0x0004 ; take high 12 bits
|
||||
|
||||
.DONE:
|
||||
|
||||
mov WORD [cluster], dx
|
||||
cmp dx, 0x0ff0 ; test for end of file marker
|
||||
jb .LOAD_IMAGE
|
||||
|
||||
.SUCCESS:
|
||||
pop es
|
||||
pop bx
|
||||
pop ecx
|
||||
xor ax, ax
|
||||
ret
|
||||
|
||||
%endif ;__FAT12_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
|
||||
|
||||
|
||||
|
||||
|
121
SysBoot/stage2/floppy16.inc
Normal file
121
SysBoot/stage2/floppy16.inc
Normal file
@@ -0,0 +1,121 @@
|
||||
|
||||
;*******************************************************
|
||||
;
|
||||
; Floppy16.inc
|
||||
; Floppy drive interface routines
|
||||
;
|
||||
; OS Development Series
|
||||
;*******************************************************
|
||||
|
||||
%ifndef __FLOPPY16_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
%define __FLOPPY16_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
|
||||
bits 16
|
||||
|
||||
bpbOEM db "My OS "
|
||||
bpbBytesPerSector: DW 512
|
||||
bpbSectorsPerCluster: DB 1
|
||||
bpbReservedSectors: DW 1
|
||||
bpbNumberOfFATs: DB 2
|
||||
bpbRootEntries: DW 224
|
||||
bpbTotalSectors: DW 2880
|
||||
bpbMedia: DB 0xf0 ;; 0xF1
|
||||
bpbSectorsPerFAT: DW 9
|
||||
bpbSectorsPerTrack: DW 18
|
||||
bpbHeadsPerCylinder: DW 2
|
||||
bpbHiddenSectors: DD 0
|
||||
bpbTotalSectorsBig: DD 0
|
||||
bsDriveNumber: DB 0
|
||||
bsUnused: DB 0
|
||||
bsExtBootSignature: DB 0x29
|
||||
bsSerialNumber: DD 0xa0a1a2a3
|
||||
bsVolumeLabel: DB "MOS FLOPPY "
|
||||
bsFileSystem: DB "FAT12 "
|
||||
|
||||
datasector dw 0x0000
|
||||
cluster dw 0x0000
|
||||
|
||||
absoluteSector db 0x00
|
||||
absoluteHead db 0x00
|
||||
absoluteTrack db 0x00
|
||||
|
||||
;************************************************;
|
||||
; Convert CHS to LBA
|
||||
; LBA = (cluster - 2) * sectors per cluster
|
||||
;************************************************;
|
||||
|
||||
ClusterLBA:
|
||||
sub ax, 0x0002 ; zero base cluster number
|
||||
xor cx, cx
|
||||
mov cl, BYTE [bpbSectorsPerCluster] ; convert byte to word
|
||||
mul cx
|
||||
add ax, WORD [datasector] ; base data sector
|
||||
ret
|
||||
|
||||
;************************************************;
|
||||
; Convert LBA to CHS
|
||||
; AX=>LBA Address to convert
|
||||
;
|
||||
; absolute sector = (logical sector / sectors per track) + 1
|
||||
; absolute head = (logical sector / sectors per track) MOD number of heads
|
||||
; absolute track = logical sector / (sectors per track * number of heads)
|
||||
;
|
||||
;************************************************;
|
||||
|
||||
LBACHS:
|
||||
xor dx, dx ; prepare dx:ax for operation
|
||||
div WORD [bpbSectorsPerTrack] ; calculate
|
||||
inc dl ; adjust for sector 0
|
||||
mov BYTE [absoluteSector], dl
|
||||
xor dx, dx ; prepare dx:ax for operation
|
||||
div WORD [bpbHeadsPerCylinder] ; calculate
|
||||
mov BYTE [absoluteHead], dl
|
||||
mov BYTE [absoluteTrack], al
|
||||
ret
|
||||
|
||||
|
||||
;************************************************;
|
||||
; Reads a series of sectors
|
||||
; CX=>Number of sectors to read
|
||||
; AX=>Starting sector
|
||||
; ES:EBX=>Buffer to read to
|
||||
;************************************************;
|
||||
|
||||
ReadSectors:
|
||||
.MAIN:
|
||||
mov di, 0x0005 ; five retries for error
|
||||
.SECTORLOOP:
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
call LBACHS ; convert starting sector to CHS
|
||||
mov ah, 0x02 ; BIOS read sector
|
||||
mov al, 0x01 ; read one sector
|
||||
mov ch, BYTE [absoluteTrack] ; track
|
||||
mov cl, BYTE [absoluteSector] ; sector
|
||||
mov dh, BYTE [absoluteHead] ; head
|
||||
mov dl, BYTE [bsDriveNumber] ; drive
|
||||
int 0x13 ; invoke BIOS
|
||||
jnc .SUCCESS ; test for read error
|
||||
xor ax, ax ; BIOS reset disk
|
||||
int 0x13 ; invoke BIOS
|
||||
dec di ; decrement error counter
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
jnz .SECTORLOOP ; attempt to read again
|
||||
int 0x18
|
||||
.SUCCESS:
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
add bx, WORD [bpbBytesPerSector] ; queue next buffer
|
||||
inc ax ; queue next sector
|
||||
loop .MAIN ; read next sector
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%endif ;__FLOPPY16_INC_67343546FDCC56AAB872_INCLUDED__
|
68
SysBoot/stage2/gdt.inc
Normal file
68
SysBoot/stage2/gdt.inc
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
|
||||
;*************************************************
|
||||
; Gdt.inc
|
||||
; -GDT Routines
|
||||
;
|
||||
; OS Development Series
|
||||
;*************************************************
|
||||
|
||||
%ifndef __GDT_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
%define __GDT_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
|
||||
bits 16
|
||||
|
||||
;*******************************************
|
||||
; InstallGDT()
|
||||
; - Install our GDT
|
||||
;*******************************************
|
||||
|
||||
InstallGDT:
|
||||
|
||||
cli ; clear interrupts
|
||||
pusha ; save registers
|
||||
lgdt [toc] ; load GDT into GDTR
|
||||
sti ; enable interrupts
|
||||
popa ; restore registers
|
||||
ret ; All done!
|
||||
|
||||
;*******************************************
|
||||
; Global Descriptor Table (GDT)
|
||||
;*******************************************
|
||||
|
||||
gdt_data:
|
||||
dd 0 ; null descriptor
|
||||
dd 0
|
||||
|
||||
; gdt code: ; code descriptor
|
||||
dw 0FFFFh ; limit low
|
||||
dw 0 ; base low
|
||||
db 0 ; base middle
|
||||
db 10011010b ; access
|
||||
db 11001111b ; granularity
|
||||
db 0 ; base high
|
||||
|
||||
; gdt data: ; data descriptor
|
||||
dw 0FFFFh ; limit low (Same as code)10:56 AM 7/8/2007
|
||||
dw 0 ; base low
|
||||
db 0 ; base middle
|
||||
db 10010010b ; access
|
||||
db 11001111b ; granularity
|
||||
db 0 ; base high
|
||||
|
||||
end_of_gdt:
|
||||
toc:
|
||||
dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT)
|
||||
dd gdt_data ; base of GDT
|
||||
|
||||
; give the descriptor offsets names
|
||||
|
||||
%define NULL_DESC 0
|
||||
%define CODE_DESC 0x8
|
||||
%define DATA_DESC 0x10
|
||||
|
||||
%endif ;__GDT_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
|
||||
|
||||
|
||||
|
175
SysBoot/stage2/memory.inc
Normal file
175
SysBoot/stage2/memory.inc
Normal file
@@ -0,0 +1,175 @@
|
||||
|
||||
;*************************************************
|
||||
; Memory.inc
|
||||
; -Basic memory routines
|
||||
;
|
||||
; OS Development Series
|
||||
;*************************************************
|
||||
|
||||
%ifndef __MEMORY_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
%define __MEMORY_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
|
||||
bits 16
|
||||
|
||||
;--------------------------------------------
|
||||
; Memory map entry structure
|
||||
;--------------------------------------------
|
||||
|
||||
struc MemoryMapEntry
|
||||
.baseAddress resq 1
|
||||
.length resq 1
|
||||
.type resd 1
|
||||
.acpi_null resd 1
|
||||
endstruc
|
||||
|
||||
;---------------------------------------------
|
||||
; Get memory map from bios
|
||||
; /in es:di->destination buffer for entries
|
||||
; /ret bp=entry count
|
||||
;---------------------------------------------
|
||||
|
||||
BiosGetMemoryMap:
|
||||
pushad
|
||||
xor ebx, ebx
|
||||
xor bp, bp ; number of entries stored here
|
||||
mov edx, 'PAMS' ; 'SMAP'
|
||||
mov eax, 0xe820
|
||||
mov ecx, 24 ; memory map entry struct is 24 bytes
|
||||
int 0x15 ; get first entry
|
||||
jc .error
|
||||
cmp eax, 'PAMS' ; bios returns SMAP in eax
|
||||
jne .error
|
||||
test ebx, ebx ; if ebx=0 then list is one entry long; bail out
|
||||
je .error
|
||||
jmp .start
|
||||
.next_entry:
|
||||
mov edx, 'PAMS' ; some bios's trash this register
|
||||
mov ecx, 24 ; entry is 24 bytes
|
||||
mov eax, 0xe820
|
||||
int 0x15 ; get next entry
|
||||
.start:
|
||||
jcxz .skip_entry ; if actual returned bytes is 0, skip entry
|
||||
.notext:
|
||||
mov ecx, [es:di + MemoryMapEntry.length] ; get length (low dword)
|
||||
test ecx, ecx ; if length is 0 skip it
|
||||
jne short .good_entry
|
||||
mov ecx, [es:di + MemoryMapEntry.length + 4]; get length (upper dword)
|
||||
jecxz .skip_entry ; if length is 0 skip it
|
||||
.good_entry:
|
||||
inc bp ; increment entry count
|
||||
add di, 24 ; point di to next entry in buffer
|
||||
.skip_entry:
|
||||
cmp ebx, 0 ; if ebx return is 0, list is done
|
||||
jne .next_entry ; get next entry
|
||||
jmp .done
|
||||
.error:
|
||||
stc
|
||||
.done:
|
||||
popad
|
||||
ret
|
||||
|
||||
;---------------------------------------------
|
||||
; Get memory size for >64M configuations (32 bit)
|
||||
; ret\ ax=KB between 1MB and 16MB
|
||||
; ret\ bx=number of 64K blocks above 16MB
|
||||
; ret\ bx=0 and ax= -1 on error
|
||||
;---------------------------------------------
|
||||
|
||||
BiosGetMemorySize64MB_32Bit:
|
||||
push ecx
|
||||
push edx
|
||||
xor ecx, ecx
|
||||
xor edx, edx
|
||||
mov ax, 0xe881
|
||||
int 0x15
|
||||
jc .error
|
||||
cmp ah, 0x86 ;unsupported function
|
||||
je .error
|
||||
cmp ah, 0x80 ;invalid command
|
||||
je .error
|
||||
jcxz .use_ax ;bios may have stored it in ax,bx or cx,dx. test if cx is 0
|
||||
mov ax, cx ;its not, so it should contain mem size; store it
|
||||
mov bx, dx
|
||||
|
||||
.use_ax:
|
||||
pop edx ;mem size is in ax and bx already, return it
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
.error:
|
||||
mov ax, -1
|
||||
mov bx, 0
|
||||
pop edx
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
;---------------------------------------------
|
||||
; Get memory size for >64M configuations
|
||||
; ret\ ax=KB between 1MB and 16MB
|
||||
; ret\ bx=number of 64K blocks above 16MB
|
||||
; ret\ bx=0 and ax= -1 on error
|
||||
;---------------------------------------------
|
||||
|
||||
BiosGetMemorySize64MB:
|
||||
push ecx
|
||||
push edx
|
||||
xor ecx, ecx
|
||||
xor edx, edx
|
||||
mov ax, 0xe801
|
||||
int 0x15
|
||||
jc .error
|
||||
cmp ah, 0x86 ;unsupported function
|
||||
je .error
|
||||
cmp ah, 0x80 ;invalid command
|
||||
je .error
|
||||
jcxz .use_ax ;bios may have stored it in ax,bx or cx,dx. test if cx is 0
|
||||
mov ax, cx ;its not, so it should contain mem size; store it
|
||||
mov bx, dx
|
||||
|
||||
.use_ax:
|
||||
pop edx ;mem size is in ax and bx already, return it
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
.error:
|
||||
mov si, msgNotSupported
|
||||
call Puts16
|
||||
mov ax, -1
|
||||
mov bx, 0
|
||||
pop edx
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
;---------------------------------------------
|
||||
; Get amount of contiguous KB from addr 0
|
||||
; ret\ ax=KB size from address 0
|
||||
;---------------------------------------------
|
||||
|
||||
BiosGetMemorySize:
|
||||
int 0x12
|
||||
ret
|
||||
|
||||
;---------------------------------------------
|
||||
; Get contiguous exetended memory size
|
||||
; ret\ ax=KB size above 1MB; ax= -1 on error
|
||||
;---------------------------------------------
|
||||
|
||||
BiosGetExtendedMemorySize:
|
||||
mov ax, 0x88
|
||||
int 0x15
|
||||
jc .error
|
||||
test ax, ax ; if size=0
|
||||
je .error
|
||||
cmp ah, 0x86 ;unsupported function
|
||||
je .error
|
||||
cmp ah, 0x80 ;invalid command
|
||||
je .error
|
||||
ret
|
||||
.error:
|
||||
mov ax, -1
|
||||
ret
|
||||
|
||||
|
||||
msgNotSupported db 0x0A, 0x0D, "BiosGetMemorySize64MB: function not supported.",0x0A, 0x0D, 0x00
|
||||
|
||||
%endif
|
172
SysBoot/stage2/stage2.asm
Normal file
172
SysBoot/stage2/stage2.asm
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
;*******************************************************
|
||||
;
|
||||
; Stage2.asm
|
||||
; Stage2 Bootloader
|
||||
;
|
||||
; OS Development Series
|
||||
;*******************************************************
|
||||
|
||||
bits 16
|
||||
|
||||
org 0x500
|
||||
|
||||
jmp main ; go to start
|
||||
|
||||
;*******************************************************
|
||||
; Preprocessor directives
|
||||
;*******************************************************
|
||||
|
||||
%include "stdio.inc" ; basic i/o routines
|
||||
%include "gdt.inc" ; Gdt routines
|
||||
%include "a20.inc" ; A20 enabling
|
||||
%include "fat12.inc" ; FAT12 driver. Kinda :)
|
||||
%include "common.inc"
|
||||
;%include "bootinfo.inc"
|
||||
%include "memory.inc"
|
||||
|
||||
;*******************************************************
|
||||
; Data Section
|
||||
;*******************************************************
|
||||
|
||||
msgFailure db 0x0D, 0x0A, "FATAL ERROR: Kernel file KERNEL.CTA missing or corrupt. Press Any Key to Reboot.", 0x0D, 0x0A, 0x0A, 0x00
|
||||
|
||||
boot_info:
|
||||
multiboot_info_flags dd 0
|
||||
multiboot_info_memoryLo dd 0
|
||||
multiboot_info_memoryHi dd 0
|
||||
multiboot_info_bootDevice dd 0
|
||||
multiboot_info_cmdLine dd 0
|
||||
multiboot_info_mods_count dd 0
|
||||
multiboot_info_mods_addr dd 0
|
||||
multiboot_info_syms0 dd 0
|
||||
multiboot_info_syms1 dd 0
|
||||
multiboot_info_syms2 dd 0
|
||||
multiboot_info_mmap_length dd 0
|
||||
multiboot_info_mmap_addr dd 0
|
||||
multiboot_info_drives_length dd 0
|
||||
multiboot_info_drives_addr dd 0
|
||||
multiboot_info_config_table dd 0
|
||||
multiboot_info_bootloader_name dd 0
|
||||
multiboot_info_apm_table dd 0
|
||||
multiboot_info_vbe_control_info dd 0
|
||||
multiboot_info_vbe_mode_info dw 0
|
||||
multiboot_info_vbe_interface_seg dw 0
|
||||
multiboot_info_vbe_interface_off dw 0
|
||||
multiboot_info_vbe_interface_len dw 0
|
||||
|
||||
main:
|
||||
|
||||
;-------------------------------;
|
||||
; Setup segments and stack ;
|
||||
;-------------------------------;
|
||||
|
||||
cli ; clear interrupts
|
||||
xor ax, ax ; null segments
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ax, 0x0000 ; stack begins at 0x9000-0xffff
|
||||
mov ss, ax
|
||||
mov sp, 0xFFFF
|
||||
sti ; enable interrupts
|
||||
|
||||
mov [multiboot_info_bootDevice], dl
|
||||
|
||||
call _EnableA20
|
||||
call InstallGDT
|
||||
sti
|
||||
|
||||
xor eax, eax
|
||||
xor ebx, ebx
|
||||
call BiosGetMemorySize64MB
|
||||
|
||||
mov word [multiboot_info_memoryHi], bx
|
||||
mov word [multiboot_info_memoryLo], ax
|
||||
|
||||
mov eax, 0x0
|
||||
mov ds, ax
|
||||
mov di, 0x1000
|
||||
call BiosGetMemoryMap
|
||||
mov dword [multiboot_info_mmap_addr], 0x1000
|
||||
xor eax, eax
|
||||
mov ax, bp
|
||||
mov dword [multiboot_info_mmap_length], eax
|
||||
|
||||
|
||||
call LoadRoot
|
||||
mov ebx, 0
|
||||
mov ebp, IMAGE_RMODE_BASE
|
||||
mov esi, ImageName
|
||||
call LoadFile ; load our file
|
||||
mov dword [ImageSize], ecx
|
||||
cmp ax, 0
|
||||
je EnterStage3
|
||||
mov si, msgFailure
|
||||
call Puts16
|
||||
mov ah, 0
|
||||
int 0x16 ; await keypress
|
||||
int 0x19 ; warm boot computer
|
||||
|
||||
;-------------------------------;
|
||||
; Go into pmode ;
|
||||
;-------------------------------;
|
||||
|
||||
EnterStage3:
|
||||
|
||||
cli ; clear interrupts
|
||||
mov eax, cr0 ; set bit 0 in cr0--enter pmode
|
||||
or eax, 1
|
||||
mov cr0, eax
|
||||
|
||||
jmp CODE_DESC:Stage3 ; far jump to fix CS. Remember that the code selector is 0x8!
|
||||
|
||||
; Note: Do NOT re-enable interrupts! Doing so will triple fault!
|
||||
; We will fix this in Stage 3.
|
||||
|
||||
;******************************************************
|
||||
; ENTRY POINT FOR STAGE 3
|
||||
;******************************************************
|
||||
|
||||
bits 32
|
||||
|
||||
BadImage db "FATAL ERROR: Kernel file KERNEL.CTA missing or corrupt. Press Any Key to Reboot.", 0
|
||||
|
||||
Stage3:
|
||||
|
||||
;-------------------------------;
|
||||
; Set registers ;
|
||||
;-------------------------------;
|
||||
|
||||
mov ax, DATA_DESC ; set data segments to data selector (0x10)
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
mov esp, 90000h ; stack begins from 90000h
|
||||
|
||||
|
||||
CopyImage:
|
||||
mov eax, dword [ImageSize]
|
||||
movzx ebx, word [bpbBytesPerSector]
|
||||
mul ebx
|
||||
mov ebx, 4
|
||||
div ebx
|
||||
cld
|
||||
mov esi, IMAGE_RMODE_BASE
|
||||
mov edi, IMAGE_PMODE_BASE
|
||||
mov ecx, eax
|
||||
rep movsd ; copy image to its protected mode address
|
||||
|
||||
mov eax, 0x2badb002 ; multiboot specs say eax should be this
|
||||
mov ebx, 0
|
||||
|
||||
;edx=8
|
||||
|
||||
push dword boot_info
|
||||
push dword [ImageSize]
|
||||
|
||||
jmp CODE_DESC:IMAGE_PMODE_BASE ; Execute Kernel
|
||||
add esp, 4
|
||||
|
||||
cli
|
||||
hlt
|
||||
|
295
SysBoot/stage2/stdio.inc
Normal file
295
SysBoot/stage2/stdio.inc
Normal file
@@ -0,0 +1,295 @@
|
||||
|
||||
;*************************************************
|
||||
; stdio.inc
|
||||
; -Input/Output routines
|
||||
;
|
||||
; OS Development Series
|
||||
;*************************************************
|
||||
|
||||
%ifndef __STDIO_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
%define __STDIO_INC_67343546FDCC56AAB872_INCLUDED__
|
||||
|
||||
|
||||
;==========================================================
|
||||
;
|
||||
; 16 Bit Real Mode Routines
|
||||
;==========================================================
|
||||
|
||||
|
||||
;************************************************;
|
||||
; Puts16 ()
|
||||
; -Prints a null terminated string
|
||||
; DS=>SI: 0 terminated string
|
||||
;************************************************;
|
||||
tmpStr db " ", 0x0D, 0x0A, 0x00
|
||||
|
||||
bits 16
|
||||
|
||||
Puts16:
|
||||
pusha ; save registers
|
||||
.Loop1:
|
||||
lodsb ; load next byte from string from SI to AL
|
||||
or al, al ; Does AL=0?
|
||||
jz Puts16Done ; Yep, null terminator found-bail out
|
||||
mov ah, 0eh ; Nope-Print the character
|
||||
int 10h ; invoke BIOS
|
||||
jmp .Loop1 ; Repeat until null terminator found
|
||||
Puts16Done:
|
||||
popa ; restore registers
|
||||
ret ; we are done, so return
|
||||
|
||||
|
||||
PutINT:
|
||||
pusha ; save registers
|
||||
|
||||
mov cx, 0
|
||||
.init:
|
||||
mov bx, cx
|
||||
add bx, tmpStr
|
||||
mov [bx], byte ' '
|
||||
inc cx
|
||||
|
||||
cmp cx, 31
|
||||
jne .init
|
||||
|
||||
|
||||
mov cx, 31 ; initialize counter
|
||||
|
||||
.loop:
|
||||
mov dx, 0
|
||||
mov bx, 0x0A
|
||||
div bx ; ax = ax/10, dx = ax%10
|
||||
mov bx, cx
|
||||
add bx, tmpStr
|
||||
add dl, '0'
|
||||
mov [bx], dl
|
||||
|
||||
sub cx, 1
|
||||
|
||||
cmp ax, 0 ; when done, ax = 0;
|
||||
je .done
|
||||
|
||||
jmp .loop
|
||||
|
||||
.done:
|
||||
mov si, tmpStr
|
||||
call Puts16
|
||||
popa
|
||||
ret
|
||||
|
||||
;==========================================================
|
||||
;
|
||||
; 32 Bit Protected Mode Routines
|
||||
;==========================================================
|
||||
|
||||
bits 32
|
||||
|
||||
%define VIDMEM 0xB8000 ; video memory
|
||||
%define COLS 80 ; width and height of screen
|
||||
%define LINES 25
|
||||
%define CHAR_ATTRIB 14 ; character attribute (White text on black background)
|
||||
|
||||
_CurX db 0 ; current x/y location
|
||||
_CurY db 0
|
||||
|
||||
;**************************************************;
|
||||
; Putch32 ()
|
||||
; - Prints a character to screen
|
||||
; BL => Character to print
|
||||
;**************************************************;
|
||||
|
||||
Putch32:
|
||||
|
||||
pusha
|
||||
mov edi, VIDMEM
|
||||
|
||||
xor eax, eax ; clear eax
|
||||
|
||||
; y * screen width
|
||||
|
||||
mov ecx, COLS*2 ; Mode 7 has 2 bytes per char, so its COLS*2 bytes per line
|
||||
mov al, byte [_CurY] ; get y pos
|
||||
mul ecx ; multiply y*COLS
|
||||
push eax ; save eax--the multiplication
|
||||
|
||||
; now add _CurX * 2
|
||||
|
||||
mov al, byte [_CurX] ; multiply _CurX by 2 because it is 2 bytes per char
|
||||
mov cl, 2
|
||||
mul cl
|
||||
pop ecx ; pop y*COLS result
|
||||
add eax, ecx
|
||||
|
||||
; add the position to draw to the base of vid memory
|
||||
|
||||
xor ecx, ecx
|
||||
add edi, eax ; add it to the base address
|
||||
|
||||
; watch for new line
|
||||
|
||||
cmp bl, 0x0A ; is it a newline character?
|
||||
je .Row ; yep--go to next row
|
||||
|
||||
; print the character
|
||||
|
||||
mov dl, bl ; Get character
|
||||
mov dh, CHAR_ATTRIB ; the character attribute
|
||||
mov word [edi], dx ; write to video display
|
||||
|
||||
; go to next location
|
||||
|
||||
inc byte [_CurX] ; go to next character
|
||||
jmp .done ; nope, bail out
|
||||
|
||||
.Row:
|
||||
mov byte [_CurX], 0 ; go back to col 0
|
||||
inc byte [_CurY] ; go to next row
|
||||
|
||||
.done:
|
||||
popa
|
||||
ret
|
||||
|
||||
;**************************************************;
|
||||
; Puts32 ()
|
||||
; - Prints a null terminated string
|
||||
; parm\ EBX = address of string to print
|
||||
;**************************************************;
|
||||
|
||||
Puts32:
|
||||
|
||||
pusha
|
||||
push ebx ; copy the string address
|
||||
pop edi
|
||||
|
||||
.loop:
|
||||
|
||||
;-------------------------------;
|
||||
; Get character ;
|
||||
;-------------------------------;
|
||||
|
||||
mov bl, byte [edi] ; get next character
|
||||
cmp bl, 0 ; is it 0 (Null terminator)?
|
||||
je .done ; yep-bail out
|
||||
|
||||
;-------------------------------;
|
||||
; Print the character ;
|
||||
;-------------------------------;
|
||||
|
||||
call Putch32 ; Nope-print it out
|
||||
|
||||
;-------------------------------;
|
||||
; Go to next character ;
|
||||
;-------------------------------;
|
||||
|
||||
inc edi ; go to next character
|
||||
jmp .loop
|
||||
|
||||
.done:
|
||||
|
||||
;-------------------------------;
|
||||
; Update hardware cursor ;
|
||||
;-------------------------------;
|
||||
|
||||
mov bh, byte [_CurY] ; get current position
|
||||
mov bl, byte [_CurX]
|
||||
call MovCur ; update cursor
|
||||
|
||||
popa ; restore registers, and return
|
||||
ret
|
||||
|
||||
;**************************************************;
|
||||
; MoveCur ()
|
||||
; - Update hardware cursor
|
||||
; parm/ bh = Y pos
|
||||
; parm/ bl = x pos
|
||||
;**************************************************;
|
||||
|
||||
|
||||
|
||||
bits 32
|
||||
|
||||
MovCur:
|
||||
|
||||
pusha
|
||||
|
||||
;-------------------------------;
|
||||
; Get current position ;
|
||||
;-------------------------------;
|
||||
|
||||
; location = _CurX + _CurY * COLS
|
||||
|
||||
xor eax, eax
|
||||
mov ecx, COLS
|
||||
mov al, bh ; get y pos
|
||||
mul ecx ; multiply y*COLS
|
||||
add al, bl ; Now add x
|
||||
mov ebx, eax
|
||||
|
||||
;--------------------------------------;
|
||||
; Set low byte index to VGA register ;
|
||||
;--------------------------------------;
|
||||
|
||||
mov al, 0x0f
|
||||
mov dx, 0x03D4
|
||||
out dx, al
|
||||
|
||||
mov al, bl
|
||||
mov dx, 0x03D5
|
||||
out dx, al ; low byte
|
||||
|
||||
;---------------------------------------;
|
||||
; Set high byte index to VGA register ;
|
||||
;---------------------------------------;
|
||||
|
||||
xor eax, eax
|
||||
|
||||
mov al, 0x0e
|
||||
mov dx, 0x03D4
|
||||
out dx, al
|
||||
|
||||
mov al, bh
|
||||
mov dx, 0x03D5
|
||||
out dx, al ; high byte
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
;**************************************************;
|
||||
; ClrScr32 ()
|
||||
; - Clears screen
|
||||
;**************************************************;
|
||||
|
||||
bits 32
|
||||
|
||||
ClrScr32:
|
||||
|
||||
pusha
|
||||
cld
|
||||
mov edi, VIDMEM
|
||||
mov cx, 2000
|
||||
mov ah, CHAR_ATTRIB
|
||||
mov al, ' '
|
||||
rep stosw
|
||||
mov byte [_CurX], 0
|
||||
mov byte [_CurY], 0
|
||||
popa
|
||||
ret
|
||||
|
||||
;**************************************************;
|
||||
; GotoXY ()
|
||||
; - Set current X/Y location
|
||||
; parm\ AL=X position
|
||||
; parm\ AH=Y position
|
||||
;**************************************************;
|
||||
|
||||
bits 32
|
||||
|
||||
GotoXY:
|
||||
pusha
|
||||
mov [_CurX], al
|
||||
mov [_CurY], ah
|
||||
popa
|
||||
ret
|
||||
|
||||
|
||||
%endif ;__STDIO_INC_67343546FDCC56AAB872_INCLUDED__
|
Reference in New Issue
Block a user