Compare commits
10 Commits
cec3b93c83
...
26fc668d74
Author | SHA1 | Date | |
---|---|---|---|
26fc668d74 | |||
56152c6d20 | |||
|
5fa8e0efa3 | ||
|
e688617286 | ||
|
d0a5eb4c6f | ||
|
5fe565b6f7 | ||
|
1b2184fe52 | ||
|
e9c4e993f4 | ||
|
36e66600f5 | ||
|
0953fe31ec |
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@
|
|||||||
*.lock
|
*.lock
|
||||||
*.com
|
*.com
|
||||||
bx_enh_dbg.ini
|
bx_enh_dbg.ini
|
||||||
|
.cache
|
||||||
|
compile_commands.json
|
||||||
|
60
Makefile
60
Makefile
@ -1,21 +1,57 @@
|
|||||||
objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o dosfs/dosfs.o gdt.o usermode.o paging.o fault.o tests.o kbd.o helper.o progs.o disk.o hexedit.o
|
objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o gdt.o\
|
||||||
CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding -march=i686 -fno-stack-protector -Wno-int-conversion -nostdlib -c
|
paging.o fault.o tests.o kbd.o helper.o disk.o file.o fs.o dosfs/dosfs.o fs_dos.o\
|
||||||
|
progs.o hexedit.o textedit.o
|
||||||
|
CFLAGS = -target "i386-elf" -m32 -mgeneral-regs-only -ffreestanding\
|
||||||
|
-march=i386 -fno-stack-protector -Wno-int-conversion -nostdlib -c -Iinclude
|
||||||
|
LFLAGS = -Wl,--gc-sections -Wl,--print-gc-sections -m32 -nostartfiles -nostdlib
|
||||||
|
|
||||||
|
ifeq ($(OUTFILE),)
|
||||||
|
OUTFILE = virtdisk.bin
|
||||||
|
endif
|
||||||
|
ifeq ($(PARTSTART),)
|
||||||
|
PARTSTART = 2048
|
||||||
|
endif
|
||||||
|
|
||||||
|
PARTVBR=$(shell echo "$(PARTSTART) * (2^9)" | bc)
|
||||||
|
PARTVBRBOOT=$(shell echo "$(PARTVBR) + 90" | bc)
|
||||||
|
KERNSEC=$(shell echo "$(PARTSTART) + 4" | bc)
|
||||||
|
|
||||||
|
.PHONY: $(OUTFILE)
|
||||||
|
|
||||||
|
all: $(OUTFILE)
|
||||||
|
|
||||||
|
$(OUTFILE): boot.bin boot_partition.bin kernel.bin
|
||||||
|
# Copy system bootloader to boot sector, don't overwrite MBR
|
||||||
|
dd bs=400 count=1 conv=notrunc if=boot.bin of=$@
|
||||||
|
# Ensure partition VBR contains EB 5A
|
||||||
|
echo -n -e '\xeb\x5a' | dd bs=1 seek=$(PARTVBR) count=2 conv=notrunc of=$@
|
||||||
|
# Copy kernel bootloader to partition VBR
|
||||||
|
dd bs=1 count=420 seek=$(PARTVBRBOOT) conv=notrunc if=boot_partition.bin of=$@
|
||||||
|
# TODO Check that disk has enough reserved sectors,
|
||||||
|
# currently this will overwrite the disk if too few
|
||||||
|
# Write kernel beyond boot sector, maximum 64K (128 sectors)
|
||||||
|
dd bs=512 count=128 seek=$(KERNSEC) conv=notrunc if=kernel.bin of=$@
|
||||||
|
|
||||||
|
kernel.bin: out.o link.ld usermode.o
|
||||||
|
clang $(LFLAGS) -Wl,-M -Tlink.ld -ffreestanding -o $@ out.o usermode.o
|
||||||
|
|
||||||
|
usermode.o: usermode.bin
|
||||||
|
objcopy -I binary -O elf32-i386 -B i386 $< $@
|
||||||
|
|
||||||
|
%.bin: %.nasm
|
||||||
|
nasm -o $@ $<
|
||||||
|
|
||||||
|
out.o: $(objects)
|
||||||
|
clang $(LFLAGS) -e entry -r -o $@ $^
|
||||||
|
|
||||||
%.o: %.nasm
|
%.o: %.nasm
|
||||||
nasm -f elf32 -o $@ $<
|
nasm -f elf32 -o $@ $<
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
clang $(CFLAGS) -O2 -o $@ $<
|
clang $(CFLAGS) -ffunction-sections -fdata-sections -Os -o $@ $<
|
||||||
|
|
||||||
all: $(objects)
|
|
||||||
nasm boot.nasm -o boot.bin
|
|
||||||
gcc -Tlink.ld -Wl,-M -m32 -ffreestanding -nostartfiles -nostdlib -o kernel.bin\
|
|
||||||
$(objects)
|
|
||||||
dd bs=400 count=1 conv=notrunc if=boot.bin of=virtdisk.bin
|
|
||||||
dd bs=512 seek=1 conv=notrunc if=kernel.bin of=virtdisk.bin
|
|
||||||
virtdisk:
|
virtdisk:
|
||||||
dd bs=1M count=32 if=/dev/zero of=virtdisk.bin
|
cp virtdisk.bin.ex virtdisk.bin
|
||||||
echo -n -e '\x55\xaa' | dd bs=1 seek=510 conv=notrunc of=virtdisk.bin
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm $(objects)
|
rm -f $(objects) out.o kernel.bin boot.bin usermode.bin
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
# luciaos
|
# ROSE
|
||||||
|
in progress toy OS
|
||||||
|
i work on stream at <https://twitch.tv/mcrrox>
|
||||||
|
219
boot.nasm
219
boot.nasm
@ -1,6 +1,8 @@
|
|||||||
secreadcnt equ 0x38
|
; This boots the active partition.
|
||||||
kernelreads equ 0x10000/(512*secreadcnt) ; 64K / Sector Size FIXME This underestimates when kernel size is not divisible by bytes per read
|
; Relocates self to 0x7E00, loads the
|
||||||
[ORG 0x7c00]
|
; first sector of active partition
|
||||||
|
; to 0x7C00 and jumps
|
||||||
|
[ORG 0x7C00]
|
||||||
[BITS 16]
|
[BITS 16]
|
||||||
xor ax, ax
|
xor ax, ax
|
||||||
mov ds, ax
|
mov ds, ax
|
||||||
@ -8,68 +10,50 @@ mov es, ax
|
|||||||
mov ax, 0x8000
|
mov ax, 0x8000
|
||||||
mov ss, ax
|
mov ss, ax
|
||||||
mov sp, 0xFF00
|
mov sp, 0xFF00
|
||||||
|
; Relocate self
|
||||||
|
mov di, 0x7E00
|
||||||
|
mov si, 0x7C00
|
||||||
|
mov cx, 512
|
||||||
|
rep movsw
|
||||||
|
jmp 0:relocated
|
||||||
|
; TODO Make this calculated, somehow
|
||||||
|
[SECTION RELOC vstart=0x7E20]
|
||||||
|
relocated:
|
||||||
mov ah, 0x41 ; int 13 extensions check
|
mov ah, 0x41 ; int 13 extensions check
|
||||||
mov bx, 0x55AA
|
mov bx, 0x55AA
|
||||||
int 0x13
|
int 0x13
|
||||||
jc no_exten
|
jc no_int13
|
||||||
mov cx, kernelreads
|
; Find active partition
|
||||||
read_loop:
|
xor cx, cx
|
||||||
|
mov si, 0x7E00+0x1BE
|
||||||
|
.find_active:
|
||||||
|
lodsb
|
||||||
|
bt ax, 7
|
||||||
|
jc read
|
||||||
|
add si, 15
|
||||||
|
inc cl
|
||||||
|
cmp cl, 4
|
||||||
|
jl .find_active
|
||||||
|
jmp err
|
||||||
|
read:
|
||||||
|
; Put partition start LBA in disk address packet
|
||||||
|
add si, 7
|
||||||
|
mov di, addr_packet_start_block
|
||||||
|
movsw
|
||||||
|
movsw
|
||||||
|
; Load the first sector of the partition
|
||||||
xor ax, ax
|
xor ax, ax
|
||||||
mov ah, 0x42
|
mov ah, 0x42
|
||||||
mov si, addr_packet
|
mov si, addr_packet
|
||||||
int 0x13
|
int 0x13
|
||||||
jc err
|
jc err
|
||||||
add word [addr_packet_transfer_buff_seg], (secreadcnt*512)/16
|
; Jump to partition boot
|
||||||
add word [addr_packet_start_block], secreadcnt
|
jmp 0:0x7C00
|
||||||
loop read_loop
|
|
||||||
entry:
|
no_int13:
|
||||||
;mov ax,0x2403 ; A20 BIOS Support
|
mov si, no_exten_str
|
||||||
;int 0x15
|
mov cx, no_exten_str_end - no_exten_str
|
||||||
;jb .no_a20
|
jmp print
|
||||||
;cmp ah,0
|
|
||||||
;jnz .no_a20
|
|
||||||
;mov ax,0x2401 ; A20 BIOS Activate
|
|
||||||
;int 0x15
|
|
||||||
;.no_a20:
|
|
||||||
cli ; no interrupts
|
|
||||||
xor ax,ax
|
|
||||||
mov ds, ax
|
|
||||||
lgdt [gdt_desc] ; load gdt register
|
|
||||||
mov eax, cr0 ; set pmode bit
|
|
||||||
or al, 1
|
|
||||||
mov cr0, eax
|
|
||||||
jmp 08h:Pmode
|
|
||||||
no_exten:
|
|
||||||
; read with CHS
|
|
||||||
; FIXME This only reads up to sector count
|
|
||||||
mov ah,8
|
|
||||||
int 0x13 ; geometry
|
|
||||||
and cx, 0x3f
|
|
||||||
push cx
|
|
||||||
push 0x0080 ; DH=head,DL=disk
|
|
||||||
push 0x2000 ; buffer seg
|
|
||||||
push 2 ; sector
|
|
||||||
.loop:
|
|
||||||
mov ax, [esp]
|
|
||||||
push 0xb800
|
|
||||||
pop es
|
|
||||||
xor di,di
|
|
||||||
call hexprint
|
|
||||||
mov ax, [esp+2]
|
|
||||||
mov es, ax
|
|
||||||
mov ax, 0x0201
|
|
||||||
mov cx, [esp]
|
|
||||||
xor bx,bx
|
|
||||||
mov dx, [esp+4]
|
|
||||||
int 0x13
|
|
||||||
jc err
|
|
||||||
add word [esp+2], 0x20
|
|
||||||
mov cx, [esp]
|
|
||||||
inc cl
|
|
||||||
mov [esp], cx
|
|
||||||
cmp cl, [esp+6]
|
|
||||||
jg entry
|
|
||||||
jmp .loop
|
|
||||||
err:
|
err:
|
||||||
mov bx, ax
|
mov bx, ax
|
||||||
mov si, string
|
mov si, string
|
||||||
@ -83,126 +67,17 @@ err_print:
|
|||||||
lodsb
|
lodsb
|
||||||
stosw
|
stosw
|
||||||
loop err_print
|
loop err_print
|
||||||
;add di, 2
|
|
||||||
;mov ax, bx
|
|
||||||
;call hexprint
|
|
||||||
hlt_loop:
|
hlt_loop:
|
||||||
hlt
|
hlt
|
||||||
jmp hlt_loop
|
jmp hlt_loop
|
||||||
hexprint:
|
|
||||||
xor cx, cx
|
|
||||||
mov bl, al
|
|
||||||
shr al, 4
|
|
||||||
jmp .donibble
|
|
||||||
.nibble2:
|
|
||||||
mov al, bl
|
|
||||||
inc cx
|
|
||||||
.donibble:
|
|
||||||
and al, 0x0F
|
|
||||||
cmp al, 0x0A
|
|
||||||
jl .noadjust
|
|
||||||
add al, 'A' - '0' - 10
|
|
||||||
.noadjust:
|
|
||||||
add al, '0'
|
|
||||||
mov ah, 0x7
|
|
||||||
stosw
|
|
||||||
test cx, cx
|
|
||||||
jz .nibble2
|
|
||||||
ret
|
|
||||||
|
|
||||||
[BITS 32]
|
|
||||||
Pmode:
|
|
||||||
mov eax, 0x10
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
mov ss, ax
|
|
||||||
; check A20
|
|
||||||
.a20:
|
|
||||||
mov edi, 0x107C00
|
|
||||||
mov esi, 0x007C00
|
|
||||||
mov [esi], esi
|
|
||||||
mov [edi], edi
|
|
||||||
cmpsd
|
|
||||||
jne .kernel
|
|
||||||
call enable_A20
|
|
||||||
;in al, 0x92 ; fast A20
|
|
||||||
;test al, 2
|
|
||||||
;jnz .fa20_end
|
|
||||||
;or al, 2
|
|
||||||
;and al, 0xFE
|
|
||||||
;out 0x92, al
|
|
||||||
;.fa20_end:
|
|
||||||
jmp .a20
|
|
||||||
.kernel:
|
|
||||||
;mov dword [0xb8000], 0x07000700 | 'P' | 'M' << 16
|
|
||||||
;mov dword [0xb8004], 0x07000700 | 'O' | 'D' << 16
|
|
||||||
;mov dword [0xb8008], 0x07000700 | 'E' | ' ' << 16
|
|
||||||
mov esi, 0x20000
|
|
||||||
mov edi, 0x100000
|
|
||||||
mov ecx, 0x10000
|
|
||||||
rep movsb
|
|
||||||
jmp 08h:0x100000
|
|
||||||
enable_A20:
|
|
||||||
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
|
|
||||||
ret
|
|
||||||
a20wait:
|
|
||||||
in al,0x64
|
|
||||||
test al,2
|
|
||||||
jnz a20wait
|
|
||||||
ret
|
|
||||||
a20wait2:
|
|
||||||
in al,0x64
|
|
||||||
test al,1
|
|
||||||
jz a20wait2
|
|
||||||
ret
|
|
||||||
|
|
||||||
gdt_desc:
|
|
||||||
dw gdt_end - gdt
|
|
||||||
dd gdt
|
|
||||||
gdt:
|
|
||||||
gdt_null: dq 0
|
|
||||||
gdt_code: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address
|
|
||||||
db 0 ; bits 16-23 base address
|
|
||||||
db 10011010b ; access byte
|
|
||||||
db 11001111b ; bits 16-19 limit (4GB), 4 bits flags
|
|
||||||
db 0 ; bits 24-31 base address
|
|
||||||
gdt_data: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address
|
|
||||||
db 0 ; bits 16-23 base address
|
|
||||||
db 10010010b ; access byte
|
|
||||||
db 11001111b ; bits 16-19 limit (4GB), 4 bits flags
|
|
||||||
db 0 ; bits 24-31 base address
|
|
||||||
gdt_end:
|
|
||||||
|
|
||||||
string: db 'DISK ERROR'
|
string: db 'DISK ERROR'
|
||||||
string_end:
|
string_end:
|
||||||
;no_exten_str: db 'NO INT13 EXTEN'
|
no_exten_str: db 'NO INT13 EXTEN'
|
||||||
;no_exten_str_end:
|
no_exten_str_end:
|
||||||
|
|
||||||
addr_packet:
|
addr_packet:
|
||||||
db 0x10, 0x00 ; size, reserved
|
db 0x10, 0x00 ; size, reserved
|
||||||
dw secreadcnt ; blocks
|
dw 1 ; blocks
|
||||||
addr_packet_transfer_buff_off: dw 0x0000 ; transfer buffer offset
|
addr_packet_transfer_buff_off: dw 0x7C00 ; transfer buffer offset
|
||||||
addr_packet_transfer_buff_seg: dw 0x2000 ; transfer buffer segment
|
addr_packet_transfer_buff_seg: dw 0x0000 ; transfer buffer segment
|
||||||
addr_packet_start_block: dq 1 ; start block
|
addr_packet_start_block: dq 0 ; start block
|
||||||
|
136
boot_partition.nasm
Normal file
136
boot_partition.nasm
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
; This boots *from a FAT partition*
|
||||||
|
; So it starts at 0x7C00+90, the offset of
|
||||||
|
; the boot code in a FAT VBR
|
||||||
|
secreadcnt equ 0x38
|
||||||
|
kernelreads equ 0x10000/(512*secreadcnt) ; 64K / Sector Size FIXME This underestimates when kernel size is not divisible by bytes per read
|
||||||
|
[ORG 0x7c00+90]
|
||||||
|
[BITS 16]
|
||||||
|
xor ax, ax
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov ax, 0x8000
|
||||||
|
mov ss, ax
|
||||||
|
mov sp, 0xFF00
|
||||||
|
; FIXME Assumes INT 13 Extension support
|
||||||
|
mov ah, 0x42
|
||||||
|
mov si, addr_packet
|
||||||
|
int 0x13
|
||||||
|
jc err
|
||||||
|
xor cx, cx
|
||||||
|
mov si, 0x7E00+0x1BE
|
||||||
|
.find_active:
|
||||||
|
lodsb
|
||||||
|
bt ax, 7
|
||||||
|
jc read
|
||||||
|
add si, 15
|
||||||
|
inc cl
|
||||||
|
cmp cl, 4
|
||||||
|
jl .find_active
|
||||||
|
jmp err
|
||||||
|
read:
|
||||||
|
mov dh, cl ; Store active partition
|
||||||
|
add si, 7
|
||||||
|
mov di, addr_packet_start_block
|
||||||
|
lodsw
|
||||||
|
; Offset of kernel in partition
|
||||||
|
add ax, 4
|
||||||
|
stosw
|
||||||
|
lodsw
|
||||||
|
adc ax, 0
|
||||||
|
stosw
|
||||||
|
mov cx, kernelreads
|
||||||
|
read_loop:
|
||||||
|
xor ax, ax
|
||||||
|
mov ah, 0x42
|
||||||
|
mov si, addr_packet
|
||||||
|
int 0x13
|
||||||
|
jc err
|
||||||
|
add word [addr_packet_transfer_buff_seg], (secreadcnt*512)/16
|
||||||
|
add word [addr_packet_start_block], secreadcnt
|
||||||
|
loop read_loop
|
||||||
|
entry:
|
||||||
|
cli ; no interrupts
|
||||||
|
xor ax,ax
|
||||||
|
mov ds, ax
|
||||||
|
lgdt [gdt_desc] ; load gdt register
|
||||||
|
mov eax, cr0 ; set pmode bit
|
||||||
|
or al, 1
|
||||||
|
mov cr0, eax
|
||||||
|
jmp 08h:Pmode
|
||||||
|
err:
|
||||||
|
mov si, string
|
||||||
|
mov cx, string_end - string
|
||||||
|
print:
|
||||||
|
push 0xb800
|
||||||
|
pop es
|
||||||
|
xor di, di
|
||||||
|
mov ah, 0x7
|
||||||
|
err_print:
|
||||||
|
lodsb
|
||||||
|
stosw
|
||||||
|
loop err_print
|
||||||
|
hlt_loop:
|
||||||
|
hlt
|
||||||
|
jmp hlt_loop
|
||||||
|
|
||||||
|
[BITS 32]
|
||||||
|
Pmode:
|
||||||
|
mov eax, 0x10
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
mov ss, ax
|
||||||
|
; check A20
|
||||||
|
.a20:
|
||||||
|
mov edi, 0x107C00
|
||||||
|
mov esi, 0x007C00
|
||||||
|
mov [esi], esi
|
||||||
|
mov [edi], edi
|
||||||
|
cmpsd
|
||||||
|
jne .kernel
|
||||||
|
; FIXME It's annoying that fast A20
|
||||||
|
; will crash old systems, but it's
|
||||||
|
; just so small...
|
||||||
|
in al, 0x92 ; fast A20
|
||||||
|
test al, 2
|
||||||
|
jnz .fa20_end
|
||||||
|
or al, 2
|
||||||
|
and al, 0xFE
|
||||||
|
out 0x92, al
|
||||||
|
.fa20_end:
|
||||||
|
jmp .a20
|
||||||
|
.kernel:
|
||||||
|
mov esi, 0x7E00
|
||||||
|
mov edi, 0x100000
|
||||||
|
mov ecx, 0x10000
|
||||||
|
rep movsb
|
||||||
|
xchg bx,bx
|
||||||
|
jmp 08h:0x100000
|
||||||
|
|
||||||
|
gdt_desc:
|
||||||
|
dw gdt_end - gdt
|
||||||
|
dd gdt
|
||||||
|
gdt:
|
||||||
|
gdt_null: dq 0
|
||||||
|
gdt_code: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address
|
||||||
|
db 0 ; bits 16-23 base address
|
||||||
|
db 10011010b ; access byte
|
||||||
|
db 11001111b ; bits 16-19 limit (4GB), 4 bits flags
|
||||||
|
db 0 ; bits 24-31 base address
|
||||||
|
gdt_data: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address
|
||||||
|
db 0 ; bits 16-23 base address
|
||||||
|
db 10010010b ; access byte
|
||||||
|
db 11001111b ; bits 16-19 limit (4GB), 4 bits flags
|
||||||
|
db 0 ; bits 24-31 base address
|
||||||
|
gdt_end:
|
||||||
|
|
||||||
|
string: db 'DISK ERROR'
|
||||||
|
string_end:
|
||||||
|
|
||||||
|
addr_packet:
|
||||||
|
db 0x10, 0x00 ; size, reserved
|
||||||
|
dw secreadcnt ; blocks
|
||||||
|
addr_packet_transfer_buff_off: dw 0x7E00 ; transfer buffer offset
|
||||||
|
addr_packet_transfer_buff_seg: dw 0x0000 ; transfer buffer segment
|
||||||
|
addr_packet_start_block: dq 0 ; start block
|
43
disk.c
43
disk.c
@ -1,22 +1,24 @@
|
|||||||
|
#include "disk.h"
|
||||||
#include "v86defs.h"
|
#include "v86defs.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "dosfs/dosfs.h"
|
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
|
|
||||||
extern void *memcpy(void *restrict dest, const void *restrict src, uintptr_t n);
|
extern void *memcpy(void *restrict dest, const void *restrict src, uintptr_t n);
|
||||||
|
|
||||||
|
#define SECTOR_SIZE 512
|
||||||
#define DISKCACHEBLOCKSIZE 0x1000 // 512 * 4
|
#define DISKCACHEBLOCKSIZE 0x1000 // 512 * 4
|
||||||
#define DISKCACHESECTORMASK 7
|
#define DISKCACHESECTORMASK 7
|
||||||
#define DISKCACHESECTORSIZE 8
|
#define DISKCACHESECTORSIZE 8
|
||||||
#define DISKCACHEBLOCKCOUNT 128
|
#define DISKCACHEBLOCKCOUNT 128
|
||||||
uint8_t (*DiskCache)[DISKCACHEBLOCKCOUNT][DISKCACHEBLOCKSIZE] = (uint8_t (*)[DISKCACHEBLOCKCOUNT][DISKCACHEBLOCKSIZE])0x280000;
|
uint8_t (*const DiskCache)[DISKCACHEBLOCKCOUNT][DISKCACHEBLOCKSIZE] = (uint8_t (* const)[DISKCACHEBLOCKCOUNT][DISKCACHEBLOCKSIZE])0x280000;
|
||||||
uint32_t DiskCacheLastRead[DISKCACHEBLOCKCOUNT];
|
uint32_t DiskCacheLastRead[DISKCACHEBLOCKCOUNT];
|
||||||
uint32_t DiskCacheSector[DISKCACHEBLOCKCOUNT];
|
uint32_t DiskCacheSector[DISKCACHEBLOCKCOUNT];
|
||||||
|
|
||||||
extern uint32_t _gpf_eax_save;
|
extern uint32_t _gpf_eax_save;
|
||||||
extern uint32_t _gpf_eflags_save;
|
extern uint32_t _gpf_eflags_save;
|
||||||
extern uint16_t error_screen[80*50]; // defined in kernel.c
|
extern uint16_t error_screen[80*50]; // defined in kernel.c
|
||||||
__attribute((__no_caller_saved_registers__))
|
__attribute__((__no_caller_saved_registers__))
|
||||||
|
__attribute__((__noreturn__))
|
||||||
extern void error_environment(); // defined in kernel.c
|
extern void error_environment(); // defined in kernel.c
|
||||||
uint32_t numHead;
|
uint32_t numHead;
|
||||||
uint32_t secPerTrack;
|
uint32_t secPerTrack;
|
||||||
@ -48,12 +50,6 @@ void Disk_SetupCHS() {
|
|||||||
maxCylinder = ((_gpf_eax_save & 0xff0000) >> 16) | ((_gpf_eax_save & 0xc0) << 2);
|
maxCylinder = ((_gpf_eax_save & 0xff0000) >> 16) | ((_gpf_eax_save & 0xc0) << 2);
|
||||||
useCHS = 1;
|
useCHS = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init Cache
|
|
||||||
for (int i = 0; i < DISKCACHEBLOCKCOUNT; i++) {
|
|
||||||
DiskCacheLastRead[i] = 0;
|
|
||||||
DiskCacheSector[i] = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint32_t TIMERVAL;
|
extern uint32_t TIMERVAL;
|
||||||
@ -95,26 +91,33 @@ void UpdateCache(uint32_t sector, uint8_t *buffer) {
|
|||||||
((uint32_t*)cache)[i] = ((uint32_t*)buffer)[i];
|
((uint32_t*)cache)[i] = ((uint32_t*)buffer)[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
|
void InitCache() {
|
||||||
// NOTE If the buffer provided is outside the 0x20000-0x2FE00 range,
|
for (int i = 0; i < DISKCACHEBLOCKCOUNT; i++) {
|
||||||
// the function will use that buffer for the Virtual 8086 process
|
DiskCacheLastRead[i] = 0;
|
||||||
// and copy to the other buffer after
|
DiskCacheSector[i] = -1;
|
||||||
uint8_t *v86buf = buffer;
|
}
|
||||||
if ((uintptr_t)v86buf >= 0x20000 && (uintptr_t)v86buf < 0x28000)
|
}
|
||||||
v86buf = (uint8_t *)0x28000;
|
|
||||||
else v86buf = (uint8_t *)0x20000;
|
|
||||||
|
|
||||||
// TODO This check should probably happen at the kernel level
|
// NOTE Must be run before reading from disk
|
||||||
if (useCHS == -1) {
|
void InitDisk() {
|
||||||
|
InitCache();
|
||||||
Disk_SetupCHS();
|
Disk_SetupCHS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Disk_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
|
||||||
uint8_t *cache = FindInCache(sector);
|
uint8_t *cache = FindInCache(sector);
|
||||||
if (cache) {
|
if (cache) {
|
||||||
memcpy(buffer, cache, count * SECTOR_SIZE);
|
memcpy(buffer, cache, count * SECTOR_SIZE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE If the buffer provided is outside the 0x20000-0x2F000 range,
|
||||||
|
// the function will use 0x20000 for the Virtual 8086 process
|
||||||
|
// and copy to the other buffer after
|
||||||
|
uint8_t *v86buf = (uintptr_t)buffer >= 0x20000 && (uintptr_t)buffer <= 0x2F000 ?
|
||||||
|
buffer :
|
||||||
|
(uint8_t*)0x20000;
|
||||||
|
|
||||||
// TODO Do error handling
|
// TODO Do error handling
|
||||||
if (!useCHS) {
|
if (!useCHS) {
|
||||||
// LBA Read
|
// LBA Read
|
||||||
@ -155,7 +158,7 @@ uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t
|
|||||||
memcpy(buffer, v86buf, count * SECTOR_SIZE);
|
memcpy(buffer, v86buf, count * SECTOR_SIZE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint32_t DFS_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
|
uint32_t Disk_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
|
||||||
// NOTE If the buffer provided is outside the 0x20000-0x2FE00 range,
|
// NOTE If the buffer provided is outside the 0x20000-0x2FE00 range,
|
||||||
// the function will use copy that buffer into the Virtual 8086 disk range
|
// the function will use copy that buffer into the Virtual 8086 disk range
|
||||||
uint8_t *v86buf = buffer;
|
uint8_t *v86buf = buffer;
|
||||||
|
@ -16,7 +16,7 @@ mov es, ax
|
|||||||
mov ss, ax
|
mov ss, ax
|
||||||
mov fs, ax
|
mov fs, ax
|
||||||
mov gs, ax
|
mov gs, ax
|
||||||
mov ebp, 0x400000
|
mov ebp, 0x800000
|
||||||
mov esp, ebp
|
mov esp, ebp
|
||||||
mov eax, 0x1f001f00
|
mov eax, 0x1f001f00
|
||||||
mov ecx, (80*25)/2
|
mov ecx, (80*25)/2
|
||||||
|
@ -83,6 +83,7 @@ je .int30
|
|||||||
cmp eax, 0x21CD ; int 0x21
|
cmp eax, 0x21CD ; int 0x21
|
||||||
je .int21
|
je .int21
|
||||||
jmp gpf_unhandled
|
jmp gpf_unhandled
|
||||||
|
|
||||||
.int21:
|
.int21:
|
||||||
pop eax ; command
|
pop eax ; command
|
||||||
cmp al, 0x00 ; get key
|
cmp al, 0x00 ; get key
|
||||||
@ -94,7 +95,13 @@ jne .s86
|
|||||||
call get_scancode
|
call get_scancode
|
||||||
jmp .return_to_offender
|
jmp .return_to_offender
|
||||||
.s86: cmp al, 0x86 ; v86 interrupt call
|
.s86: cmp al, 0x86 ; v86 interrupt call
|
||||||
|
je .v86int
|
||||||
|
cmp ax, 0x86D8 ; get v86 data pointer
|
||||||
jne .return_to_offender
|
jne .return_to_offender
|
||||||
|
mov eax, 0x30000 ; V86 Data
|
||||||
|
jmp .return_to_offender
|
||||||
|
|
||||||
|
.v86int:
|
||||||
add esp, 4
|
add esp, 4
|
||||||
add dword [esp+0], 2
|
add dword [esp+0], 2
|
||||||
; add a new task
|
; add a new task
|
||||||
@ -120,6 +127,7 @@ push eax ; cs
|
|||||||
push 0xFF00 ; sp
|
push 0xFF00 ; sp
|
||||||
push 0x8000 ; ss
|
push 0x8000 ; ss
|
||||||
jmp _enter_v86_internal_no_task ; NOT a function call
|
jmp _enter_v86_internal_no_task ; NOT a function call
|
||||||
|
|
||||||
.int30:
|
.int30:
|
||||||
pop eax ; return value
|
pop eax ; return value
|
||||||
jmp return_prev_task
|
jmp return_prev_task
|
||||||
|
113
file.c
Normal file
113
file.c
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#include "file.h"
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
|
// TODO Replace with something better
|
||||||
|
extern uint8_t ActiveFsId;
|
||||||
|
|
||||||
|
// Sets adjusted_path to the path without filesystem info,
|
||||||
|
// returns the filesystem calculated
|
||||||
|
uint8_t GetFsFromPath(char *path, char **adjusted_path) {
|
||||||
|
// On active filsystem
|
||||||
|
if (*path == '/') {
|
||||||
|
*adjusted_path = path;
|
||||||
|
return GetActiveFilesystemId();
|
||||||
|
}
|
||||||
|
// Read the filesystem ID
|
||||||
|
uint8_t id = 0;
|
||||||
|
char *tmp_path = path;
|
||||||
|
// Find first /
|
||||||
|
for (;*tmp_path != '/';tmp_path++);
|
||||||
|
*adjusted_path = tmp_path;
|
||||||
|
// Read octal num
|
||||||
|
tmp_path--;
|
||||||
|
for (uint8_t bit_off = 0; tmp_path >= path; tmp_path--, bit_off+=3) {
|
||||||
|
// Outside of octal range, error
|
||||||
|
if (*tmp_path < '0' || *tmp_path > '8') return 0;
|
||||||
|
id += (*tmp_path - '0') << bit_off;
|
||||||
|
|
||||||
|
}
|
||||||
|
// Return filesystem
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error. Fills provided struct FILE
|
||||||
|
int file_open(FILE *file, char *path, char mode) {
|
||||||
|
char *adj_path;
|
||||||
|
uint8_t fsid = GetFsFromPath(path, &adj_path);
|
||||||
|
filesystem *fs = GetFilesystem(fsid);
|
||||||
|
int err = fs->ops.file_open(fs->fs_data, file, adj_path, mode);
|
||||||
|
file->filesystem_id = fsid;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error.
|
||||||
|
int file_seek(FILE *file, uint32_t offset) {
|
||||||
|
filesystem *fs = GetFilesystem(file->filesystem_id);
|
||||||
|
return fs->ops.file_seek(fs->fs_data, file, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on error, bytes read on success.
|
||||||
|
int file_read(FILE *file, uint8_t *dest, uint32_t len) {
|
||||||
|
filesystem *fs = GetFilesystem(file->filesystem_id);
|
||||||
|
return fs->ops.file_read(fs->fs_data, file, dest, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on error, bytes written on success.
|
||||||
|
int file_write(FILE *file, uint8_t *src, uint32_t len) {
|
||||||
|
filesystem *fs = GetFilesystem(file->filesystem_id);
|
||||||
|
return fs->ops.file_write(fs->fs_data, file, src, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_close(FILE *file) {
|
||||||
|
filesystem *fs = GetFilesystem(file->filesystem_id);
|
||||||
|
return fs->ops.file_close(fs->fs_data, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error. Fills provided struct DIR
|
||||||
|
int dir_open(DIR *dir, char *path) {
|
||||||
|
char *adj_path;
|
||||||
|
uint8_t fsid = GetFsFromPath(path, &adj_path);
|
||||||
|
filesystem *fs = GetFilesystem(fsid);
|
||||||
|
int err = fs->ops.dir_open(fs->fs_data, dir, adj_path);
|
||||||
|
dir->filesystem_id = fsid;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return 0 on success, non-zero error code on error. Fills provided struct dirent.
|
||||||
|
int dir_nextentry(DIR *dir, dirent *ent) {
|
||||||
|
filesystem *fs = GetFilesystem(dir->filesystem_id);
|
||||||
|
return fs->ops.dir_nextentry(fs->fs_data, dir, ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dir_close(DIR *dir) {
|
||||||
|
filesystem *fs = GetFilesystem(dir->filesystem_id);
|
||||||
|
return fs->ops.dir_close(fs->fs_data, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error. Fills provided struct dirent.
|
||||||
|
int path_getinfo(char *path, dirent *ent) {
|
||||||
|
char *adj_path;
|
||||||
|
filesystem *fs = GetFilesystem(GetFsFromPath(path, &adj_path));
|
||||||
|
return fs->ops.path_getinfo(fs->fs_data, adj_path, ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error.
|
||||||
|
int path_mkdir(char *path) {
|
||||||
|
char *adj_path;
|
||||||
|
filesystem *fs = GetFilesystem(GetFsFromPath(path, &adj_path));
|
||||||
|
return fs->ops.path_mkdir(fs->fs_data, adj_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error.
|
||||||
|
int path_rmdir(char *path) {
|
||||||
|
char *adj_path;
|
||||||
|
filesystem *fs = GetFilesystem(GetFsFromPath(path, &adj_path));
|
||||||
|
return fs->ops.path_rmdir(fs->fs_data, adj_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error.
|
||||||
|
int path_rmfile(char *path) {
|
||||||
|
char *adj_path;
|
||||||
|
filesystem *fs = GetFilesystem(GetFsFromPath(path, &adj_path));
|
||||||
|
return fs->ops.path_rmfile(fs->fs_data, adj_path);
|
||||||
|
}
|
130
fs.c
Normal file
130
fs.c
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#include "fs.h"
|
||||||
|
#include "disk.h"
|
||||||
|
|
||||||
|
struct FsType {
|
||||||
|
uint32_t type_id;
|
||||||
|
int (*init_func)(filesystem *, uint32_t);
|
||||||
|
// Not yet decided
|
||||||
|
char (*detect_func)(uint32_t);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO Get these dynamically somehow
|
||||||
|
int InitDosFs(filesystem *fs, uint32_t start_sector);
|
||||||
|
char DetectDosPart(uint32_t start_sector);
|
||||||
|
|
||||||
|
struct FsType SupportedFilesystems[] = {
|
||||||
|
{
|
||||||
|
.type_id = 0xD05,
|
||||||
|
.init_func = InitDosFs,
|
||||||
|
.detect_func = DetectDosPart
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAXFS 255
|
||||||
|
filesystem *ActiveFilesystems = (filesystem *)0x240000;
|
||||||
|
|
||||||
|
uint8_t ActiveFsIdx;
|
||||||
|
|
||||||
|
filesystem *GetFilesystem(uint8_t idx) {
|
||||||
|
if (idx >= MAXFS) return 0;
|
||||||
|
filesystem *fs = &ActiveFilesystems[idx];
|
||||||
|
return fs->type != 0 ? fs : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem *GetActiveFilesystem() {
|
||||||
|
return &ActiveFilesystems[ActiveFsIdx];
|
||||||
|
}
|
||||||
|
uint8_t GetActiveFilesystemId() {
|
||||||
|
return ActiveFsIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem *SetActiveFilesystem(uint8_t idx) {
|
||||||
|
if (idx >= MAXFS) return 0;
|
||||||
|
filesystem *fs = &ActiveFilesystems[idx];
|
||||||
|
if (fs->type == 0) return 0;
|
||||||
|
ActiveFsIdx = idx;
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActiveFilesystemBitmap(char *bitmap) {
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
bitmap[i] = ActiveFilesystems[i].type != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PartTableEntry_t {
|
||||||
|
uint8_t attr;
|
||||||
|
uint8_t start_chs0;
|
||||||
|
uint8_t start_chs1;
|
||||||
|
uint8_t start_chs2;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t end_chs0;
|
||||||
|
uint8_t end_chs1;
|
||||||
|
uint8_t end_chs2;
|
||||||
|
uint32_t start_lba;
|
||||||
|
uint32_t num_sectors;
|
||||||
|
};
|
||||||
|
typedef struct MBR_t {
|
||||||
|
char boot_code[0x1B8];
|
||||||
|
uint32_t signature;
|
||||||
|
uint16_t reserved;
|
||||||
|
struct PartTableEntry_t partTable[4];
|
||||||
|
uint16_t boot_sig;
|
||||||
|
} __attribute__((__packed__)) MBR_t;
|
||||||
|
|
||||||
|
// TODO Just check for this
|
||||||
|
uint8_t BootPartition;
|
||||||
|
uint8_t NextAvailableFilesystem;
|
||||||
|
|
||||||
|
MBR_t SysMbr;
|
||||||
|
|
||||||
|
void MakeMBRPartitions() {
|
||||||
|
// Get MBR
|
||||||
|
MBR_t *mbr = &SysMbr;
|
||||||
|
Disk_ReadSector(0, (uint8_t*)mbr, 0, 1);
|
||||||
|
|
||||||
|
// Scan partitions
|
||||||
|
for (int p = 0; p < 4; p++) {
|
||||||
|
if (p == BootPartition) continue;
|
||||||
|
if (mbr->partTable[p].type == 0) continue;
|
||||||
|
uint32_t partStart = mbr->partTable[p].start_lba;
|
||||||
|
if (partStart == 0) continue;
|
||||||
|
// Scan supported filesystems
|
||||||
|
filesystem *sys = &ActiveFilesystems[NextAvailableFilesystem];
|
||||||
|
for (int i = 0; i < sizeof(SupportedFilesystems)/sizeof(struct FsType); i++) {
|
||||||
|
if (!SupportedFilesystems[i].detect_func(partStart)) continue;
|
||||||
|
SupportedFilesystems[i].init_func(sys, partStart);
|
||||||
|
sys->type = SupportedFilesystems[i].type_id;
|
||||||
|
ActiveFsIdx = NextAvailableFilesystem;
|
||||||
|
NextAvailableFilesystem++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MakeSystemVolume(uint8_t bootPartition) {
|
||||||
|
// Clear out filesystem area
|
||||||
|
for (int i = 0; i < (sizeof(filesystem)*MAXFS)/sizeof(uint32_t);i++)
|
||||||
|
((uint32_t*)ActiveFilesystems)[i] = 0;
|
||||||
|
|
||||||
|
BootPartition = bootPartition;
|
||||||
|
NextAvailableFilesystem = 1;
|
||||||
|
// Get MBR
|
||||||
|
MBR_t *mbr = &SysMbr;
|
||||||
|
Disk_ReadSector(0, (uint8_t*)mbr, 0, 1);
|
||||||
|
// Get boot partition sector
|
||||||
|
uint32_t sys_sector = mbr->partTable[bootPartition].start_lba;
|
||||||
|
|
||||||
|
// Scan supported filesystems
|
||||||
|
filesystem *sys = &ActiveFilesystems[0];
|
||||||
|
for (int i = 0; i < sizeof(SupportedFilesystems)/sizeof(struct FsType); i++) {
|
||||||
|
asm volatile("xchg %bx,%bx");
|
||||||
|
if (!SupportedFilesystems[i].detect_func(sys_sector)) continue;
|
||||||
|
SupportedFilesystems[i].init_func(sys, sys_sector);
|
||||||
|
sys->type = SupportedFilesystems[i].type_id;
|
||||||
|
ActiveFsIdx = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init Failed
|
||||||
|
return -1;
|
||||||
|
}
|
239
fs_dos.c
Normal file
239
fs_dos.c
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
#include "disk.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "dosfs/dosfs.h"
|
||||||
|
|
||||||
|
char *strncpy(char *restrict d, const char *restrict s, uintptr_t n);
|
||||||
|
int strcmp(const char *l, const char *r);
|
||||||
|
void *memcpy(void *restrict dest, const void *restrict src, uintptr_t n);
|
||||||
|
|
||||||
|
// Implementations for DOSFS
|
||||||
|
|
||||||
|
uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
|
||||||
|
return Disk_ReadSector(unit, buffer, sector, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DFS_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
|
||||||
|
return Disk_WriteSector(unit, buffer, sector, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// System Implementations
|
||||||
|
|
||||||
|
typedef struct fsdat {
|
||||||
|
VOLINFO vi;
|
||||||
|
} fsdat;
|
||||||
|
|
||||||
|
int file83ToPath(uint8_t *src, char *path) {
|
||||||
|
uint8_t tmp, trailingSpace;
|
||||||
|
for (trailingSpace=0, tmp = 0; tmp < 8 && src[tmp]; tmp++) {
|
||||||
|
path[tmp] = src[tmp];
|
||||||
|
if (src[tmp] == ' ') trailingSpace++;
|
||||||
|
else trailingSpace = 0;
|
||||||
|
}
|
||||||
|
tmp -= trailingSpace;
|
||||||
|
path[tmp++] = '.';
|
||||||
|
trailingSpace = 0;
|
||||||
|
for (int i = 8; i < 11 && src[i]; i++, tmp++) {
|
||||||
|
path[tmp] = src[i];
|
||||||
|
if (src[i] == ' ') trailingSpace++;
|
||||||
|
else trailingSpace = 0;
|
||||||
|
}
|
||||||
|
tmp -= trailingSpace;
|
||||||
|
if (trailingSpace == 3) tmp--;
|
||||||
|
path[tmp] = 0;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t stripToDir(char *path) {
|
||||||
|
int i = 0;
|
||||||
|
// find end of string
|
||||||
|
for (;path[i];i++);
|
||||||
|
// find last /
|
||||||
|
for (;path[i] != '/' && i >= 0;i--);
|
||||||
|
// path[i] == '/'
|
||||||
|
// set next to end, return split location
|
||||||
|
path[i+1] = 0;
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dos_file_open(uint8_t *dat, FILE *f, char *path, char mode) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
uint8_t dfs_mode =
|
||||||
|
(mode & OPENREAD ? DFS_READ : 0) |
|
||||||
|
(mode & OPENWRITE ? DFS_WRITE : 0);
|
||||||
|
return DFS_OpenFile(&fs->vi, (uint8_t *)path, dfs_mode, scratch, (FILEINFO *)f->bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dos_file_seek(uint8_t *dat, FILE *f, uint32_t offset) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
DFS_Seek((FILEINFO *)f->bytes, offset, scratch);
|
||||||
|
if (((FILEINFO *)f->bytes)->pointer != offset) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dos_file_read(uint8_t *dat, FILE *f, uint8_t *dest, uint32_t len) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
uint32_t successcount;
|
||||||
|
uint32_t err = DFS_ReadFile((FILEINFO *)f->bytes, scratch, dest, &successcount, len);
|
||||||
|
// Error
|
||||||
|
if (err != 0 && err != DFS_EOF)
|
||||||
|
return 0;
|
||||||
|
// Success or EOF
|
||||||
|
return successcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dos_file_write(uint8_t *dat, FILE *f, uint8_t *src, uint32_t len) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
uint32_t successcount;
|
||||||
|
uint32_t err = DFS_WriteFile((FILEINFO *)f->bytes, scratch, src, &successcount, len);
|
||||||
|
// Error
|
||||||
|
if (err != 0) return 0;
|
||||||
|
// Success
|
||||||
|
return successcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DOSFS doesn't have anything to clean up
|
||||||
|
void dos_file_close(uint8_t *dat, FILE *f) { return; }
|
||||||
|
|
||||||
|
int dos_dir_open(uint8_t *dat, DIR *d, char *path) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
((DIRINFO *)d->bytes)->scratch = scratch;
|
||||||
|
return DFS_OpenDir(&fs->vi, (uint8_t *)path, (DIRINFO *)d->bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dos_dir_nextentry(uint8_t *dat, DIR *d, dirent *ent) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
DIRENT de;
|
||||||
|
for (;;) {
|
||||||
|
uint32_t code = DFS_GetNext(&fs->vi, (DIRINFO *)d->bytes, &de);
|
||||||
|
if (code == DFS_EOF) return 1;
|
||||||
|
if (code != DFS_OK) return -1;
|
||||||
|
// Deleted file, continue to next entry
|
||||||
|
if (de.name[0] == 0) continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Copy info
|
||||||
|
ent->type = de.attr & ATTR_DIRECTORY ? FT_DIR : FT_REG;
|
||||||
|
ent->size = (uint32_t)de.filesize_0 +
|
||||||
|
((uint32_t)de.filesize_1 << 8) +
|
||||||
|
((uint32_t)de.filesize_2 << 16) +
|
||||||
|
((uint32_t)de.filesize_3 << 24);
|
||||||
|
// Haven't decided format on these yet
|
||||||
|
ent->last_modified = 0;
|
||||||
|
ent->last_accessed = 0;
|
||||||
|
ent->created = 0;
|
||||||
|
|
||||||
|
ent->namelen = file83ToPath(de.name, ent->name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DOSFS doesn't have anything to clean up
|
||||||
|
void dos_dir_close(uint8_t *dat, DIR *d) { return; }
|
||||||
|
|
||||||
|
// TODO Make this less expensive -> Use DOSFS directly?
|
||||||
|
int dos_path_getinfo(uint8_t *dat, char *path, dirent *d) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
|
||||||
|
// Get directory path is in
|
||||||
|
uint8_t tmppath[MAX_PATH];
|
||||||
|
strncpy((char*)tmppath,path,MAX_PATH);
|
||||||
|
tmppath[MAX_PATH-1]=0;
|
||||||
|
uintptr_t nameidx = stripToDir((char*)tmppath);
|
||||||
|
char *name = &path[nameidx];
|
||||||
|
|
||||||
|
// Open directory
|
||||||
|
DIR dir;
|
||||||
|
dos_dir_open(dat, &dir, (char*)tmppath);
|
||||||
|
|
||||||
|
dirent de;
|
||||||
|
// Enumerate info
|
||||||
|
for (;dos_dir_nextentry(dat, &dir, &de) == 0;) {
|
||||||
|
// Check if correct entry
|
||||||
|
if (strcmp(de.name, name) == 0) {
|
||||||
|
// Copy to caller dirent
|
||||||
|
for (int i = 0; i < sizeof(dirent); i++)
|
||||||
|
((uint8_t*)d)[i] = ((uint8_t*)&de)[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Did not find or error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Unimplemented
|
||||||
|
int dos_path_mkdir(uint8_t *dat, char *path) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Unimplemented
|
||||||
|
int dos_path_rmdir(uint8_t *dat, char *path) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Unimplemented
|
||||||
|
int dos_path_rmfile(uint8_t *dat, char *path) {
|
||||||
|
fsdat *fs = (fsdat *)dat;
|
||||||
|
uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DOSFS doesn't have anything to clean up
|
||||||
|
void dos_endfs(uint8_t *dat) { return; }
|
||||||
|
|
||||||
|
// Try to detect if partition is a valid DOS partition
|
||||||
|
char DetectDosPart(uint32_t start_sector) {
|
||||||
|
// Read sector
|
||||||
|
//uint8_t *scratch = (uint8_t *)0x20000;
|
||||||
|
//Disk_ReadSector(0, scratch, start_sector, 1);
|
||||||
|
//// Check for start bytes EBXX90
|
||||||
|
//if (((*(uint32_t*)&scratch[0]) & 0x00FF00FF) != 0x9000EB) return 0;
|
||||||
|
//// Check for bytes per sector == 512 (We don't support other values anyway)
|
||||||
|
//if (*(uint16_t*)&scratch[0xB] != 512) return 0;
|
||||||
|
|
||||||
|
// TODO Check more, so we *know* it's FAT
|
||||||
|
|
||||||
|
// We're probably FAT
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int InitDosFs(filesystem *fs, uint32_t start_sector) {
|
||||||
|
uint8_t *diskReadBuf = (uint8_t *)0x20000;
|
||||||
|
|
||||||
|
VOLINFO *vi = (VOLINFO *)fs->fs_data;
|
||||||
|
if (DFS_GetVolInfo(0, diskReadBuf, start_sector, (VOLINFO *)fs->fs_data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; vi->label[i] && i < sizeof(vi->label); i++)
|
||||||
|
fs->label[i] = vi->label[i];
|
||||||
|
fs->labellen = i;
|
||||||
|
|
||||||
|
fs->ops.file_open = dos_file_open;
|
||||||
|
fs->ops.file_seek = dos_file_seek;
|
||||||
|
fs->ops.file_read = dos_file_read;
|
||||||
|
fs->ops.file_write = dos_file_write;
|
||||||
|
fs->ops.file_close = dos_file_close;
|
||||||
|
fs->ops.dir_open = dos_dir_open;
|
||||||
|
fs->ops.dir_nextentry = dos_dir_nextentry;
|
||||||
|
fs->ops.dir_close = dos_dir_close;
|
||||||
|
fs->ops.path_getinfo = dos_path_getinfo;
|
||||||
|
fs->ops.path_mkdir = dos_path_mkdir;
|
||||||
|
fs->ops.path_rmdir = dos_path_rmdir;
|
||||||
|
fs->ops.path_rmfile = dos_path_rmfile;
|
||||||
|
fs->ops.endfs = dos_endfs;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -66,6 +66,7 @@ pop ds
|
|||||||
pop eax
|
pop eax
|
||||||
iret
|
iret
|
||||||
|
|
||||||
|
; from linux 0.0.1
|
||||||
global picInit
|
global picInit
|
||||||
picInit:
|
picInit:
|
||||||
mov al, 0x11 ; initialization sequence
|
mov al, 0x11 ; initialization sequence
|
||||||
|
65
helper.c
65
helper.c
@ -5,6 +5,22 @@ uint16_t *nextLine(uint16_t *p, uint16_t *b) {
|
|||||||
return (uint16_t *)(v + (160 - ((v - (uintptr_t)b) % 160)));
|
return (uint16_t *)(v + (160 - ((v - (uintptr_t)b) % 160)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void trimPath(char *path, char *buff, uint32_t maxLen) {
|
||||||
|
int pathLen = 0;
|
||||||
|
for (;path[pathLen];pathLen++);
|
||||||
|
pathLen++;
|
||||||
|
if (pathLen < maxLen) {
|
||||||
|
for(int i = 0; i < pathLen; i++)
|
||||||
|
buff[i] = path[i];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
buff[i] = '.';
|
||||||
|
for (int i = 3; i < maxLen; i++) {
|
||||||
|
buff[i] = path[pathLen-maxLen+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void V8086Int(uint8_t interrupt, union V86Regs_t *regs) {
|
void V8086Int(uint8_t interrupt, union V86Regs_t *regs) {
|
||||||
// Edit the v8086 code with the interrupt
|
// Edit the v8086 code with the interrupt
|
||||||
// Writing 4 bytes to ensure proper code
|
// Writing 4 bytes to ensure proper code
|
||||||
@ -32,51 +48,6 @@ void SetCursorDisabled() {
|
|||||||
V8086Int(0x10, ®s);
|
V8086Int(0x10, ®s);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t OpenVol(VOLINFO *vi) {
|
void GetFileList(DIR *dir, dirent *entries, int32_t *entCount, int32_t maxEntries) {
|
||||||
uint8_t *diskReadBuf = (uint8_t *)0x20000;
|
for ((*entCount) = 0; *entCount < maxEntries && !dir_nextentry(dir, &entries[*entCount]); (*entCount)++);
|
||||||
uint8_t pactive, ptype;
|
|
||||||
uint32_t pstart, psize;
|
|
||||||
pstart = DFS_GetPtnStart(0, diskReadBuf, 0, &pactive, &ptype, &psize);
|
|
||||||
return DFS_GetVolInfo(0, diskReadBuf, pstart, vi);
|
|
||||||
}
|
|
||||||
uint32_t OpenDir(uint8_t *path, VOLINFO *vi, DIRINFO *di) {
|
|
||||||
uint8_t *diskReadBuf = (uint8_t *)0x20000;
|
|
||||||
di->scratch = diskReadBuf;
|
|
||||||
return DFS_OpenDir(vi, path, di);
|
|
||||||
}
|
|
||||||
|
|
||||||
void File83ToPath(char *src, char *path) {
|
|
||||||
uint8_t tmp, trailingSpace;
|
|
||||||
for (trailingSpace=0, tmp = 0; tmp < 8 && src[tmp]; tmp++) {
|
|
||||||
path[tmp] = src[tmp];
|
|
||||||
if (src[tmp] == ' ') trailingSpace++;
|
|
||||||
else trailingSpace = 0;
|
|
||||||
}
|
|
||||||
tmp -= trailingSpace;
|
|
||||||
path[tmp++] = '.';
|
|
||||||
trailingSpace = 0;
|
|
||||||
for (int i = 8; i < 11 && src[i]; i++, tmp++) {
|
|
||||||
path[tmp] = src[i];
|
|
||||||
if (src[i] == ' ') trailingSpace++;
|
|
||||||
else trailingSpace = 0;
|
|
||||||
}
|
|
||||||
tmp -= trailingSpace;
|
|
||||||
if (trailingSpace == 3) tmp--;
|
|
||||||
path[tmp] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetFileList(DIRENT *entries, int32_t *entCount, VOLINFO *vi, DIRINFO *di) {
|
|
||||||
uint8_t *diskReadBuf = (uint8_t *)0x20000;
|
|
||||||
DIRENT de;
|
|
||||||
int32_t fileCount = 0;
|
|
||||||
while (!DFS_GetNext(vi, di, &de)) {
|
|
||||||
if (de.name[0]) {
|
|
||||||
uint8_t *d = (uint8_t*)&entries[fileCount];
|
|
||||||
uint8_t *s = (uint8_t*)&de;
|
|
||||||
for (int i = 0; i < sizeof(DIRENT); i++)
|
|
||||||
d[i] = s[i];
|
|
||||||
fileCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*entCount = fileCount;
|
|
||||||
}
|
}
|
||||||
|
104
hexedit.c
104
hexedit.c
@ -1,3 +1,4 @@
|
|||||||
|
#include "file.h"
|
||||||
#include "progs.h"
|
#include "progs.h"
|
||||||
|
|
||||||
#define BLOCKSIZE 0x10000 // 64K
|
#define BLOCKSIZE 0x10000 // 64K
|
||||||
@ -5,17 +6,16 @@
|
|||||||
#define BLOCKSHIFT 16 // blockSize = 1 << blockShift
|
#define BLOCKSHIFT 16 // blockSize = 1 << blockShift
|
||||||
#define MAXFILESIZE 0x80000000 // 2GB
|
#define MAXFILESIZE 0x80000000 // 2GB
|
||||||
#define TOTALBLOCKS (MAXFILESIZE/BLOCKSIZE)
|
#define TOTALBLOCKS (MAXFILESIZE/BLOCKSIZE)
|
||||||
uint16_t writtenMap[TOTALBLOCKS];
|
uint16_t writtenMap[TOTALBLOCKS] __attribute__((section(".hexbss")));;
|
||||||
uint32_t blockLenMap[TOTALBLOCKS];
|
uint32_t blockLenMap[TOTALBLOCKS] __attribute__((section(".hexbss")));;
|
||||||
// NOTE This is linked at the end of program BSS section,
|
// NOTE This is linked at the end of program BSS section,
|
||||||
// so that it can be expanded without telling C how much
|
// so that it can be expanded without telling C how much
|
||||||
// it actually needs
|
// it actually needs
|
||||||
uint8_t writeStoreBase[BLOCKSIZE] __attribute__((section(".bss.end")));
|
uint8_t writeStoreBase[BLOCKSIZE] __attribute__((section(".hexlatebss")));
|
||||||
void HexEditor(uint8_t *path, VOLINFO *vi) {
|
void HexEditor(char *path) {
|
||||||
uint32_t err;
|
uint32_t err;
|
||||||
uint16_t *vga_text = (uint16_t *)0xb8000;
|
uint16_t *vga_text = (uint16_t *)0xb8000;
|
||||||
uint32_t screenSize = 80*25;
|
uint32_t screenSize = 80*25;
|
||||||
uint8_t *scratch = (uint8_t *)0x20000;
|
|
||||||
uint8_t (*writeStore)[BLOCKSIZE] = &writeStoreBase;
|
uint8_t (*writeStore)[BLOCKSIZE] = &writeStoreBase;
|
||||||
for (int i = 0; i < TOTALBLOCKS; i++)
|
for (int i = 0; i < TOTALBLOCKS; i++)
|
||||||
writtenMap[i] = 0;
|
writtenMap[i] = 0;
|
||||||
@ -23,31 +23,39 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
// First two blocks are screen buffer
|
// First two blocks are screen buffer
|
||||||
uint32_t nextFreeBlock = 2;
|
uint32_t nextFreeBlock = 2;
|
||||||
|
|
||||||
FILEINFO fi;
|
|
||||||
vga_text = (uint16_t *)0xb8000;
|
vga_text = (uint16_t *)0xb8000;
|
||||||
for (int i = 0; i < 80*50; i++)
|
for (int i = 0; i < 80*50; i++)
|
||||||
vga_text[i] = 0x0f00;
|
vga_text[i] = 0x0f00;
|
||||||
err = DFS_OpenFile(vi, path, DFS_READ | DFS_WRITE, scratch, &fi);
|
dirent de;
|
||||||
|
err = path_getinfo(path, &de);
|
||||||
if (err) {
|
if (err) {
|
||||||
vga_text += printStr("Open Error: ", vga_text);
|
vga_text += printStr("Error getting file info.", vga_text);
|
||||||
printDword(err, vga_text);
|
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fi.filelen == 0) {
|
uint32_t filelen = de.size;
|
||||||
|
if (filelen == 0) {
|
||||||
vga_text += printStr("File ", vga_text);
|
vga_text += printStr("File ", vga_text);
|
||||||
vga_text += printStr((char*)path, vga_text);
|
vga_text += printStr((char*)path, vga_text);
|
||||||
vga_text += printStr(" has no data.", vga_text);
|
vga_text += printStr(" has no data.", vga_text);
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fi.filelen > MAXFILESIZE) {
|
if (filelen > MAXFILESIZE) {
|
||||||
vga_text += printStr("File ", vga_text);
|
vga_text += printStr("File ", vga_text);
|
||||||
vga_text += printStr((char*)path, vga_text);
|
vga_text += printStr((char*)path, vga_text);
|
||||||
vga_text += printStr(" is too large (> 2GB).", vga_text);
|
vga_text += printStr(" is too large (> 2GB).", vga_text);
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
FILE file;
|
||||||
|
err = file_open(&file, path, OPENREAD|OPENWRITE);
|
||||||
|
if (err) {
|
||||||
|
vga_text += printStr("Open Error: ", vga_text);
|
||||||
|
printDword(err, vga_text);
|
||||||
|
kbd_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
uint32_t drawOffset = 0, lastDrawOffset = -1;
|
uint32_t drawOffset = 0, lastDrawOffset = -1;
|
||||||
char cont = 1;
|
char cont = 1;
|
||||||
uint32_t byteCount = 16*24, lastByteCount = 0;
|
uint32_t byteCount = 16*24, lastByteCount = 0;
|
||||||
@ -70,13 +78,13 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
// things will be caught by sanity checks.
|
// things will be caught by sanity checks.
|
||||||
// Scroll Back
|
// Scroll Back
|
||||||
if (cursorScreenOff < 0) {
|
if (cursorScreenOff < 0) {
|
||||||
if (drawOffset - 16 < fi.filelen)
|
if (drawOffset - 16 < filelen)
|
||||||
drawOffset -= 16;
|
drawOffset -= 16;
|
||||||
cursorScreenOff += 16;
|
cursorScreenOff += 16;
|
||||||
}
|
}
|
||||||
// Scroll Forward
|
// Scroll Forward
|
||||||
if (cursorScreenOff >= byteCount) {
|
if (cursorScreenOff >= byteCount) {
|
||||||
if (drawOffset + 16 < fi.filelen)
|
if (drawOffset + 16 < filelen)
|
||||||
drawOffset += 16;
|
drawOffset += 16;
|
||||||
cursorScreenOff -= 16;
|
cursorScreenOff -= 16;
|
||||||
}
|
}
|
||||||
@ -84,8 +92,8 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
// Sanity checks
|
// Sanity checks
|
||||||
if (cursorScreenOff >= byteCount)
|
if (cursorScreenOff >= byteCount)
|
||||||
cursorScreenOff = byteCount - 1;
|
cursorScreenOff = byteCount - 1;
|
||||||
if (cursorScreenOff + drawOffset >= fi.filelen)
|
if (cursorScreenOff + drawOffset >= filelen)
|
||||||
cursorScreenOff = fi.filelen - drawOffset - 1;
|
cursorScreenOff = filelen - drawOffset - 1;
|
||||||
if (cursorScreenOff < 0) cursorScreenOff = 0;
|
if (cursorScreenOff < 0) cursorScreenOff = 0;
|
||||||
|
|
||||||
if (cursorNibble != lastCursorNibble)
|
if (cursorNibble != lastCursorNibble)
|
||||||
@ -185,16 +193,14 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
} else {
|
} else {
|
||||||
uint32_t blockOffset = drawOffset & BLOCKMASK;
|
uint32_t blockOffset = drawOffset & BLOCKMASK;
|
||||||
vga_text = &((uint16_t*)0xb8000)[80];
|
vga_text = &((uint16_t*)0xb8000)[80];
|
||||||
DFS_Seek(&fi, blockOffset, scratch);
|
if (file_seek(&file, blockOffset)) {
|
||||||
if (fi.pointer != blockOffset) {
|
|
||||||
vga_text += printStr("Seek Error", vga_text);
|
vga_text += printStr("Seek Error", vga_text);
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
err = DFS_ReadFile(&fi, scratch, screenBuff, &currBuffLength, BLOCKSIZE);
|
currBuffLength = file_read(&file, screenBuff, BLOCKSIZE);
|
||||||
if (err && err != DFS_EOF) {
|
if (!currBuffLength && blockOffset != filelen) {
|
||||||
vga_text += printStr("Read Error: ", vga_text);
|
vga_text += printStr("Read Error", vga_text);
|
||||||
printDword(err, vga_text);
|
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -222,16 +228,14 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
} else {
|
} else {
|
||||||
uint32_t blockOffset = (drawOffset & BLOCKMASK) + BLOCKSIZE;
|
uint32_t blockOffset = (drawOffset & BLOCKMASK) + BLOCKSIZE;
|
||||||
vga_text = &((uint16_t*)0xb8000)[80];
|
vga_text = &((uint16_t*)0xb8000)[80];
|
||||||
DFS_Seek(&fi, blockOffset, scratch);
|
if (file_seek(&file, blockOffset)) {
|
||||||
if (fi.pointer != blockOffset) {
|
|
||||||
vga_text += printStr("Seek Error", vga_text);
|
vga_text += printStr("Seek Error", vga_text);
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
err = DFS_ReadFile(&fi, scratch, &screenBuff[BLOCKSIZE], &nextBuffLength, BLOCKSIZE);
|
nextBuffLength = file_read(&file, &screenBuff[BLOCKSIZE], BLOCKSIZE);
|
||||||
if (err && err != DFS_EOF) {
|
if (!nextBuffLength && blockOffset != filelen) {
|
||||||
vga_text += printStr("Read Error: ", vga_text);
|
vga_text += printStr("Read Error", vga_text);
|
||||||
printDword(err, vga_text);
|
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -244,11 +248,15 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
}
|
}
|
||||||
if (redraw) {
|
if (redraw) {
|
||||||
vga_text = (uint16_t *)0xb8000;
|
vga_text = (uint16_t *)0xb8000;
|
||||||
vga_text += printStr((char*)path, vga_text);
|
|
||||||
vga_text += printChar(fileChanged ? '*' : ' ', vga_text);
|
|
||||||
{
|
{
|
||||||
const char prnt[] = "Scroll: Up/Down PgUp/PgDown Home/End Exit: F1";
|
const char prnt[] = "Scroll: Up/Down PgUp/PgDown Home/End Exit: F1";
|
||||||
vga_text = &((uint16_t*)0xb8000)[80-sizeof(prnt)];
|
vga_text = &((uint16_t*)0xb8000)[0];
|
||||||
|
char pathBuff[22];
|
||||||
|
trimPath((char*)path, pathBuff, sizeof(pathBuff));
|
||||||
|
vga_text += printStr(pathBuff, vga_text);
|
||||||
|
vga_text += printChar(fileChanged ? '*' : ' ', vga_text);
|
||||||
|
for (;vga_text < &((uint16_t*)0xb8000)[80-sizeof(prnt)];)
|
||||||
|
vga_text += printChar(' ', vga_text);
|
||||||
vga_text += printStr((char*)prnt, vga_text);
|
vga_text += printStr((char*)prnt, vga_text);
|
||||||
}
|
}
|
||||||
vga_text = &((uint16_t*)0xb8000)[80];
|
vga_text = &((uint16_t*)0xb8000)[80];
|
||||||
@ -297,12 +305,12 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
switch (key & 0xff) {
|
switch (key & 0xff) {
|
||||||
case KEY_DOWN:
|
case KEY_DOWN:
|
||||||
// Stay in file
|
// Stay in file
|
||||||
if ((cursorScreenOff + 16 + drawOffset) < fi.filelen)
|
if ((cursorScreenOff + 16 + drawOffset) < filelen)
|
||||||
cursorScreenOff += 16;
|
cursorScreenOff += 16;
|
||||||
break;
|
break;
|
||||||
case KEY_UP:
|
case KEY_UP:
|
||||||
// Stay in file
|
// Stay in file
|
||||||
if ((uint32_t)(cursorScreenOff - 16 + drawOffset) < fi.filelen)
|
if ((uint32_t)(cursorScreenOff - 16 + drawOffset) < filelen)
|
||||||
cursorScreenOff -= 16;
|
cursorScreenOff -= 16;
|
||||||
break;
|
break;
|
||||||
case KEY_LEFT:
|
case KEY_LEFT:
|
||||||
@ -312,7 +320,7 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
cursorNibble = 0;
|
cursorNibble = 0;
|
||||||
cursorScreenOff |= 0xF;
|
cursorScreenOff |= 0xF;
|
||||||
// Stay in file
|
// Stay in file
|
||||||
} else if ((cursorScreenOff - 1 + drawOffset) < fi.filelen) {
|
} else if ((cursorScreenOff - 1 + drawOffset) < filelen) {
|
||||||
cursorScreenOff--;
|
cursorScreenOff--;
|
||||||
if (cursorNibble == 1) cursorNibble = 0;
|
if (cursorNibble == 1) cursorNibble = 0;
|
||||||
}
|
}
|
||||||
@ -324,19 +332,19 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
cursorNibble = 2;
|
cursorNibble = 2;
|
||||||
cursorScreenOff &= ~0xF;
|
cursorScreenOff &= ~0xF;
|
||||||
// Stay in file
|
// Stay in file
|
||||||
} else if ((cursorScreenOff + 1 + drawOffset) < fi.filelen) {
|
} else if ((cursorScreenOff + 1 + drawOffset) < filelen) {
|
||||||
cursorScreenOff++;
|
cursorScreenOff++;
|
||||||
if (cursorNibble == 0) cursorNibble = 1;
|
if (cursorNibble == 0) cursorNibble = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case KEY_PGDOWN:
|
case KEY_PGDOWN:
|
||||||
if (drawOffset + byteCount < fi.filelen)
|
if (drawOffset + byteCount < filelen)
|
||||||
drawOffset += byteCount;
|
drawOffset += byteCount;
|
||||||
else if ((fi.filelen / byteCount) * byteCount > drawOffset)
|
else if ((filelen / byteCount) * byteCount > drawOffset)
|
||||||
drawOffset = (fi.filelen / byteCount) * byteCount;
|
drawOffset = (filelen / byteCount) * byteCount;
|
||||||
break;
|
break;
|
||||||
case KEY_PGUP:
|
case KEY_PGUP:
|
||||||
if (drawOffset - byteCount < fi.filelen)
|
if (drawOffset - byteCount < filelen)
|
||||||
drawOffset -= byteCount;
|
drawOffset -= byteCount;
|
||||||
else drawOffset = 0;
|
else drawOffset = 0;
|
||||||
break;
|
break;
|
||||||
@ -355,8 +363,8 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
drawOffset = 0;
|
drawOffset = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_F4: // end of file
|
case KEY_F4: // end of file
|
||||||
if ((fi.filelen / byteCount) * byteCount > drawOffset)
|
if ((filelen / byteCount) * byteCount > drawOffset)
|
||||||
drawOffset = (fi.filelen / byteCount) * byteCount;
|
drawOffset = (filelen / byteCount) * byteCount;
|
||||||
break;
|
break;
|
||||||
case KEY_F6: // TODO write file
|
case KEY_F6: // TODO write file
|
||||||
break;
|
break;
|
||||||
@ -407,8 +415,12 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
}
|
}
|
||||||
if (!fileChanged) return;
|
if (!fileChanged) return;
|
||||||
vga_text = (uint16_t*)0xb8000;
|
vga_text = (uint16_t*)0xb8000;
|
||||||
vga_text += printStr((char*)path, vga_text);
|
{
|
||||||
|
char pathBuff[23];
|
||||||
|
trimPath((char*)path, pathBuff, sizeof(pathBuff));
|
||||||
|
vga_text += printStr(pathBuff, vga_text);
|
||||||
vga_text += printChar(fileChanged ? '*' : ' ', vga_text);
|
vga_text += printChar(fileChanged ? '*' : ' ', vga_text);
|
||||||
|
}
|
||||||
vga_text += printChar(' ', vga_text);
|
vga_text += printChar(' ', vga_text);
|
||||||
vga_text += printStr("Save changes to file? (Y/N)", vga_text);
|
vga_text += printStr("Save changes to file? (Y/N)", vga_text);
|
||||||
for (;vga_text < &((uint16_t*)0xb8000)[80];vga_text++)
|
for (;vga_text < &((uint16_t*)0xb8000)[80];vga_text++)
|
||||||
@ -417,23 +429,21 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
|
|||||||
for(;(key & 0xff) != KEY_N && (key & 0xff) != KEY_Y;key = get_scancode());
|
for(;(key & 0xff) != KEY_N && (key & 0xff) != KEY_Y;key = get_scancode());
|
||||||
if ((key & 0xff) != KEY_Y) return;
|
if ((key & 0xff) != KEY_Y) return;
|
||||||
// Write changes
|
// Write changes
|
||||||
for (int i = 0; i < TOTALBLOCKS && (i << BLOCKSHIFT) < fi.filelen; i++) {
|
for (int i = 0; i < TOTALBLOCKS && (i << BLOCKSHIFT) < filelen; i++) {
|
||||||
// No change in current block
|
// No change in current block
|
||||||
uint16_t blockIdx = writtenMap[i];
|
uint16_t blockIdx = writtenMap[i];
|
||||||
uint32_t blockLen = blockLenMap[i];
|
uint32_t blockLen = blockLenMap[i];
|
||||||
if (!blockIdx) continue;
|
if (!blockIdx) continue;
|
||||||
// Write block to file
|
// Write block to file
|
||||||
uint32_t successcount;
|
|
||||||
uint32_t blockOff = i << BLOCKSHIFT;
|
uint32_t blockOff = i << BLOCKSHIFT;
|
||||||
DFS_Seek(&fi, blockOff, scratch);
|
if (file_seek(&file, blockOff)) {
|
||||||
if (fi.pointer != blockOff) {
|
|
||||||
vga_text = (uint16_t*)0xb8000;
|
vga_text = (uint16_t*)0xb8000;
|
||||||
vga_text += printStr("Seek Error ", vga_text);
|
vga_text += printStr("Seek Error ", vga_text);
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t err = DFS_WriteFile(&fi, scratch, writeStore[blockIdx], &successcount, blockLen);
|
uint32_t successcount = file_write(&file, writeStore[blockIdx], blockLen);
|
||||||
if (successcount < blockLen || err) {
|
if (successcount < blockLen) {
|
||||||
vga_text = (uint16_t*)0xb8000;
|
vga_text = (uint16_t*)0xb8000;
|
||||||
vga_text += printStr("Write Error ", vga_text);
|
vga_text += printStr("Write Error ", vga_text);
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
|
7
include/disk.h
Normal file
7
include/disk.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void InitDisk();
|
||||||
|
|
||||||
|
uint32_t Disk_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count);
|
||||||
|
uint32_t Disk_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count);
|
36
include/file.h
Normal file
36
include/file.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "file_s.h"
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error. Fills provided struct FILE
|
||||||
|
int file_open(FILE *file, char *path, char mode);
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error.
|
||||||
|
int file_seek(FILE *file, uint32_t offset);
|
||||||
|
|
||||||
|
// Returns 0 on error, bytes read on success.
|
||||||
|
int file_read(FILE *file, uint8_t *dest, uint32_t len);
|
||||||
|
|
||||||
|
// Returns 0 on error, bytes written on success.
|
||||||
|
int file_write(FILE *file, uint8_t *src, uint32_t len);
|
||||||
|
|
||||||
|
void file_close(FILE *file);
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error. Fills provided struct DIR
|
||||||
|
int dir_open(DIR *dir, char *path);
|
||||||
|
|
||||||
|
// Return 0 on success, non-zero error code on error. Fills provided struct dirent.
|
||||||
|
int dir_nextentry(DIR *dir, dirent *ent);
|
||||||
|
|
||||||
|
void dir_close(DIR *dir);
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error. Fills provided struct dirent.
|
||||||
|
int path_getinfo(char *path, dirent *ent);
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error.
|
||||||
|
int path_mkdir(char *path);
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error.
|
||||||
|
int path_rmdir(char *path);
|
||||||
|
|
||||||
|
// Returns 0 on success, non-zero error code on error.
|
||||||
|
int path_rmfile(char *path);
|
31
include/file_s.h
Normal file
31
include/file_s.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct FILE {
|
||||||
|
uint8_t filesystem_id;
|
||||||
|
uint8_t bytes[0x3F];
|
||||||
|
} __attribute__((__packed__)) FILE;
|
||||||
|
|
||||||
|
typedef struct DIR {
|
||||||
|
uint8_t filesystem_id;
|
||||||
|
uint8_t bytes[0x3F];
|
||||||
|
} __attribute__((__packed__)) DIR;
|
||||||
|
|
||||||
|
typedef enum filetype {
|
||||||
|
FT_UNKNOWN,
|
||||||
|
FT_REG,
|
||||||
|
FT_DIR
|
||||||
|
} filetype;
|
||||||
|
|
||||||
|
typedef struct dirent {
|
||||||
|
filetype type;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t last_modified;
|
||||||
|
uint32_t last_accessed;
|
||||||
|
uint32_t created;
|
||||||
|
uint8_t namelen;
|
||||||
|
char name[255];
|
||||||
|
} dirent;
|
||||||
|
|
||||||
|
#define OPENREAD 1
|
||||||
|
#define OPENWRITE 2
|
32
include/fs.h
Normal file
32
include/fs.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "file_s.h"
|
||||||
|
|
||||||
|
typedef struct filesystem {
|
||||||
|
uint32_t resv0;
|
||||||
|
uint32_t type;
|
||||||
|
struct fs_operations {
|
||||||
|
int (*file_open)(uint8_t *, FILE *, char *, char);
|
||||||
|
int (*file_seek)(uint8_t *, FILE *, uint32_t);
|
||||||
|
int (*file_read)(uint8_t *, FILE *, uint8_t *, uint32_t);
|
||||||
|
int (*file_write)(uint8_t *, FILE *, uint8_t *, uint32_t);
|
||||||
|
void (*file_close)(uint8_t *, FILE *);
|
||||||
|
int (*dir_open)(uint8_t *, DIR *, char *);
|
||||||
|
int (*dir_nextentry)(uint8_t *, DIR *, dirent *);
|
||||||
|
void (*dir_close)(uint8_t *, DIR *);
|
||||||
|
int (*path_getinfo)(uint8_t *, char *, dirent *);
|
||||||
|
int (*path_mkdir)(uint8_t *, char *);
|
||||||
|
int (*path_rmdir)(uint8_t *, char *);
|
||||||
|
int (*path_rmfile)(uint8_t *, char *);
|
||||||
|
void (*endfs)(uint8_t *);
|
||||||
|
} ops;
|
||||||
|
uint8_t labellen;
|
||||||
|
char label[255];
|
||||||
|
uint8_t fs_data[2048-4-4-44-256];
|
||||||
|
} __attribute__((packed)) filesystem;
|
||||||
|
|
||||||
|
filesystem *GetFilesystem(uint8_t idx);
|
||||||
|
filesystem *GetActiveFilesystem();
|
||||||
|
uint8_t GetActiveFilesystemId();
|
||||||
|
filesystem *SetActiveFilesystem(uint8_t idx);
|
||||||
|
void ActiveFilesystemBitmap(char *bitmap);
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "v86defs.h"
|
#include "v86defs.h"
|
||||||
#include "dosfs/dosfs.h"
|
#include "file.h"
|
||||||
|
|
||||||
void V8086Int(uint8_t interrupt, union V86Regs_t *regs);
|
void V8086Int(uint8_t interrupt, union V86Regs_t *regs);
|
||||||
|
|
||||||
@ -12,8 +12,6 @@ void SetVideo50Lines();
|
|||||||
void SetCursorDisabled();
|
void SetCursorDisabled();
|
||||||
|
|
||||||
uint16_t *nextLine(uint16_t *p, uint16_t *b);
|
uint16_t *nextLine(uint16_t *p, uint16_t *b);
|
||||||
|
void trimPath(char *path, char *buff, uint32_t maxLen);
|
||||||
|
|
||||||
uint32_t OpenVol(VOLINFO *vi);
|
void GetFileList(DIR *dir, dirent *entries, int32_t *entCount, int32_t maxEntries);
|
||||||
uint32_t OpenDir(uint8_t *path, VOLINFO *vi, DIRINFO *di);
|
|
||||||
void File83ToPath(char *src, char *path);
|
|
||||||
void GetFileList(DIRENT *entries, int32_t *entCount, VOLINFO *vi, DIRINFO *di);
|
|
@ -8,6 +8,6 @@ struct interrupt_frame {
|
|||||||
uint32_t es, ds, fs, gs;
|
uint32_t es, ds, fs, gs;
|
||||||
};
|
};
|
||||||
__attribute__ ((interrupt))
|
__attribute__ ((interrupt))
|
||||||
void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code);
|
void gpf_handler_v86(struct interrupt_frame volatile *frame, unsigned long error_code);
|
||||||
|
|
||||||
void setup_interrupts();
|
void setup_interrupts();
|
@ -5,6 +5,9 @@
|
|||||||
__attribute((__no_caller_saved_registers__))
|
__attribute((__no_caller_saved_registers__))
|
||||||
void kbd_wait();
|
void kbd_wait();
|
||||||
|
|
||||||
|
__attribute((__no_caller_saved_registers__))
|
||||||
|
void kbd_clear();
|
||||||
|
|
||||||
__attribute((__no_caller_saved_registers__))
|
__attribute((__no_caller_saved_registers__))
|
||||||
uint8_t get_key();
|
uint8_t get_key();
|
||||||
|
|
||||||
@ -12,7 +15,7 @@ __attribute((__no_caller_saved_registers__))
|
|||||||
uint16_t get_scancode();
|
uint16_t get_scancode();
|
||||||
|
|
||||||
__attribute__ ((interrupt))
|
__attribute__ ((interrupt))
|
||||||
void keyboardHandler(struct interrupt_frame *frame);
|
void keyboardHandler(struct interrupt_frame volatile *frame);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
KEY_ESCAPE=0x01, KEY_1=0x02, KEY_2=0x03,
|
KEY_ESCAPE=0x01, KEY_1=0x02, KEY_2=0x03,
|
12
include/progs.h
Normal file
12
include/progs.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "print.h"
|
||||||
|
#include "kbd.h"
|
||||||
|
#include "v86defs.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
void HexEditor(char *path);
|
||||||
|
void TextViewTest(char *path);
|
||||||
|
void ProgramLoadTest(char *path);
|
@ -1,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "dosfs/dosfs.h"
|
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "v86defs.h"
|
#include "v86defs.h"
|
@ -14,6 +14,7 @@ extern void v86DiskReadCHS();
|
|||||||
|
|
||||||
union __attribute((__packed__)) V86Regs_t {
|
union __attribute((__packed__)) V86Regs_t {
|
||||||
struct dword_regs {
|
struct dword_regs {
|
||||||
|
uint32_t ebp;
|
||||||
uint32_t edi;
|
uint32_t edi;
|
||||||
uint32_t esi;
|
uint32_t esi;
|
||||||
uint32_t ebx;
|
uint32_t ebx;
|
||||||
@ -22,6 +23,7 @@ union __attribute((__packed__)) V86Regs_t {
|
|||||||
uint32_t eax;
|
uint32_t eax;
|
||||||
} d;
|
} d;
|
||||||
struct word_regs {
|
struct word_regs {
|
||||||
|
uint16_t bp, _upper_bp;
|
||||||
uint16_t di, _upper_di;
|
uint16_t di, _upper_di;
|
||||||
uint16_t si, _upper_si;
|
uint16_t si, _upper_si;
|
||||||
uint16_t bx, _upper_bx;
|
uint16_t bx, _upper_bx;
|
||||||
@ -30,8 +32,9 @@ union __attribute((__packed__)) V86Regs_t {
|
|||||||
uint16_t ax, _upper_ax;
|
uint16_t ax, _upper_ax;
|
||||||
} w;
|
} w;
|
||||||
struct byte_regs {
|
struct byte_regs {
|
||||||
uint16_t di, _upper_di;
|
uint32_t ebp;
|
||||||
uint16_t si, _upper_si;
|
uint32_t edi;
|
||||||
|
uint32_t esi;
|
||||||
uint8_t bl, bh;
|
uint8_t bl, bh;
|
||||||
uint16_t _upper_bx;
|
uint16_t _upper_bx;
|
||||||
uint8_t dl, dh;
|
uint8_t dl, dh;
|
24
interrupt.c
24
interrupt.c
@ -90,19 +90,22 @@ void IRQ_clear_mask(char IRQline) {
|
|||||||
outb(port, value);
|
outb(port, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mostly from https://web.archive.org/web/20090719085533/http://osdev.berlios.de/v86.html
|
||||||
char v86_if = 0;
|
char v86_if = 0;
|
||||||
extern uint16_t error_screen[80*50]; // defined in kernel.c
|
extern uint16_t error_screen[80*50]; // defined in kernel.c
|
||||||
extern uint16_t *ivt;
|
extern uint16_t IVT[];
|
||||||
extern void real_test();
|
extern void real_test();
|
||||||
extern void jmp_usermode_test();
|
extern void jmp_usermode_test();
|
||||||
__attribute((__no_caller_saved_registers__))
|
__attribute__((__no_caller_saved_registers__))
|
||||||
|
__attribute__((__noreturn__))
|
||||||
extern void return_prev_task();
|
extern void return_prev_task();
|
||||||
__attribute((__no_caller_saved_registers__))
|
__attribute__((__no_caller_saved_registers__))
|
||||||
|
__attribute__((__noreturn__))
|
||||||
extern void error_environment(); // defined in kernel.c
|
extern void error_environment(); // defined in kernel.c
|
||||||
extern uint32_t _gpf_eax_save;
|
extern uint32_t _gpf_eax_save;
|
||||||
#define VALID_FLAGS 0xDFF
|
#define VALID_FLAGS 0xDFF
|
||||||
__attribute__ ((interrupt))
|
__attribute__ ((interrupt))
|
||||||
void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code) {
|
void gpf_handler_v86(struct interrupt_frame volatile *frame, unsigned long error_code) {
|
||||||
//asm volatile("mov %%ax,%%ds"::"a"(0x10));
|
//asm volatile("mov %%ax,%%ds"::"a"(0x10));
|
||||||
uint8_t *ip;
|
uint8_t *ip;
|
||||||
uint16_t *stack;
|
uint16_t *stack;
|
||||||
@ -209,8 +212,9 @@ void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code) {
|
|||||||
else
|
else
|
||||||
stack[2] &= ~EFLAG_IF;
|
stack[2] &= ~EFLAG_IF;
|
||||||
|
|
||||||
frame->cs = ivt[ip[1] * 2 + 1];
|
asm volatile("xchg %bx,%bx");
|
||||||
frame->eip = ivt[ip[1] * 2];
|
frame->cs = IVT[ip[1] * 2 + 1];
|
||||||
|
frame->eip = IVT[ip[1] * 2];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
@ -333,3 +337,11 @@ void setup_interrupts() {
|
|||||||
asm volatile("sti");
|
asm volatile("sti");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((__noreturn__))
|
||||||
|
void triple_fault() {
|
||||||
|
IDTR.size = 0;
|
||||||
|
asm volatile("lidt %0": : "m"(IDTR));
|
||||||
|
asm volatile("sti");
|
||||||
|
asm volatile("int $1");
|
||||||
|
for(;;);
|
||||||
|
}
|
||||||
|
18
kbd.c
18
kbd.c
@ -31,11 +31,13 @@ uint8_t scancodesToAsciiShift[0x3B] =
|
|||||||
"\0" // 0x38
|
"\0" // 0x38
|
||||||
" " // 0x39
|
" " // 0x39
|
||||||
"\0"; // 0x3A
|
"\0"; // 0x3A
|
||||||
uint8_t _KBDWAIT;
|
volatile uint8_t _KBDWAIT;
|
||||||
uint8_t _KEYCAPS = 0, _KEYSHIFT = 0;
|
volatile uint8_t _KEYCAPS = 0;
|
||||||
uint8_t _LSTKEY_ASCII = 0, _LSTKEY_SCAN = 0;
|
volatile uint8_t _KEYSHIFT = 0;
|
||||||
|
volatile uint8_t _LSTKEY_ASCII = 0;
|
||||||
|
volatile uint8_t _LSTKEY_SCAN = 0;
|
||||||
__attribute__ ((interrupt))
|
__attribute__ ((interrupt))
|
||||||
void keyboardHandler(struct interrupt_frame *frame) {
|
void keyboardHandler(struct interrupt_frame volatile *frame) {
|
||||||
uint16_t old_ds;
|
uint16_t old_ds;
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"mov %%ds, %%bx\n"
|
"mov %%ds, %%bx\n"
|
||||||
@ -43,6 +45,7 @@ void keyboardHandler(struct interrupt_frame *frame) {
|
|||||||
"mov %%ax, %%ds\n"
|
"mov %%ax, %%ds\n"
|
||||||
:"=b"(old_ds)::"%ax"
|
:"=b"(old_ds)::"%ax"
|
||||||
);
|
);
|
||||||
|
asm volatile("xchg %bx,%bx");
|
||||||
uint8_t key;
|
uint8_t key;
|
||||||
asm volatile("inb $0x60, %%al":"=a"(key));
|
asm volatile("inb $0x60, %%al":"=a"(key));
|
||||||
if (key == 0x3A) { // caps lock press
|
if (key == 0x3A) { // caps lock press
|
||||||
@ -71,6 +74,13 @@ void keyboardHandler(struct interrupt_frame *frame) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute((__no_caller_saved_registers__))
|
||||||
|
void kbd_clear() {
|
||||||
|
_KBDWAIT = 0;
|
||||||
|
_LSTKEY_ASCII = 0;
|
||||||
|
_LSTKEY_SCAN = 0;
|
||||||
|
}
|
||||||
|
|
||||||
__attribute((__no_caller_saved_registers__))
|
__attribute((__no_caller_saved_registers__))
|
||||||
void kbd_wait() {
|
void kbd_wait() {
|
||||||
_KBDWAIT = 0;
|
_KBDWAIT = 0;
|
||||||
|
303
kernel.c
303
kernel.c
@ -1,6 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "dosfs/dosfs.h"
|
#include "file.h"
|
||||||
|
#include "fs.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "kbd.h"
|
#include "kbd.h"
|
||||||
@ -10,6 +11,7 @@
|
|||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "progs.h"
|
#include "progs.h"
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
|
#include "disk.h"
|
||||||
|
|
||||||
typedef unsigned short word;
|
typedef unsigned short word;
|
||||||
|
|
||||||
@ -63,15 +65,6 @@ uint32_t get_cr4() {
|
|||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern char _loadusercode, _usercode, _eusercode;
|
|
||||||
void LoadUser() {
|
|
||||||
// Put Usermode code in proper place based on linker
|
|
||||||
char *s = &_loadusercode;
|
|
||||||
char *d = &_usercode;
|
|
||||||
while (d < &_eusercode)
|
|
||||||
*d++ = *s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern char _edata, _v86code, _ev86code, _bstart, _bend;
|
extern char _edata, _v86code, _ev86code, _bstart, _bend;
|
||||||
void setup_binary() {
|
void setup_binary() {
|
||||||
// Put V86 code in proper place based on linker
|
// Put V86 code in proper place based on linker
|
||||||
@ -80,26 +73,11 @@ void setup_binary() {
|
|||||||
while (d < &_ev86code)
|
while (d < &_ev86code)
|
||||||
*d++ = *s++;
|
*d++ = *s++;
|
||||||
|
|
||||||
LoadUser();
|
|
||||||
|
|
||||||
// Clear BSS area
|
// Clear BSS area
|
||||||
for (d = &_bstart; d < &_bend; d++)
|
for (d = &_bstart; d < &_bend; d++)
|
||||||
*d = 0;
|
*d = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern char _bprogstart, _bprogend;
|
|
||||||
// NOTE This is linked at the same place
|
|
||||||
// as the load address of usermode code,
|
|
||||||
// so things linked with bss here *must not*
|
|
||||||
// call usermode code at the same place
|
|
||||||
void ClearProgBss() {
|
|
||||||
// TODO Make sure there's no weird alignment stuff,
|
|
||||||
// although more BSS should always come after this
|
|
||||||
// ideally.
|
|
||||||
for (uint32_t *d = (uint32_t*)&_bprogstart; d < (uint32_t*)&_bprogend; d++)
|
|
||||||
*d = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t error_screen[80*50]; // 50-line VGA screen of error content
|
uint16_t error_screen[80*50]; // 50-line VGA screen of error content
|
||||||
|
|
||||||
extern uint16_t *ivt;
|
extern uint16_t *ivt;
|
||||||
@ -124,9 +102,19 @@ void ensure_v86env() {
|
|||||||
*d++ = *s++;
|
*d++ = *s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute((__no_caller_saved_registers__))
|
uint32_t _ERRORCODE = 0;
|
||||||
|
__attribute__((__no_caller_saved_registers__))
|
||||||
|
uint32_t check_error_code() {
|
||||||
|
uint32_t v = _ERRORCODE;
|
||||||
|
_ERRORCODE = 0;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((__no_caller_saved_registers__))
|
||||||
|
__attribute__((__noreturn__))
|
||||||
extern void return_prev_task();
|
extern void return_prev_task();
|
||||||
__attribute((__no_caller_saved_registers__))
|
__attribute__((__no_caller_saved_registers__))
|
||||||
|
__attribute__((__noreturn__))
|
||||||
void error_environment(uint32_t stack0, uint32_t stack1, uint32_t stack2, uint32_t stack3, uint32_t stack4, uint32_t stack5) {
|
void error_environment(uint32_t stack0, uint32_t stack1, uint32_t stack2, uint32_t stack3, uint32_t stack4, uint32_t stack5) {
|
||||||
ensure_v86env();
|
ensure_v86env();
|
||||||
setup_interrupts(); // just in case
|
setup_interrupts(); // just in case
|
||||||
@ -158,21 +146,24 @@ void error_environment(uint32_t stack0, uint32_t stack1, uint32_t stack2, uint32
|
|||||||
for(;;) {
|
for(;;) {
|
||||||
uint8_t key = get_scancode() & 0xff;
|
uint8_t key = get_scancode() & 0xff;
|
||||||
if (key == KEY_E) {
|
if (key == KEY_E) {
|
||||||
|
*(uint8_t*)0x800000 = 0x00;
|
||||||
v86_entry = i386LinearToFp(v86TransFlag);
|
v86_entry = i386LinearToFp(v86TransFlag);
|
||||||
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s);
|
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s);
|
||||||
|
if (*(uint8_t*)0x800000 == 0x88) *(uint32_t*)0xa0000 = 0x01010101;
|
||||||
}
|
}
|
||||||
if (key == KEY_R) break;
|
if (key == KEY_R) break;
|
||||||
}
|
}
|
||||||
// reset error screen
|
// reset error screen
|
||||||
for (int i = 0; i < (80*50)/2; i++)
|
for (int i = 0; i < (80*50)/2; i++)
|
||||||
((uint32_t*)error_screen)[i] = 0x0f000f00;
|
((uint32_t*)error_screen)[i] = 0x0f000f00;
|
||||||
|
_ERRORCODE = -1;
|
||||||
return_prev_task();
|
return_prev_task();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GetFreeStack() {
|
uint32_t GetFreeStack() {
|
||||||
uint32_t stack;
|
uint32_t stack;
|
||||||
asm volatile("mov %%esp,%%eax":"=a"(stack));
|
asm volatile("mov %%esp,%%eax":"=a"(stack));
|
||||||
stack = ((stack - 0x4000) / 0x1000) * 0x1000;
|
stack = ((stack - 0x2000) / 0x1000) * 0x1000;
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,10 +174,11 @@ Real Mode Accessible (First MB)
|
|||||||
01000 - 04000 Free (12kB)
|
01000 - 04000 Free (12kB)
|
||||||
04000 - 07C00 V86 Code (15kB)
|
04000 - 07C00 V86 Code (15kB)
|
||||||
07C00 - 08000 Boot & V86 Code (512B)
|
07C00 - 08000 Boot & V86 Code (512B)
|
||||||
08000 - 20000 V86 Code (96kB)
|
08000 - 20000 Free (96kB)
|
||||||
20000 - 30000 Disk Buffer (64kB)
|
20000 - 30000 Disk Buffer (64kB)
|
||||||
30000 - 80000 Free (320kB)
|
30000 - 40000 V86 Data (64kB)
|
||||||
80000 - 90000 Real Mode Stack (64kB)
|
40000 - 80000 Free (256kB)
|
||||||
|
80000 - 90000 V86 Stack (64kB)
|
||||||
90000 - A0000 Free (64kB)
|
90000 - A0000 Free (64kB)
|
||||||
A0000 - C0000 VGA (128kB)
|
A0000 - C0000 VGA (128kB)
|
||||||
C0000 - FFFFF BIOS Area (256kB)
|
C0000 - FFFFF BIOS Area (256kB)
|
||||||
@ -194,7 +186,9 @@ Protected Only (1MB+)
|
|||||||
100000 - 200000 Kernel Code (1mB)
|
100000 - 200000 Kernel Code (1mB)
|
||||||
200000 - 200080 TSS (128B)
|
200000 - 200080 TSS (128B)
|
||||||
200080 - 202080 TSS IOMAP (8kB)
|
200080 - 202080 TSS IOMAP (8kB)
|
||||||
202080 - 300000 Free (~1/2mB)
|
202080 - 208000 Free (~24kB)
|
||||||
|
208000 - 240000 Kernel File Stack (224kB)
|
||||||
|
240000 - 280000 Active Filesystems (128kB)
|
||||||
280000 - 300000 Disk Cache (512kB)
|
280000 - 300000 Disk Cache (512kB)
|
||||||
300000 - 310000 Task Stack (64kB)
|
300000 - 310000 Task Stack (64kB)
|
||||||
310000 - 320000 Interrupt Stack (64kB)
|
310000 - 320000 Interrupt Stack (64kB)
|
||||||
@ -202,6 +196,7 @@ Protected Only (1MB+)
|
|||||||
400000 - 700000 Usermode Code (3mB)
|
400000 - 700000 Usermode Code (3mB)
|
||||||
700000 - 800000 Usermode Stack (1mB)
|
700000 - 800000 Usermode Stack (1mB)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void DrawScreen(uint16_t *vga) {
|
void DrawScreen(uint16_t *vga) {
|
||||||
uint16_t *vga_text = vga;
|
uint16_t *vga_text = vga;
|
||||||
// clear screen
|
// clear screen
|
||||||
@ -253,28 +248,29 @@ void RestoreVGA() {
|
|||||||
SetPalette();
|
SetPalette();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fileCount;
|
int32_t fileCount, fileOffset;
|
||||||
DIRENT *entries = (DIRENT*)0x400000;
|
// We store dir entries in usermode space,
|
||||||
|
// which is nice because there's nothing after,
|
||||||
|
// but it does mean we need to reload the dir
|
||||||
|
// after every task called. This might be fine,
|
||||||
|
// since the task might have modified the directory.
|
||||||
|
extern char _USERMODE;
|
||||||
|
dirent *const DirEntries = (dirent*)&_USERMODE;
|
||||||
|
#define MAXDISPFILES 16
|
||||||
void PrintFileList(uint16_t *vga) {
|
void PrintFileList(uint16_t *vga) {
|
||||||
uint16_t *vga_text = &((uint16_t *)vga)[80*6+3];
|
uint16_t *vga_text = &((uint16_t *)vga)[80*6+3];
|
||||||
for (int i = 0; i < fileCount; i++) {
|
for (int i = 0; (i + fileOffset) < fileCount && i < MAXDISPFILES; i++) {
|
||||||
DIRENT *de = &entries[i];
|
dirent *de = &DirEntries[i + fileOffset];
|
||||||
for (int i = 0; i < 11 && de->name[i]; i++) {
|
de->name[de->namelen < 20 ? de->namelen : 20] = 0;
|
||||||
if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3
|
vga_text += printStr(de->name, vga_text);
|
||||||
*(uint8_t *)vga_text = de->name[i];
|
|
||||||
vga_text++;
|
|
||||||
}
|
|
||||||
vga_text += printStr(" ", vga_text);
|
vga_text += printStr(" ", vga_text);
|
||||||
vga_text += printDec((uint32_t)de->filesize_0 +
|
vga_text += printDec(de->size, vga_text);
|
||||||
((uint32_t)de->filesize_1 << 8) +
|
|
||||||
((uint32_t)de->filesize_2 << 16) +
|
|
||||||
((uint32_t)de->filesize_3 << 24), vga_text);
|
|
||||||
*(uint8_t*)vga_text++ = 'B';
|
*(uint8_t*)vga_text++ = 'B';
|
||||||
vga_text = nextLine(vga_text, vga) + 3;
|
vga_text = nextLine(vga_text, vga) + 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char IsDir(DIRENT *de) {
|
char IsDir(dirent *de) {
|
||||||
return de->attr & ATTR_DIRECTORY;
|
return de->type == FT_DIR;
|
||||||
}
|
}
|
||||||
void ScancodeTest() {
|
void ScancodeTest() {
|
||||||
uint16_t *vga = (uint16_t*)0xb8000;
|
uint16_t *vga = (uint16_t*)0xb8000;
|
||||||
@ -288,16 +284,21 @@ void ScancodeTest() {
|
|||||||
}
|
}
|
||||||
extern void create_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
|
extern void create_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
|
||||||
uint16_t FileSelectScreen[80*25];
|
uint16_t FileSelectScreen[80*25];
|
||||||
|
char ValidFilesystems[256];
|
||||||
void FileSelect() {
|
void FileSelect() {
|
||||||
uint8_t current_path[80];
|
ActiveFilesystemBitmap(ValidFilesystems);
|
||||||
|
uint8_t currentFsId = 0;
|
||||||
|
char current_path[80];
|
||||||
uintptr_t current_path_end;
|
uintptr_t current_path_end;
|
||||||
for (int i = 0; i < sizeof(current_path); i++)
|
for (int i = 0; i < sizeof(current_path); i++)
|
||||||
current_path[i] = 0;
|
current_path[i] = 0;
|
||||||
current_path[0] = '/';
|
current_path[0] = '0';
|
||||||
current_path_end = 1;
|
current_path[1] = '/';
|
||||||
|
current_path_end = 2;
|
||||||
fileCount = 5;
|
fileCount = 5;
|
||||||
uint16_t *vga_text = (uint16_t *)FileSelectScreen;
|
uint16_t *vga_text = (uint16_t *)FileSelectScreen;
|
||||||
int32_t fileHovered = 0, lastFileHovered = 0;
|
int32_t fileHovered = 0;
|
||||||
|
fileOffset = 0;
|
||||||
for (char reload = 1;;) {
|
for (char reload = 1;;) {
|
||||||
DrawScreen(vga_text);
|
DrawScreen(vga_text);
|
||||||
// Info line (4)
|
// Info line (4)
|
||||||
@ -311,25 +312,33 @@ void FileSelect() {
|
|||||||
vga += 80;
|
vga += 80;
|
||||||
printStr("O to open directory", vga);
|
printStr("O to open directory", vga);
|
||||||
vga += 80;
|
vga += 80;
|
||||||
|
printStr("S to switch volume", vga);
|
||||||
|
vga += 80;
|
||||||
printStr("F4 to run tests", vga);
|
printStr("F4 to run tests", vga);
|
||||||
}
|
}
|
||||||
printStr((char*)current_path, &vga_text[80*4 + 2]);
|
printStr(current_path, &vga_text[80*4 + 2]);
|
||||||
for (int i = 2; i < 15; i++)
|
for (int i = 2; i < 15; i++)
|
||||||
*(uint8_t*)&vga_text[80*5 + i] = '-';
|
*(uint8_t*)&vga_text[80*5 + i] = '-';
|
||||||
VOLINFO vi; DIRINFO di;
|
DIR dir;
|
||||||
if (reload) {
|
if (reload) {
|
||||||
OpenVol(&vi);
|
|
||||||
current_path[current_path_end] = 0;
|
current_path[current_path_end] = 0;
|
||||||
OpenDir(current_path, &vi, &di);
|
dir_open(&dir, current_path);
|
||||||
GetFileList(entries, &fileCount, &vi, &di);
|
GetFileList(&dir, DirEntries, &fileCount, INT32_MAX);
|
||||||
reload = 0;
|
reload = 0;
|
||||||
}
|
}
|
||||||
PrintFileList(vga_text);
|
if (fileHovered >= fileCount) {
|
||||||
if (lastFileHovered != fileHovered) {
|
fileOffset = fileCount - MAXDISPFILES;
|
||||||
*(uint8_t*)&vga_text[80*(6+lastFileHovered)+2] = ' ';
|
fileHovered = fileCount - 1;
|
||||||
lastFileHovered = fileHovered;
|
|
||||||
}
|
}
|
||||||
*(uint8_t*)&vga_text[80*(6+fileHovered)+2] = '>';
|
if ((fileHovered - fileOffset) >= MAXDISPFILES)
|
||||||
|
fileOffset = fileHovered - MAXDISPFILES + 1;
|
||||||
|
else if ((fileHovered - fileOffset) < 0)
|
||||||
|
fileOffset = fileHovered;
|
||||||
|
PrintFileList(vga_text);
|
||||||
|
for (int i = 6; i < 24; i++) {
|
||||||
|
*(uint8_t*)&vga_text[80*i+2] = ' ';
|
||||||
|
}
|
||||||
|
*(uint8_t*)&vga_text[80*(6+(fileHovered-fileOffset))+2] = '>';
|
||||||
// Copy to real VGA
|
// Copy to real VGA
|
||||||
for (int i = 0; i < 80*25; i++)
|
for (int i = 0; i < 80*25; i++)
|
||||||
((uint16_t*)0xb8000)[i] = vga_text[i];
|
((uint16_t*)0xb8000)[i] = vga_text[i];
|
||||||
@ -338,7 +347,7 @@ void FileSelect() {
|
|||||||
switch (key & 0xff) { // scancode component
|
switch (key & 0xff) { // scancode component
|
||||||
case KEY_DOWN: // down
|
case KEY_DOWN: // down
|
||||||
fileHovered++;
|
fileHovered++;
|
||||||
if (fileHovered >= fileCount) fileHovered = 0;
|
if (fileHovered >= fileCount) { fileHovered = 0; fileOffset = 0; }
|
||||||
break;
|
break;
|
||||||
case KEY_UP: // up
|
case KEY_UP: // up
|
||||||
fileHovered--;
|
fileHovered--;
|
||||||
@ -356,33 +365,46 @@ void FileSelect() {
|
|||||||
reload = 1;
|
reload = 1;
|
||||||
break;
|
break;
|
||||||
case KEY_P:
|
case KEY_P:
|
||||||
if (IsDir(&entries[fileHovered])) break;
|
if (IsDir(&DirEntries[fileHovered])) break;
|
||||||
File83ToPath((char*)entries[fileHovered].name, (char*)¤t_path[current_path_end]);
|
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
|
||||||
create_child(GetFreeStack(), (uintptr_t)ProgramLoadTest, 2, current_path, &vi);
|
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
|
||||||
|
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
|
||||||
|
create_child(GetFreeStack(), (uintptr_t)ProgramLoadTest, 1, current_path);
|
||||||
|
current_path[current_path_end] = 0;
|
||||||
RestoreVGA();
|
RestoreVGA();
|
||||||
reload = 1;
|
reload = 1;
|
||||||
break;
|
break;
|
||||||
case KEY_X:
|
case KEY_X:
|
||||||
if (IsDir(&entries[fileHovered])) break;
|
if (IsDir(&DirEntries[fileHovered])) break;
|
||||||
File83ToPath((char*)entries[fileHovered].name, (char*)¤t_path[current_path_end]);
|
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
|
||||||
ClearProgBss();
|
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
|
||||||
create_child(GetFreeStack(), (uintptr_t)HexEditor, 2, current_path, &vi);
|
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
|
||||||
|
create_child(GetFreeStack(), (uintptr_t)HexEditor, 1, current_path);
|
||||||
|
current_path[current_path_end] = 0;
|
||||||
RestoreVGA();
|
RestoreVGA();
|
||||||
reload = 1;
|
reload = 1;
|
||||||
break;
|
break;
|
||||||
case KEY_T:
|
case KEY_T:
|
||||||
if (IsDir(&entries[fileHovered])) break;
|
if (IsDir(&DirEntries[fileHovered])) break;
|
||||||
File83ToPath((char*)entries[fileHovered].name, (char*)¤t_path[current_path_end]);
|
|
||||||
//TextViewTest(path, &vi);
|
//TextViewTest(path, &vi);
|
||||||
create_child(GetFreeStack(), (uintptr_t)TextViewTest, 2, current_path, &vi);
|
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
|
||||||
|
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
|
||||||
|
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
|
||||||
|
create_child(GetFreeStack(), (uintptr_t)TextViewTest, 1, current_path);
|
||||||
|
current_path[current_path_end] = 0;
|
||||||
RestoreVGA();
|
RestoreVGA();
|
||||||
reload = 1;
|
reload = 1;
|
||||||
break;
|
break;
|
||||||
case KEY_O:
|
case KEY_O:
|
||||||
case 0x9C: // enter release
|
case 0x9C: // enter release
|
||||||
if (IsDir(&entries[fileHovered])) {
|
if (IsDir(&DirEntries[fileHovered])) {
|
||||||
uint8_t tmp_path[80];
|
uint8_t tmp_path[80];
|
||||||
File83ToPath((char*)entries[fileHovered].name, (char*)tmp_path);
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < DirEntries[fileHovered].namelen && i < sizeof(tmp_path)-1; i++)
|
||||||
|
tmp_path[i] = DirEntries[fileHovered].name[i];
|
||||||
|
tmp_path[i] = 0;
|
||||||
|
}
|
||||||
if ((*(uint32_t*)tmp_path & 0xffff) == ('.' | 0x0000)) {
|
if ((*(uint32_t*)tmp_path & 0xffff) == ('.' | 0x0000)) {
|
||||||
// Current dir, do nothing
|
// Current dir, do nothing
|
||||||
break;
|
break;
|
||||||
@ -392,6 +414,7 @@ void FileSelect() {
|
|||||||
current_path[current_path_end] = 0;
|
current_path[current_path_end] = 0;
|
||||||
reload = 1;
|
reload = 1;
|
||||||
fileHovered = 0;
|
fileHovered = 0;
|
||||||
|
fileOffset = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (int i = 0; (i + current_path_end) < sizeof(current_path); i++)
|
for (int i = 0; (i + current_path_end) < sizeof(current_path); i++)
|
||||||
@ -402,8 +425,28 @@ void FileSelect() {
|
|||||||
current_path[current_path_end] = 0;
|
current_path[current_path_end] = 0;
|
||||||
reload = 1;
|
reload = 1;
|
||||||
fileHovered = 0;
|
fileHovered = 0;
|
||||||
|
fileOffset = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KEY_S:
|
||||||
|
// Next filesystem TODO Support over 077 I'm so lazy right now
|
||||||
|
for (currentFsId = (currentFsId + 1) % 64; !ValidFilesystems[currentFsId]; currentFsId = (currentFsId + 1) % 64);
|
||||||
|
if (currentFsId < 8) {
|
||||||
|
current_path[0] = '0' + currentFsId;
|
||||||
|
current_path[1] = '/';
|
||||||
|
current_path[2] = 0;
|
||||||
|
current_path_end = 2;
|
||||||
|
} else {
|
||||||
|
current_path[0] = '0' + (currentFsId >> 3);
|
||||||
|
current_path[1] = '0' + (currentFsId & 7);
|
||||||
|
current_path[2] = '/';
|
||||||
|
current_path[3] = 0;
|
||||||
|
current_path_end = 3;
|
||||||
|
}
|
||||||
|
reload = 1;
|
||||||
|
fileHovered = 0;
|
||||||
|
fileOffset = 0;
|
||||||
|
break;
|
||||||
case KEY_F6:
|
case KEY_F6:
|
||||||
ScancodeTest();
|
ScancodeTest();
|
||||||
reload = 1;
|
reload = 1;
|
||||||
@ -414,17 +457,61 @@ void FileSelect() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MakeSystemVolume(uint8_t sysPartition);
|
||||||
|
void MakeMBRPartitions();
|
||||||
|
void SystemRun(uint8_t sysPartition) {
|
||||||
|
uint16_t *vga_text = (word *)0xb8000;
|
||||||
|
RestoreVGA();
|
||||||
|
DrawScreen((uint16_t*)0xb8000);
|
||||||
|
|
||||||
|
InitDisk();
|
||||||
|
|
||||||
|
// Check for FAT partition
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
create_child(GetFreeStack(), (uintptr_t)MakeSystemVolume, 1, sysPartition);
|
||||||
|
if (!check_error_code()) break;
|
||||||
|
vga_text = &((word*)0xb8000)[80*4 + 2];
|
||||||
|
vga_text += printStr("Error loading file select. Ensure the disk has a valid MBR and FAT partition.", vga_text);
|
||||||
|
vga_text = &((word*)0xb8000)[80*5 + 2];
|
||||||
|
vga_text += printStr("Press R to retry.", vga_text);
|
||||||
|
for (;(get_scancode() & 0xff) != KEY_R;);
|
||||||
|
}
|
||||||
|
create_child(GetFreeStack(), (uintptr_t)MakeMBRPartitions, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
create_child(GetFreeStack(), (uintptr_t)FileSelect, 0);
|
||||||
|
// should never return, so if it does,
|
||||||
|
// we have an error
|
||||||
|
{
|
||||||
|
union V86Regs_t regs;
|
||||||
|
FARPTR v86_entry = i386LinearToFp(v86TextMode);
|
||||||
|
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s);
|
||||||
|
}
|
||||||
|
RestoreVGA();
|
||||||
|
DrawScreen((uint16_t*)0xb8000);
|
||||||
|
vga_text = &((word*)0xb8000)[80*4 + 2];
|
||||||
|
vga_text += printStr("Error loading file select. Ensure the disk has a valid MBR and FAT partition.", vga_text);
|
||||||
|
vga_text = &((word*)0xb8000)[80*5 + 2];
|
||||||
|
vga_text += printStr("Press R to retry.", vga_text);
|
||||||
|
for (;(get_scancode() & 0xff) != KEY_R;);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((__noreturn__))
|
||||||
|
extern void triple_fault();
|
||||||
uint32_t kernel_check = 0x12345678;
|
uint32_t kernel_check = 0x12345678;
|
||||||
void start() {
|
void start() {
|
||||||
word *vga_text = (word *)0xb8000;
|
word *vga_text = (word *)0xb8000;
|
||||||
char h[] = "LuciaOS";
|
char h[] = "ROSE";
|
||||||
for (int i = 0; i < sizeof(h); i++)
|
for (int i = 0; i < sizeof(h); i++)
|
||||||
*(char *)&vga_text[i] = h[i];
|
*(char *)&vga_text[i] = h[i];
|
||||||
vga_text = &vga_text[80];
|
vga_text = &vga_text[80];
|
||||||
|
|
||||||
// DL *should* be preserved
|
// DL *should* be preserved
|
||||||
uint8_t dl;
|
uint16_t boot_dx;
|
||||||
asm volatile("nop":"=d"(dl));
|
asm volatile("nop":"=d"(boot_dx));
|
||||||
|
|
||||||
if (!check_cmov()) {
|
if (!check_cmov()) {
|
||||||
char cmov_err[] = "NO CMOV";
|
char cmov_err[] = "NO CMOV";
|
||||||
@ -433,7 +520,7 @@ void start() {
|
|||||||
for (;;) asm volatile("hlt");
|
for (;;) asm volatile("hlt");
|
||||||
}
|
}
|
||||||
|
|
||||||
vga_text += printByte(dl, vga_text);
|
vga_text += printWord(boot_dx, vga_text);
|
||||||
vga_text++;
|
vga_text++;
|
||||||
|
|
||||||
uint32_t o;
|
uint32_t o;
|
||||||
@ -460,46 +547,40 @@ void start() {
|
|||||||
//vga_text += printStr("Y ", vga_text);
|
//vga_text += printStr("Y ", vga_text);
|
||||||
//enable_sse();
|
//enable_sse();
|
||||||
|
|
||||||
setup_binary();
|
|
||||||
|
|
||||||
// edit
|
|
||||||
setup_interrupts();
|
|
||||||
setup_tss();
|
|
||||||
init_paging();
|
|
||||||
//print_flags();
|
//print_flags();
|
||||||
vga_text += printStr("CR0:", vga_text);
|
vga_text += printStr("CR0:", vga_text);
|
||||||
vga_text += printDword(get_cr0(), vga_text);
|
vga_text += printDword(get_cr0(), vga_text);
|
||||||
vga_text++;
|
vga_text++;
|
||||||
//print_cr3();
|
//print_cr3();
|
||||||
//print_cr4();
|
//print_cr4();
|
||||||
|
|
||||||
|
// Setup system
|
||||||
|
setup_binary();
|
||||||
|
vga_text += printStr("bin...", vga_text);
|
||||||
|
vga_text++;
|
||||||
|
setup_interrupts();
|
||||||
|
vga_text += printStr("int...", vga_text);
|
||||||
|
vga_text++;
|
||||||
|
setup_tss();
|
||||||
|
vga_text += printStr("tss...", vga_text);
|
||||||
|
vga_text++;
|
||||||
|
init_paging();
|
||||||
|
vga_text += printStr("page...", vga_text);
|
||||||
|
vga_text++;
|
||||||
backup_ivtbios();
|
backup_ivtbios();
|
||||||
|
vga_text += printStr("bkup...", vga_text);
|
||||||
|
vga_text++;
|
||||||
|
|
||||||
//vga_text = &((word *)0xb8000)[160];
|
// DL contained disk number, DH contained active partition
|
||||||
//vga_text += printStr("Press T for tests, or any key to continue... ", vga_text);
|
uint8_t SystemPartition = boot_dx >> 8;
|
||||||
//uint8_t key = get_key();
|
|
||||||
//if (key == 't' || key == 'T')
|
vga_text = &((uint16_t*)0xb8000)[160];
|
||||||
// create_child(GetFreeStack(), (uintptr_t)RunTests, 0);
|
vga_text += printStr("Starting Shell...", vga_text);
|
||||||
RestoreVGA();
|
create_child(GetFreeStack(), (uintptr_t)SystemRun, 1, SystemPartition);
|
||||||
DrawScreen((uint16_t*)0xb8000);
|
// If this returns, something is *very* wrong, reboot the system
|
||||||
uint32_t stack;
|
// TODO Maybe try to recover?
|
||||||
asm volatile("mov %%esp,%%eax":"=a"(stack));
|
|
||||||
stack = ((stack - 0x4000) / 0x1000) * 0x1000;
|
// Triple fault
|
||||||
for (;;) {
|
triple_fault();
|
||||||
create_child(stack, (uintptr_t)FileSelect, 0);
|
|
||||||
// should never return, so if it does,
|
|
||||||
// we have an error
|
|
||||||
{
|
|
||||||
union V86Regs_t regs;
|
|
||||||
FARPTR v86_entry = i386LinearToFp(v86TextMode);
|
|
||||||
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s);
|
|
||||||
}
|
|
||||||
RestoreVGA();
|
|
||||||
DrawScreen((uint16_t*)0xb8000);
|
|
||||||
vga_text = &((word*)0xb8000)[80*4 + 2];
|
|
||||||
vga_text += printStr("Error loading file select. Ensure the disk has a valid MBR and FAT partition.", vga_text);
|
|
||||||
vga_text = &((word*)0xb8000)[80*5 + 2];
|
|
||||||
vga_text += printStr("Press R to retry.", vga_text);
|
|
||||||
for (;(get_scancode() & 0xff) != KEY_R;);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
link.ld
47
link.ld
@ -2,13 +2,17 @@ OUTPUT_FORMAT(binary)
|
|||||||
ENTRY(entry)
|
ENTRY(entry)
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
|
IVT = 0x00000;
|
||||||
. = 0x100000;
|
. = 0x100000;
|
||||||
|
_USERMODE = 0x800000;
|
||||||
|
_USERMODE_END = 0x1000000;
|
||||||
|
|
||||||
.text : {
|
.text : {
|
||||||
*(.text);
|
*(.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.data : {
|
.data : {
|
||||||
|
*(.data*);
|
||||||
*(.data);
|
*(.data);
|
||||||
*(.rodata);
|
*(.rodata);
|
||||||
*(.rodata*);
|
*(.rodata*);
|
||||||
@ -16,27 +20,34 @@ SECTIONS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.realmode 0x4000 :
|
.realmode 0x4000 :
|
||||||
AT ( ADDR(.data) + SIZEOF(.data) )
|
AT ( _edata )
|
||||||
{ _v86code = .; *(.v86); _ev86code = .; }
|
{ _v86code = .; *(.v86); _ev86code = .; }
|
||||||
|
. = _edata + SIZEOF(.realmode);
|
||||||
. = ADDR(.data) + SIZEOF(.data) + SIZEOF(.realmode);
|
|
||||||
.thing : { _loadusercode = .; }
|
|
||||||
|
|
||||||
.usermode 0x400000 :
|
|
||||||
AT ( ADDR(.data) + SIZEOF(.data) + SIZEOF(.realmode) )
|
|
||||||
{ _usercode = .; *(.user); _eusercode = .; }
|
|
||||||
|
|
||||||
.bss 0x400000 : {
|
|
||||||
_bprogstart = .;
|
|
||||||
hexedit.o(.bss);
|
|
||||||
_bprogend = .;
|
|
||||||
hexedit.o(.bss.end);
|
|
||||||
}
|
|
||||||
|
|
||||||
. = ADDR(.data) + SIZEOF(.data) + SIZEOF(.realmode) + SIZEOF(.usermode);
|
|
||||||
|
|
||||||
.bss : ALIGN(0x1000)
|
.bss : ALIGN(0x1000)
|
||||||
{
|
{
|
||||||
_bstart = .; *(.bss); _bend = .;
|
_bstart = .; *(.bss); *(.bss*) _bend = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss _USERMODE (NOLOAD) : AT(_bend) {
|
||||||
|
_bhexstart = .;
|
||||||
|
*(.hexbss);
|
||||||
|
*(.hexbss*);
|
||||||
|
_bhexend = .;
|
||||||
|
*(.hexlatebss);
|
||||||
|
*(.hexlatebss*);
|
||||||
|
}
|
||||||
|
.bss _USERMODE (NOLOAD) : AT(_bend) {
|
||||||
|
_btextstart = .;
|
||||||
|
*(.textbss);
|
||||||
|
*(.textbss*);
|
||||||
|
_btextend = .;
|
||||||
|
*(.textlatebss);
|
||||||
|
*(.textlatebss*);
|
||||||
|
}
|
||||||
|
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.note*)
|
||||||
|
*(.comment*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
63
paging.c
63
paging.c
@ -1,8 +1,7 @@
|
|||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
|
|
||||||
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
||||||
uint32_t first_page_table[1024] __attribute__((aligned(4096))); // 0x00000000 - 0x00400000
|
uint32_t page_tables[4][1024] __attribute__((aligned(4096)));
|
||||||
uint32_t second_page_table[1024] __attribute__((aligned(4096))); // 0x00400000 - 0x00800000
|
|
||||||
|
|
||||||
void enable_paging() {
|
void enable_paging() {
|
||||||
asm(
|
asm(
|
||||||
@ -13,38 +12,52 @@ void enable_paging() {
|
|||||||
::"a"(page_directory));
|
::"a"(page_directory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Add a function which can dynamically add and remove pages,
|
||||||
|
// that keeps track internally of what's already used?
|
||||||
|
|
||||||
|
// NOTE This function cannot cross 4MB (1024 page) boundaries
|
||||||
|
void map_pages(uintptr_t page, uintptr_t num_pages, uintptr_t phy_address, char access_flags) {
|
||||||
|
uintptr_t access = access_flags & 0x7;
|
||||||
|
|
||||||
|
// Each page is 4K, Each page table is 4M
|
||||||
|
uintptr_t page_dir_entry = page >> 10;
|
||||||
|
if (page_dir_entry >= 4) return;
|
||||||
|
uintptr_t page_index = page & 0x3ff;
|
||||||
|
if (page_index + num_pages > 1024) return;
|
||||||
|
|
||||||
|
// Address must be 4K aligned
|
||||||
|
if (phy_address & 0x3ff) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < num_pages; i++)
|
||||||
|
page_tables[page_dir_entry][page_index + i] = phy_address + (i * 0x1000) | access_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User, R/W, Present
|
||||||
|
#define USERACCESS (4|2|1)
|
||||||
|
// Supervisor, R/W, Present
|
||||||
|
#define SUPERACCESS (2|1)
|
||||||
|
|
||||||
void init_paging() {
|
void init_paging() {
|
||||||
for (int i = 0; i < 1024; i++)
|
for (int i = 0; i < 1024; i++)
|
||||||
// Supervisor, R/W, Not Present
|
// Supervisor, R/W, Not Present
|
||||||
page_directory[i] = 2;
|
page_directory[i] = 2;
|
||||||
|
|
||||||
// First Page Table
|
// 1024 Pages = 1MB
|
||||||
// First MB: Real Mode
|
// First MB: Real Mode
|
||||||
{
|
// TODO Make some of this not accessible to usermode?
|
||||||
int i;
|
map_pages(0x00000000 >> 12, 256, 0x00000000, USERACCESS);
|
||||||
// Up to 0xC0000
|
|
||||||
// TODO make some areas here Read Only
|
|
||||||
for (i = 0;i < 16*0xC; i++)
|
|
||||||
// User, R/W, Present
|
|
||||||
first_page_table[i] = (i * 0x1000) |4|2|1;
|
|
||||||
// Remainder of first MB BIOS Area (writable?)
|
|
||||||
for (;i < 256; i++)
|
|
||||||
// User, R/W, Present
|
|
||||||
first_page_table[i] = (i * 0x1000) |4|2|1;
|
|
||||||
}
|
|
||||||
// Next 3MB: Kernel
|
// Next 3MB: Kernel
|
||||||
for (int i = 256; i < 1024; i++)
|
map_pages(0x00100000 >> 12, 768, 0x00100000, SUPERACCESS);
|
||||||
// Supervisor, R/W, Present
|
// Next 4MB: Kernel
|
||||||
first_page_table[i] = (i * 0x1000) |2|1;
|
map_pages(0x00400000 >> 12, 1024, 0x00400000, SUPERACCESS);
|
||||||
|
|
||||||
// Usermode Page Table
|
// Next 8MB: Usermode
|
||||||
for (int i = 0; i < 1024; i++)
|
map_pages(0x00800000 >> 12, 1024, 0x00800000, USERACCESS);
|
||||||
// User, R/W, Present
|
map_pages(0x00C00000 >> 12, 1024, 0x00C00000, USERACCESS);
|
||||||
second_page_table[i] = (i * 0x1000 + 0x400000) |4|2|1;
|
|
||||||
|
|
||||||
// User, R/W, Present
|
// We aren't using page directory permissions
|
||||||
page_directory[0] = ((uintptr_t)first_page_table)|4|2|1;
|
for (int i = 0; i < 4; i++)
|
||||||
page_directory[1] = ((uintptr_t)second_page_table)|4|2|1;
|
page_directory[i] = ((uintptr_t)&page_tables[i]) | USERACCESS;
|
||||||
|
|
||||||
enable_paging();
|
enable_paging();
|
||||||
}
|
}
|
||||||
|
221
progs.c
221
progs.c
@ -1,224 +1,41 @@
|
|||||||
#include "progs.h"
|
#include "progs.h"
|
||||||
#include "helper.h"
|
#include "file.h"
|
||||||
#include "kbd.h"
|
|
||||||
|
|
||||||
void TextViewTest(uint8_t *path, VOLINFO *vi) {
|
extern char _USERMODE, _USERMODE_END;
|
||||||
uint16_t *vga_text = (uint16_t *)0xb8000;
|
|
||||||
uint32_t fileLen;
|
|
||||||
uint8_t *diskReadBuf = (uint8_t *)0x500000;
|
|
||||||
{
|
|
||||||
uint32_t err;
|
|
||||||
uint8_t *scratch = (uint8_t *)0x20000;
|
|
||||||
FILEINFO fi;
|
|
||||||
err = DFS_OpenFile(vi, path, DFS_READ, scratch, &fi);
|
|
||||||
if (err) {
|
|
||||||
vga_text += printStr("Open Error: ", vga_text);
|
|
||||||
printDword(err, vga_text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// file too large
|
|
||||||
if (fi.filelen > 0x300000) {
|
|
||||||
vga_text += printStr("File too large.", vga_text);
|
|
||||||
kbd_wait();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DFS_Seek(&fi, 0, scratch);
|
|
||||||
if (fi.pointer != 0) {
|
|
||||||
vga_text += printStr("Seek Error", vga_text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
err = DFS_ReadFile(&fi, scratch, diskReadBuf, &fileLen, fi.filelen);
|
|
||||||
if (err && err != DFS_EOF) {
|
|
||||||
vga_text += printStr("Read Error: ", vga_text);
|
|
||||||
printDword(err, vga_text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t *lineOffsets = (uint32_t *)0x400000;
|
|
||||||
uint32_t lastLine;
|
|
||||||
{
|
|
||||||
char nl;
|
|
||||||
uint8_t c = 0x0A; // start with a pretend newline
|
|
||||||
uint32_t line = -1; // start a pretend line behind
|
|
||||||
for (int32_t o = -1; o < (int32_t)fileLen; c = diskReadBuf[++o]) {
|
|
||||||
// newline
|
|
||||||
if (c == 0x0A) {
|
|
||||||
lineOffsets[++line] = o;
|
|
||||||
}
|
|
||||||
// file too large
|
|
||||||
if ((uintptr_t)&lineOffsets[line] >= 0x4FFFFC) {
|
|
||||||
vga_text += printStr("File too large.", vga_text);
|
|
||||||
kbd_wait();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastLine = line;
|
|
||||||
}
|
|
||||||
uint32_t currLine = 0;
|
|
||||||
char cont = 1;
|
|
||||||
uint32_t screenSize = 80*25;
|
|
||||||
char redraw = 1;
|
|
||||||
uint32_t linesOnScreen = 0;
|
|
||||||
for (;cont;) {
|
|
||||||
if (redraw) {
|
|
||||||
vga_text = (uint16_t *)0xb8000;
|
|
||||||
for (int i = 0; i < screenSize; i++)
|
|
||||||
vga_text[i] = 0x0f00;
|
|
||||||
vga_text += printStr((char*)path, vga_text);
|
|
||||||
vga_text += 2;
|
|
||||||
vga_text += printStr("Line: ", vga_text);
|
|
||||||
vga_text += printDec(currLine, vga_text);
|
|
||||||
vga_text += printChar('/', vga_text);
|
|
||||||
vga_text += printDec(lastLine, vga_text);
|
|
||||||
vga_text += printStr(" Scroll: Up/Down PgUp/PgDown Home/End", vga_text);
|
|
||||||
{
|
|
||||||
const char prnt[] = "Exit: E ";
|
|
||||||
vga_text = &((uint16_t*)0xb8000)[80-sizeof(prnt)];
|
|
||||||
vga_text += printStr((char*)prnt, vga_text);
|
|
||||||
}
|
|
||||||
for (vga_text = &((uint16_t*)0xb8000)[84]; vga_text < &((uint16_t*)0xb8000)[screenSize]; vga_text += 80)
|
|
||||||
*(uint8_t*)vga_text = '|';
|
|
||||||
vga_text = &((uint16_t*)0xb8000)[0];
|
|
||||||
uint32_t lineOff = 6;
|
|
||||||
uint8_t c = 0x0A; // start with a pretend newline
|
|
||||||
uint32_t line = currLine - 1; // start a pretend line behind
|
|
||||||
int32_t o = lineOffsets[currLine]; // the real or fake newline on previous line
|
|
||||||
linesOnScreen = screenSize/80;
|
|
||||||
for (; o < (int32_t)fileLen && vga_text < &((uint16_t*)0xb8000)[screenSize]; c = diskReadBuf[++o]) {
|
|
||||||
// newline
|
|
||||||
if (c == 0x0A) {
|
|
||||||
vga_text = nextLine(vga_text,(uint16_t*)0xb8000);
|
|
||||||
line++;
|
|
||||||
{
|
|
||||||
uint16_t *vga_tmp = vga_text;
|
|
||||||
uint16_t decTmp[11];
|
|
||||||
char cnt = printDec(line, decTmp);
|
|
||||||
char off = cnt <= 4 ? 0 : cnt - 4;
|
|
||||||
vga_tmp += 4 - (cnt - off);
|
|
||||||
for (int i = off; i < cnt; i++, vga_tmp++)
|
|
||||||
*(uint8_t*)vga_tmp = (uint8_t)decTmp[i];
|
|
||||||
}
|
|
||||||
vga_text += 6;
|
|
||||||
lineOff = 6;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*(uint8_t*)vga_text = c;
|
|
||||||
vga_text++;
|
|
||||||
lineOff++;
|
|
||||||
if (lineOff == 80) { // last char
|
|
||||||
vga_text += 6;
|
|
||||||
lineOff = 6;
|
|
||||||
linesOnScreen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
redraw = 0;
|
|
||||||
}
|
|
||||||
uint16_t key = get_scancode();
|
|
||||||
union V86Regs_t regs;
|
|
||||||
FARPTR v86_entry;
|
|
||||||
switch (key & 0xff) {
|
|
||||||
case KEY_DOWN: // down
|
|
||||||
if (currLine < lastLine && lineOffsets[currLine+1] < fileLen) {
|
|
||||||
currLine++;
|
|
||||||
redraw = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KEY_UP: // up
|
|
||||||
if ((currLine > 0 && lineOffsets[currLine-1] < fileLen) || currLine == 1) {
|
|
||||||
currLine--;
|
|
||||||
redraw = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KEY_PGDOWN:
|
|
||||||
if (currLine+(linesOnScreen/2) <= lastLine && lineOffsets[currLine+(linesOnScreen/2)] < fileLen) {
|
|
||||||
currLine += (linesOnScreen/2);
|
|
||||||
redraw = 1;
|
|
||||||
} else goto end;
|
|
||||||
break;
|
|
||||||
case KEY_PGUP:
|
|
||||||
if (currLine > (linesOnScreen/2) && lineOffsets[currLine-(linesOnScreen/2)] < fileLen) {
|
|
||||||
currLine -= (linesOnScreen/2);
|
|
||||||
redraw = 1;
|
|
||||||
} else if (currLine <= (linesOnScreen/2)) {
|
|
||||||
currLine = 0;
|
|
||||||
redraw = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KEY_HOME: home:
|
|
||||||
if (currLine != 0) {
|
|
||||||
currLine = 0;
|
|
||||||
redraw = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KEY_END: end:
|
|
||||||
if (currLine != lastLine) {
|
|
||||||
currLine = lastLine;
|
|
||||||
redraw = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KEY_E: // e
|
|
||||||
cont = 0;
|
|
||||||
break;
|
|
||||||
case KEY_F2:
|
|
||||||
if (screenSize != 80*25) {
|
|
||||||
SetVideo25Lines();
|
|
||||||
SetCursorDisabled();
|
|
||||||
screenSize = 80*25;
|
|
||||||
redraw = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KEY_F5:
|
|
||||||
if (screenSize != 80*50) {
|
|
||||||
SetVideo50Lines();
|
|
||||||
SetCursorDisabled();
|
|
||||||
screenSize = 80*50;
|
|
||||||
redraw = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 400000 - 700000 Usermode Code (3mB)
|
|
||||||
// 700000 - 800000 Usermode Stack (1mB)
|
|
||||||
extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
|
extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
|
||||||
void ProgramLoadTest(uint8_t *path, VOLINFO *vi) {
|
void ProgramLoadTest(char *path) {
|
||||||
uint16_t *vga_text = (uint16_t *)0xb8000;
|
uint16_t *vga_text = (uint16_t *)0xb8000;
|
||||||
for (int i = 0; i < 80*25; i++)
|
for (int i = 0; i < 80*25; i++)
|
||||||
vga_text[i] = 0x0f00;
|
vga_text[i] = 0x0f00;
|
||||||
uint32_t successcount;
|
uint32_t successcount;
|
||||||
uint8_t *diskReadBuf = (uint8_t *)0x400000;
|
uint8_t *diskReadBuf = (uint8_t *)&_USERMODE;
|
||||||
{
|
{
|
||||||
uint32_t err;
|
uint32_t err;
|
||||||
uint8_t *scratch = (uint8_t *)0x20000;
|
dirent de;
|
||||||
FILEINFO fi;
|
err = path_getinfo(path, &de);
|
||||||
err = DFS_OpenFile(vi, path, DFS_READ, scratch, &fi);
|
if (de.size > 0x300000 || err) {
|
||||||
|
vga_text += printStr("File too large or error.", vga_text);
|
||||||
|
kbd_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FILE file;
|
||||||
|
err = file_open(&file, path, OPENREAD);
|
||||||
if (err) {
|
if (err) {
|
||||||
vga_text += printStr("Open Error: ", vga_text);
|
vga_text += printStr("Open Error: ", vga_text);
|
||||||
printDword(err, vga_text);
|
printDword(err, vga_text);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fi.filelen > 0x300000) {
|
err = file_seek(&file, 0);
|
||||||
vga_text += printStr("File too large.", vga_text);
|
if (err) {
|
||||||
kbd_wait();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DFS_Seek(&fi, 0, scratch);
|
|
||||||
if (fi.pointer != 0) {
|
|
||||||
vga_text += printStr("Seek Error", vga_text);
|
vga_text += printStr("Seek Error", vga_text);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
err = DFS_ReadFile(&fi, scratch, diskReadBuf, &successcount, fi.filelen);
|
successcount = err = file_read(&file, diskReadBuf, de.size);
|
||||||
if (err && err != DFS_EOF) {
|
if (!err && de.size > 0) {
|
||||||
vga_text += printStr("Read Error: ", vga_text);
|
vga_text += printStr("Read Error", vga_text);
|
||||||
printDword(err, vga_text);
|
printDword(err, vga_text);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (successcount < fi.filelen) {
|
|
||||||
vga_text += printStr("Could not read all file bytes.", vga_text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
vga_text += printStr("Successfully loaded program \"", vga_text);
|
vga_text += printStr("Successfully loaded program \"", vga_text);
|
||||||
vga_text += printStr((char*)path, vga_text);
|
vga_text += printStr((char*)path, vga_text);
|
||||||
@ -228,7 +45,7 @@ void ProgramLoadTest(uint8_t *path, VOLINFO *vi) {
|
|||||||
vga_text = nextLine(vga_text,(uint16_t*)0xb8000);
|
vga_text = nextLine(vga_text,(uint16_t*)0xb8000);
|
||||||
vga_text += printStr("Press any key to run.", vga_text);
|
vga_text += printStr("Press any key to run.", vga_text);
|
||||||
kbd_wait();
|
kbd_wait();
|
||||||
uint32_t res = create_user_child(0x800000, 0x400000, 0);
|
uint32_t res = create_user_child((uintptr_t)&_USERMODE_END, (uintptr_t)&_USERMODE, 0);
|
||||||
union V86Regs_t regs;
|
union V86Regs_t regs;
|
||||||
regs.w.ax = 3; // text mode
|
regs.w.ax = 3; // text mode
|
||||||
V8086Int(0x10, ®s);
|
V8086Int(0x10, ®s);
|
||||||
|
12
progs.h
12
progs.h
@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "dosfs/dosfs.h"
|
|
||||||
#include "print.h"
|
|
||||||
#include "kbd.h"
|
|
||||||
#include "v86defs.h"
|
|
||||||
#include "helper.h"
|
|
||||||
|
|
||||||
void HexEditor(uint8_t *path, VOLINFO *vi);
|
|
||||||
void TextViewTest(uint8_t *path, VOLINFO *vi);
|
|
||||||
void ProgramLoadTest(uint8_t *path, VOLINFO *vi);
|
|
10
setenv.sh
Executable file
10
setenv.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SOURCE=${BASH_SOURCE[0]}
|
||||||
|
while [ -L "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||||
|
DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
|
||||||
|
SOURCE=$(readlink "$SOURCE")
|
||||||
|
[[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||||
|
done
|
||||||
|
DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
|
||||||
|
export CPATH="${DIR}/include:${DIR}/lib/include"
|
30
task.nasm
30
task.nasm
@ -152,17 +152,12 @@ mov ecx, esp ; return stack
|
|||||||
call save_current_task
|
call save_current_task
|
||||||
_enter_v86_internal_no_task:
|
_enter_v86_internal_no_task:
|
||||||
mov ebp, esp ; save stack pointer
|
mov ebp, esp ; save stack pointer
|
||||||
mov eax, dword [ebp+16] ; regs
|
; push v86 stuff for iret
|
||||||
test eax, eax
|
mov eax, 0x3000
|
||||||
jz .no_regs
|
push eax ; gs
|
||||||
; load regs: edi, esi, ebx, edx, ecx, eax
|
push eax ; fs
|
||||||
mov edi, dword [eax+0]
|
push eax ; ds
|
||||||
mov esi, dword [eax+4]
|
push eax ; es
|
||||||
mov ebx, dword [eax+8]
|
|
||||||
mov edx, dword [eax+12]
|
|
||||||
mov ecx, dword [eax+16]
|
|
||||||
mov eax, dword [eax+20]
|
|
||||||
.no_regs:
|
|
||||||
push dword [ebp+0] ; ss
|
push dword [ebp+0] ; ss
|
||||||
push dword [ebp+4] ; esp
|
push dword [ebp+4] ; esp
|
||||||
pushfd ; eflags
|
pushfd ; eflags
|
||||||
@ -170,6 +165,19 @@ or dword [esp], (1 << 17) ; set VM flags
|
|||||||
;or dword [esp], (3 << 12) ; IOPL 3
|
;or dword [esp], (3 << 12) ; IOPL 3
|
||||||
push dword [ebp+8] ; cs
|
push dword [ebp+8] ; cs
|
||||||
push dword [ebp+12] ; eip
|
push dword [ebp+12] ; eip
|
||||||
|
; check if we have regs
|
||||||
|
mov eax, dword [ebp+16] ; regs
|
||||||
|
test eax, eax
|
||||||
|
jz .no_regs
|
||||||
|
; load regs: ebp, edi, esi, ebx, edx, ecx, eax
|
||||||
|
mov ebp, dword [eax+0]
|
||||||
|
mov edi, dword [eax+4]
|
||||||
|
mov esi, dword [eax+8]
|
||||||
|
mov ebx, dword [eax+12]
|
||||||
|
mov edx, dword [eax+16]
|
||||||
|
mov ecx, dword [eax+20]
|
||||||
|
mov eax, dword [eax+24]
|
||||||
|
.no_regs:
|
||||||
iret
|
iret
|
||||||
|
|
||||||
; return address in eax, return stack in ebp
|
; return address in eax, return stack in ebp
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[BITS 32]
|
[BITS 32]
|
||||||
[ORG 0x400000]
|
[ORG 0x800000]
|
||||||
xchg bx,bx
|
xchg bx,bx
|
||||||
mov edi, 0xB8000
|
mov edi, 0xB8000
|
||||||
mov ecx, 80*25
|
mov ecx, 80*25
|
||||||
|
228
tests.c
228
tests.c
@ -13,18 +13,21 @@ void TestV86() {
|
|||||||
regs.d.eax = 0x66666666;
|
regs.d.eax = 0x66666666;
|
||||||
FARPTR v86_entry = i386LinearToFp(v86Test);
|
FARPTR v86_entry = i386LinearToFp(v86Test);
|
||||||
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s);
|
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s);
|
||||||
|
uint16_t *vga_text = (uint16_t *)0xb8000 + (80*2);
|
||||||
|
vga_text += printStr("Done.", vga_text);
|
||||||
}
|
}
|
||||||
extern char _loadusercode, _usercode, _eusercode;
|
extern char _USERMODE, _USERMODE_END;
|
||||||
|
extern char _binary_usermode_bin_start, _binary_usermode_bin_end;
|
||||||
void ReloadUser() {
|
void ReloadUser() {
|
||||||
// Put Usermode code in proper place based on linker
|
// Put Usermode code in proper place based on linker
|
||||||
char *s = &_loadusercode;
|
char *s = &_binary_usermode_bin_start;
|
||||||
char *d = &_usercode;
|
char *d = (char *)&_USERMODE;
|
||||||
while (d < &_eusercode)
|
while (s < &_binary_usermode_bin_end)
|
||||||
*d++ = *s++;
|
*d++ = *s++;
|
||||||
}
|
}
|
||||||
char TestUser() {
|
char TestUser() {
|
||||||
ReloadUser();
|
ReloadUser();
|
||||||
char *vga = (char *)(uintptr_t)create_user_child(0x800000, (uintptr_t)user_test, 0);
|
char *vga = (char *)(uintptr_t)create_user_child((uintptr_t)&_USERMODE_END, (uintptr_t)&_USERMODE, 0);
|
||||||
if ((uintptr_t)vga != 0xA0000) {
|
if ((uintptr_t)vga != 0xA0000) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -34,24 +37,40 @@ char TestUser() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
void TestDiskRead() {
|
void TestDiskRead() {
|
||||||
//vga_text += printStr("Starting Disk Read... ", vga_text);
|
|
||||||
union V86Regs_t regs;
|
|
||||||
char *diskReadBuf = (char *)0x20000;
|
char *diskReadBuf = (char *)0x20000;
|
||||||
v86disk_addr_packet.transfer_buffer =
|
v86disk_addr_packet.transfer_buffer =
|
||||||
(uintptr_t)diskReadBuf & 0x000F |
|
(uintptr_t)diskReadBuf & 0x000F |
|
||||||
(((uintptr_t)diskReadBuf & 0xFFFF0) << 12);
|
(((uintptr_t)diskReadBuf & 0xFFFF0) << 12);
|
||||||
|
v86disk_addr_packet.start_block = 0;
|
||||||
|
v86disk_addr_packet.blocks = 2;
|
||||||
|
union V86Regs_t regs;
|
||||||
|
kbd_clear();
|
||||||
|
for (;;) {
|
||||||
regs.h.ah = 0x42;
|
regs.h.ah = 0x42;
|
||||||
FARPTR v86_entry = i386LinearToFp(v86DiskOp);
|
FARPTR v86_entry = i386LinearToFp(v86DiskOp);
|
||||||
enter_v86(0x0000, 0x8000, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s);
|
enter_v86(0x0000, 0x8000, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s);
|
||||||
uint16_t *vga_text = (uint16_t *)0xb8000;
|
uint16_t *vga_text = (uint16_t *)0xb8000;
|
||||||
for (int i = 0; i < (80*25)/2; i++) {
|
for (int i = 0; i < 25; i++) {
|
||||||
printByte(diskReadBuf[i], &vga_text[i*2]);
|
uint16_t *vga_line = &vga_text[i*80];
|
||||||
|
for (int j = 0; j < 26; j++) {
|
||||||
|
printByte(diskReadBuf[i*26 + j], &vga_line[j*2]);
|
||||||
|
*(uint8_t*)&vga_line[j + (26*2)+1] = diskReadBuf[i*26 + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint16_t scan = get_scancode();
|
||||||
|
if ((scan & 0xff) == KEY_PGUP) {
|
||||||
|
if(v86disk_addr_packet.start_block > 0) v86disk_addr_packet.start_block--;
|
||||||
|
} else if ((scan & 0xff) == KEY_PGDOWN)
|
||||||
|
v86disk_addr_packet.start_block++;
|
||||||
|
else if (scan & 0xff00) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extern uint32_t _gpf_eax_save;
|
extern uint32_t _gpf_eax_save;
|
||||||
extern uint32_t _gpf_eflags_save;
|
extern uint32_t _gpf_eflags_save;
|
||||||
void TestCHS() {
|
void TestCHS() {
|
||||||
uint16_t *vga_text = (uint16_t*)0xb8000;
|
uint16_t *vga_text = (uint16_t*)0xb8000;
|
||||||
|
for (int i = 0; i < 80*25; i++)
|
||||||
|
vga_text[i] = 0x0f00;
|
||||||
printStr("CHS Test ", vga_text);
|
printStr("CHS Test ", vga_text);
|
||||||
// CHS Read
|
// CHS Read
|
||||||
union V86Regs_t regs;
|
union V86Regs_t regs;
|
||||||
@ -103,113 +122,123 @@ void TestCHS() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void TestFAT() {
|
|
||||||
uint16_t *vga_text = (uint16_t *)0xb8000;
|
|
||||||
uint8_t *diskReadBuf = (uint8_t *)0x22400;
|
|
||||||
for (int i = 0; i < 80*25; i++)
|
|
||||||
vga_text[i] = 0x0f00;
|
|
||||||
VOLINFO vi;
|
|
||||||
|
|
||||||
uint8_t pactive, ptype;
|
//void TestFAT() {
|
||||||
uint32_t pstart, psize;
|
// uint16_t *vga_text = (uint16_t *)0xb8000;
|
||||||
pstart = DFS_GetPtnStart(0, diskReadBuf, 0, &pactive, &ptype, &psize);
|
// uint8_t *diskReadBuf = (uint8_t *)0x22400;
|
||||||
vga_text = (uint16_t *)0xb8000;
|
// for (int i = 0; i < 80*25; i++)
|
||||||
vga_text += printStr("PartStart: ", vga_text);
|
// vga_text[i] = 0x0f00;
|
||||||
vga_text += printDword(pstart, vga_text);
|
// VOLINFO vi;
|
||||||
vga_text += 2;
|
//
|
||||||
vga_text += printStr("PartSize: ", vga_text);
|
// uint8_t pactive, ptype;
|
||||||
vga_text += printDword(psize, vga_text);
|
// uint32_t pstart, psize;
|
||||||
vga_text += 2;
|
// pstart = DFS_GetPtnStart(0, diskReadBuf, SystemPartition, &pactive, &ptype, &psize);
|
||||||
vga_text += printStr("PartActive: ", vga_text);
|
// vga_text = (uint16_t *)0xb8000;
|
||||||
vga_text += printByte(pactive, vga_text);
|
// vga_text += printStr("PartStart: ", vga_text);
|
||||||
vga_text += 2;
|
// vga_text += printDword(pstart, vga_text);
|
||||||
vga_text += printStr("PartType: ", vga_text);
|
// vga_text += 2;
|
||||||
vga_text += printByte(ptype, vga_text);
|
// vga_text += printStr("PartSize: ", vga_text);
|
||||||
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
|
// vga_text += printDword(psize, vga_text);
|
||||||
//asm ("xchgw %bx, %bx");
|
// vga_text += 2;
|
||||||
|
// vga_text += printStr("PartActive: ", vga_text);
|
||||||
DFS_GetVolInfo(0, diskReadBuf, pstart, &vi);
|
// vga_text += printByte(pactive, vga_text);
|
||||||
vga_text += printStr("Label: ", vga_text);
|
// vga_text += 2;
|
||||||
vga_text += printStr((char*)vi.label, vga_text);
|
// vga_text += printStr("PartType: ", vga_text);
|
||||||
vga_text += 2;
|
// vga_text += printByte(ptype, vga_text);
|
||||||
vga_text += printStr("Sec/Clus: ", vga_text);
|
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
|
||||||
vga_text += printByte(vi.secperclus, vga_text);
|
// //asm ("xchgw %bx, %bx");
|
||||||
vga_text += 2;
|
//
|
||||||
vga_text += printStr("ResrvSec: ", vga_text);
|
// DFS_GetVolInfo(0, diskReadBuf, pstart, &vi);
|
||||||
vga_text += printWord(vi.reservedsecs, vga_text);
|
// vga_text += printStr("Label: ", vga_text);
|
||||||
vga_text += 2;
|
// vga_text += printStr((char*)vi.label, vga_text);
|
||||||
vga_text += printStr("NumSec: ", vga_text);
|
// vga_text += 2;
|
||||||
vga_text += printDword(vi.numsecs, vga_text);
|
// vga_text += printStr("Sec/Clus: ", vga_text);
|
||||||
vga_text += 2;
|
// vga_text += printByte(vi.secperclus, vga_text);
|
||||||
vga_text += printStr("Sec/FAT: ", vga_text);
|
// vga_text += 2;
|
||||||
vga_text += printDword(vi.secperfat, vga_text);
|
// vga_text += printStr("ResrvSec: ", vga_text);
|
||||||
vga_text += 2;
|
// vga_text += printWord(vi.reservedsecs, vga_text);
|
||||||
vga_text += printStr("FAT1@: ", vga_text);
|
// vga_text += 2;
|
||||||
vga_text += printDword(vi.fat1, vga_text);
|
// vga_text += printStr("NumSec: ", vga_text);
|
||||||
vga_text += 2;
|
// vga_text += printDword(vi.numsecs, vga_text);
|
||||||
vga_text += printStr("ROOT@: ", vga_text);
|
// vga_text += 2;
|
||||||
vga_text += printDword(vi.rootdir, vga_text);
|
// vga_text += printStr("Sec/FAT: ", vga_text);
|
||||||
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
|
// vga_text += printDword(vi.secperfat, vga_text);
|
||||||
//asm ("xchgw %bx, %bx");
|
// vga_text += 2;
|
||||||
|
// vga_text += printStr("FAT1@: ", vga_text);
|
||||||
vga_text += printStr("Files in root:", vga_text);
|
// vga_text += printDword(vi.fat1, vga_text);
|
||||||
DIRINFO di;
|
// vga_text += 2;
|
||||||
di.scratch = diskReadBuf;
|
// vga_text += printStr("ROOT@: ", vga_text);
|
||||||
DFS_OpenDir(&vi, (uint8_t*)"", &di);
|
// vga_text += printDword(vi.rootdir, vga_text);
|
||||||
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
|
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
|
||||||
DIRENT de;
|
// //asm ("xchgw %bx, %bx");
|
||||||
while (!DFS_GetNext(&vi, &di, &de)) {
|
//
|
||||||
if (de.name[0]) {
|
// vga_text += printStr("Files in root:", vga_text);
|
||||||
for (int i = 0; i < 11 && de.name[i]; i++) {
|
// DIRINFO di;
|
||||||
if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3
|
// di.scratch = diskReadBuf;
|
||||||
*(uint8_t *)vga_text = de.name[i];
|
// DFS_OpenDir(&vi, (uint8_t*)"", &di);
|
||||||
vga_text++;
|
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
|
||||||
}
|
// DIRENT de;
|
||||||
vga_text += printStr(" ", vga_text);
|
// while (!DFS_GetNext(&vi, &di, &de)) {
|
||||||
vga_text += printDec((uint32_t)de.filesize_0 + ((uint32_t)de.filesize_1 << 8) + ((uint32_t)de.filesize_2 << 16) + ((uint32_t)de.filesize_3 << 24), vga_text);
|
// if (de.name[0]) {
|
||||||
*(uint8_t*)vga_text++ = 'B';
|
// for (int i = 0; i < 11 && de.name[i]; i++) {
|
||||||
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
|
// if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3
|
||||||
}
|
// *(uint8_t *)vga_text = de.name[i];
|
||||||
//asm ("xchgw %bx, %bx");
|
// vga_text++;
|
||||||
}
|
// }
|
||||||
}
|
// vga_text += printStr(" ", vga_text);
|
||||||
|
// vga_text += printDec((uint32_t)de.filesize_0 + ((uint32_t)de.filesize_1 << 8) + ((uint32_t)de.filesize_2 << 16) + ((uint32_t)de.filesize_3 << 24), vga_text);
|
||||||
|
// *(uint8_t*)vga_text++ = 'B';
|
||||||
|
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
|
||||||
|
// }
|
||||||
|
// //asm ("xchgw %bx, %bx");
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
void RunTests() {
|
void RunTests() {
|
||||||
|
char doTests = 1;
|
||||||
uint16_t *vga_text = (uint16_t*)0xb8000;
|
uint16_t *vga_text = (uint16_t*)0xb8000;
|
||||||
|
uint8_t key;
|
||||||
|
for (char l = 1;l;) {
|
||||||
|
if (doTests) {
|
||||||
|
vga_text = (uint16_t*)0xb8000;
|
||||||
for (int i = 0; i < 80*25; i++)
|
for (int i = 0; i < 80*25; i++)
|
||||||
vga_text[i] = 0x1f00;
|
vga_text[i] = 0x1f00;
|
||||||
uint8_t key;
|
|
||||||
vga_text += printStr("V86 Test... ", vga_text);
|
vga_text += printStr("V86 Test... ", vga_text);
|
||||||
//asm ("xchgw %bx, %bx");
|
//asm ("xchgw %bx, %bx");
|
||||||
TestV86(); // has int 3 wait in v86
|
TestV86(); // has int 3 wait in v86
|
||||||
vga_text = (uint16_t *)0xb8000 + (80*3);
|
vga_text = (uint16_t *)0xb8000 + (80*3);
|
||||||
vga_text += printStr("Done. Press 'N' for next test.", vga_text);
|
vga_text += printStr("Press 'N' for next test.", vga_text);
|
||||||
for(;;) {
|
for(;;) {
|
||||||
key = get_key();
|
key = get_key();
|
||||||
if (key == 'N' || key == 'n') break;
|
if (key == 'N' || key == 'n') break;
|
||||||
*vga_text = (*vga_text & 0xFF00) | key;
|
*vga_text = (*vga_text & 0xFF00) | key;
|
||||||
vga_text++;
|
vga_text++;
|
||||||
}
|
}
|
||||||
char userResult = TestUser();
|
if (TestUser()) {
|
||||||
union V86Regs_t regs;
|
union V86Regs_t regs;
|
||||||
regs.w.ax = 3; // text mode
|
regs.w.ax = 3; // text mode
|
||||||
V8086Int(0x10, ®s);
|
V8086Int(0x10, ®s);
|
||||||
vga_text = (uint16_t *)0xb8000 + (80*5);
|
vga_text = (uint16_t *)0xb8000 + (80*5);
|
||||||
printStr("Press any key to continue.", vga_text);
|
|
||||||
if (userResult) {
|
|
||||||
// Usermode returned wrong value
|
|
||||||
printStr("Usermode test failed! Press any key to continue.", vga_text);
|
printStr("Usermode test failed! Press any key to continue.", vga_text);
|
||||||
|
kbd_wait();
|
||||||
|
} else {
|
||||||
|
kbd_wait();
|
||||||
|
union V86Regs_t regs;
|
||||||
|
regs.w.ax = 3; // text mode
|
||||||
|
V8086Int(0x10, ®s);
|
||||||
|
}
|
||||||
|
doTests = 0;
|
||||||
}
|
}
|
||||||
kbd_wait();
|
|
||||||
TestCHS();
|
|
||||||
kbd_wait();
|
|
||||||
TestDiskRead();
|
|
||||||
kbd_wait();
|
|
||||||
TestFAT();
|
|
||||||
|
|
||||||
|
vga_text = &((uint16_t*)0xB8000)[80*14];
|
||||||
|
vga_text += printStr("Press E for a flagrant system error. ", vga_text);
|
||||||
|
vga_text = &((uint16_t*)0xB8000)[80*15];
|
||||||
|
vga_text += printStr("Press D for disk tests. ", vga_text);
|
||||||
vga_text = &((uint16_t*)0xB8000)[80*16];
|
vga_text = &((uint16_t*)0xB8000)[80*16];
|
||||||
vga_text += printStr("Press E for a flagrant system error. Press C to continue... ", vga_text);
|
vga_text += printStr("Press R to repeat tests. ", vga_text);
|
||||||
for (char l = 1;l;) { switch (key = get_key()) {
|
vga_text = &((uint16_t*)0xB8000)[80*17];
|
||||||
|
vga_text += printStr("Press C to continue... ", vga_text);
|
||||||
|
switch (key = get_key()) {
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'E':
|
case 'E':
|
||||||
// flagrant system error
|
// flagrant system error
|
||||||
@ -220,10 +249,23 @@ void RunTests() {
|
|||||||
// continue
|
// continue
|
||||||
l = 0;
|
l = 0;
|
||||||
break;
|
break;
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
// disk tests
|
||||||
|
TestCHS();
|
||||||
|
kbd_wait();
|
||||||
|
TestDiskRead();
|
||||||
|
//TestFAT();
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
doTests = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
*vga_text = (*vga_text & 0xFF00) | key;
|
*vga_text = (*vga_text & 0xFF00) | key;
|
||||||
vga_text++;
|
vga_text++;
|
||||||
break;
|
break;
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
244
textedit.c
Normal file
244
textedit.c
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
#include "progs.h"
|
||||||
|
|
||||||
|
#define MAXFILESIZE 0x300000 // 3MB
|
||||||
|
#define MAXLINES 100000
|
||||||
|
#define BLOCKSIZE 0x1000
|
||||||
|
#define BLOCKMASK 0xfff
|
||||||
|
#define BLOCKSHIFT 12
|
||||||
|
#define TOTALBLOCKS (MAXFILESIZE/BLOCKSIZE)
|
||||||
|
uintptr_t lineOffsets[MAXLINES] __attribute__((section(".textbss")));;
|
||||||
|
uintptr_t lineLengths[MAXLINES] __attribute__((section(".textbss")));;
|
||||||
|
uint8_t editedBlocks[TOTALBLOCKS] __attribute__((section(".textbss")));;
|
||||||
|
uint8_t fileBuffer[MAXFILESIZE]
|
||||||
|
__attribute__((aligned(0x1000)))
|
||||||
|
__attribute__((section(".textlatebss")));
|
||||||
|
void TextViewTest(char *path) {
|
||||||
|
uint16_t *vga_text = (uint16_t *)0xb8000;
|
||||||
|
uint32_t fileLen;
|
||||||
|
{
|
||||||
|
uint32_t err;
|
||||||
|
dirent de;
|
||||||
|
err = path_getinfo(path, &de);
|
||||||
|
if (err) {
|
||||||
|
vga_text += printStr("Error getting file info.", vga_text);
|
||||||
|
kbd_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fileLen = de.size;
|
||||||
|
FILE file;
|
||||||
|
err = file_open(&file, path, OPENREAD);
|
||||||
|
if (err) {
|
||||||
|
vga_text += printStr("Open Error: ", vga_text);
|
||||||
|
printDword(err, vga_text);
|
||||||
|
kbd_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// file too large
|
||||||
|
if (fileLen > MAXFILESIZE) {
|
||||||
|
vga_text += printStr("File too large.", vga_text);
|
||||||
|
kbd_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file_seek(&file, 0)) {
|
||||||
|
vga_text += printStr("Seek Error", vga_text);
|
||||||
|
kbd_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t bytesRead = file_read(&file, fileBuffer, fileLen);
|
||||||
|
if (bytesRead < fileLen) {
|
||||||
|
vga_text += printStr("Read Error: ", vga_text);
|
||||||
|
printDword(err, vga_text);
|
||||||
|
kbd_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t lastLine;
|
||||||
|
{
|
||||||
|
char nl;
|
||||||
|
uint8_t c = 0x0A; // start with a pretend newline
|
||||||
|
uint32_t line = -1; // start a pretend line behind
|
||||||
|
uint32_t lineLen = 0;
|
||||||
|
for (int32_t o = -1; o < (int32_t)fileLen; lineLen++, c = fileBuffer[++o]) {
|
||||||
|
// newline
|
||||||
|
if (c == 0x0A) {
|
||||||
|
lineOffsets[++line] = o;
|
||||||
|
lineLengths[line] = lineLen > 0 ? lineLen : 1;
|
||||||
|
lineLen = 0;
|
||||||
|
}
|
||||||
|
// file too large
|
||||||
|
if (line >= MAXLINES) {
|
||||||
|
vga_text += printStr("File too large.", vga_text);
|
||||||
|
kbd_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineLengths[line] = lineLen;
|
||||||
|
lastLine = line;
|
||||||
|
}
|
||||||
|
uint32_t currLine = 0;
|
||||||
|
char cont = 1;
|
||||||
|
uint32_t screenSize = 80*25;
|
||||||
|
char redraw = 1;
|
||||||
|
uint32_t linesOnScreen = 0;
|
||||||
|
uint32_t cursorLine = 0;
|
||||||
|
uint32_t cursorLineOffset = 0;
|
||||||
|
char cursorChange = 0;
|
||||||
|
for (;cont;) {
|
||||||
|
if (cursorLine > lastLine) {
|
||||||
|
cursorLine = lastLine;
|
||||||
|
cursorLineOffset = lineLengths[lastLine] - 2;
|
||||||
|
cursorChange = 1;
|
||||||
|
}
|
||||||
|
if (lineLengths[cursorLine+1] == 1 && cursorLineOffset == 0){}
|
||||||
|
else if (cursorLineOffset >= lineLengths[cursorLine+1] - 1) {
|
||||||
|
cursorLineOffset = 0;
|
||||||
|
cursorLine++;
|
||||||
|
cursorChange = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redraw || cursorChange) {
|
||||||
|
vga_text = (uint16_t *)0xb8000;
|
||||||
|
for (int i = 0; i < screenSize; i++)
|
||||||
|
vga_text[i] = 0x0f00;
|
||||||
|
char pathBuff[22];
|
||||||
|
trimPath((char*)path, pathBuff, sizeof(pathBuff));
|
||||||
|
vga_text += printStr(pathBuff, vga_text);
|
||||||
|
vga_text += 2;
|
||||||
|
vga_text += printDec(currLine, vga_text);
|
||||||
|
vga_text += printChar('/', vga_text);
|
||||||
|
vga_text += printDec(lastLine, vga_text);
|
||||||
|
vga_text += printStr(" Scroll: Up/Down PgUp/PgDown Home/End", vga_text);
|
||||||
|
{
|
||||||
|
const char prnt[] = "Exit: F1";
|
||||||
|
vga_text = &((uint16_t*)0xb8000)[80-sizeof(prnt)+1];
|
||||||
|
vga_text += printStr((char*)prnt, vga_text);
|
||||||
|
}
|
||||||
|
for (vga_text = &((uint16_t*)0xb8000)[84]; vga_text < &((uint16_t*)0xb8000)[screenSize]; vga_text += 80)
|
||||||
|
*(uint8_t*)vga_text = '|';
|
||||||
|
vga_text = &((uint16_t*)0xb8000)[0];
|
||||||
|
uint32_t screenLineOff = 6;
|
||||||
|
uint32_t lineOffset = 0;
|
||||||
|
uint8_t c = 0x0A; // start with a pretend newline
|
||||||
|
uint32_t line = currLine - 1; // start a pretend line behind
|
||||||
|
int32_t o = lineOffsets[currLine]; // the real or fake newline on previous line
|
||||||
|
linesOnScreen = screenSize/80;
|
||||||
|
for (; o < (int32_t)fileLen && vga_text < &((uint16_t*)0xb8000)[screenSize]; c = fileBuffer[++o]) {
|
||||||
|
// newline
|
||||||
|
if (c == 0x0A) {
|
||||||
|
vga_text = nextLine(vga_text,(uint16_t*)0xb8000);
|
||||||
|
line++;
|
||||||
|
lineOffset = 0;
|
||||||
|
{
|
||||||
|
uint16_t *vga_tmp = vga_text;
|
||||||
|
uint16_t decTmp[11];
|
||||||
|
char cnt = printDec(line, decTmp);
|
||||||
|
char off = cnt <= 4 ? 0 : cnt - 4;
|
||||||
|
vga_tmp += 4 - (cnt - off);
|
||||||
|
for (int i = off; i < cnt; i++, vga_tmp++)
|
||||||
|
*(uint8_t*)vga_tmp = (uint8_t)decTmp[i];
|
||||||
|
}
|
||||||
|
vga_text += 6;
|
||||||
|
screenLineOff = 6;
|
||||||
|
if (cursorLine == line && cursorLineOffset == lineOffset) {
|
||||||
|
((uint8_t*)vga_text)[1] = 0xf0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*(uint8_t*)vga_text = c;
|
||||||
|
if (cursorLine == line && cursorLineOffset == lineOffset) {
|
||||||
|
((uint8_t*)vga_text)[1] = 0xf0;
|
||||||
|
}
|
||||||
|
lineOffset++;
|
||||||
|
vga_text++;
|
||||||
|
screenLineOff++;
|
||||||
|
if (screenLineOff == 80) { // last char
|
||||||
|
vga_text += 6;
|
||||||
|
screenLineOff = 6;
|
||||||
|
linesOnScreen--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
redraw = 0;
|
||||||
|
}
|
||||||
|
uint16_t key = get_scancode();
|
||||||
|
union V86Regs_t regs;
|
||||||
|
FARPTR v86_entry;
|
||||||
|
switch (key & 0xff) {
|
||||||
|
/*case KEY_DOWN: // down
|
||||||
|
if (currLine < lastLine && lineOffsets[currLine+1] < fileLen) {
|
||||||
|
currLine++;
|
||||||
|
redraw = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_UP: // up
|
||||||
|
if ((currLine > 0 && lineOffsets[currLine-1] < fileLen) || currLine == 1) {
|
||||||
|
currLine--;
|
||||||
|
redraw = 1;
|
||||||
|
}
|
||||||
|
break;*/
|
||||||
|
case KEY_DOWN:
|
||||||
|
cursorLine++;
|
||||||
|
cursorChange = 1;
|
||||||
|
break;
|
||||||
|
case KEY_UP:
|
||||||
|
if (cursorLine > 0) cursorLine--;
|
||||||
|
cursorChange = 1;
|
||||||
|
break;
|
||||||
|
case KEY_LEFT:
|
||||||
|
if (cursorLineOffset > 0) cursorLineOffset--;
|
||||||
|
cursorChange = 1;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHT:
|
||||||
|
cursorLineOffset++;
|
||||||
|
cursorChange = 1;
|
||||||
|
break;
|
||||||
|
case KEY_PGDOWN:
|
||||||
|
if (currLine+(linesOnScreen/2) <= lastLine && lineOffsets[currLine+(linesOnScreen/2)] < fileLen) {
|
||||||
|
currLine += (linesOnScreen/2);
|
||||||
|
redraw = 1;
|
||||||
|
} else goto end;
|
||||||
|
break;
|
||||||
|
case KEY_PGUP:
|
||||||
|
if (currLine > (linesOnScreen/2) && lineOffsets[currLine-(linesOnScreen/2)] < fileLen) {
|
||||||
|
currLine -= (linesOnScreen/2);
|
||||||
|
redraw = 1;
|
||||||
|
} else if (currLine <= (linesOnScreen/2)) {
|
||||||
|
currLine = 0;
|
||||||
|
redraw = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_HOME: home:
|
||||||
|
if (currLine != 0) {
|
||||||
|
currLine = 0;
|
||||||
|
redraw = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_END: end:
|
||||||
|
if (currLine != lastLine) {
|
||||||
|
currLine = lastLine;
|
||||||
|
redraw = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_F1:
|
||||||
|
cont = 0;
|
||||||
|
break;
|
||||||
|
case KEY_F2:
|
||||||
|
if (screenSize != 80*25) {
|
||||||
|
SetVideo25Lines();
|
||||||
|
SetCursorDisabled();
|
||||||
|
screenSize = 80*25;
|
||||||
|
redraw = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_F5:
|
||||||
|
if (screenSize != 80*50) {
|
||||||
|
SetVideo50Lines();
|
||||||
|
SetCursorDisabled();
|
||||||
|
screenSize = 80*50;
|
||||||
|
redraw = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
[SECTION .user]
|
[BITS 32]
|
||||||
|
[ORG 0x800000]
|
||||||
global user_test
|
global user_test
|
||||||
user_test:
|
user_test:
|
||||||
mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16
|
mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16
|
||||||
@ -42,6 +43,7 @@ push 0x00000000 ; edx
|
|||||||
push 0x00000000 ; ebx
|
push 0x00000000 ; ebx
|
||||||
push 0x00000000 ; esi
|
push 0x00000000 ; esi
|
||||||
push 0x00000000 ; edi
|
push 0x00000000 ; edi
|
||||||
|
push 0x00000000 ; ebp
|
||||||
push esp ; regs
|
push esp ; regs
|
||||||
push 0x10 ; interrupt
|
push 0x10 ; interrupt
|
||||||
mov eax, 0x86 ; command = 86h, virtual 8086 call
|
mov eax, 0x86 ; command = 86h, virtual 8086 call
|
||||||
|
192
v86.nasm
192
v86.nasm
@ -4,7 +4,83 @@ global v86Interrupt
|
|||||||
v86Interrupt:
|
v86Interrupt:
|
||||||
int 0x00
|
int 0x00
|
||||||
int 0x30
|
int 0x30
|
||||||
jmp $
|
ud2
|
||||||
|
|
||||||
|
global v86TransFlag
|
||||||
|
v86TransFlag:
|
||||||
|
push cs
|
||||||
|
pop es
|
||||||
|
mov ax, 0x13
|
||||||
|
int 0x10
|
||||||
|
mov ax,0x1012
|
||||||
|
xor bx,bx
|
||||||
|
mov cx,5
|
||||||
|
mov dx,.c
|
||||||
|
int 0x10
|
||||||
|
push 0xa000
|
||||||
|
pop es
|
||||||
|
xor di,di
|
||||||
|
xor ax,ax
|
||||||
|
.loop:
|
||||||
|
mov cx, 12800
|
||||||
|
rep stosb
|
||||||
|
inc ax
|
||||||
|
cmp ax,5
|
||||||
|
jl .loop
|
||||||
|
int 0x30
|
||||||
|
ud2
|
||||||
|
.c: db `\0263>=*.\?\?\?=*.\0263>`
|
||||||
|
|
||||||
|
global v86VideoInt
|
||||||
|
v86VideoInt:
|
||||||
|
int 0x10
|
||||||
|
int 0x30
|
||||||
|
ud2
|
||||||
|
|
||||||
|
global v86DiskOp
|
||||||
|
v86DiskOp:
|
||||||
|
xor bx, bx ; TODO fix assuming we're in first 64k
|
||||||
|
mov ds, bx
|
||||||
|
mov dl, 0x80 ; TODO get this from BIOS or something
|
||||||
|
mov si, v86disk_addr_packet ; ds:si
|
||||||
|
int 0x13
|
||||||
|
jc .err
|
||||||
|
int 0x30
|
||||||
|
.err:
|
||||||
|
ud2
|
||||||
|
global v86disk_addr_packet
|
||||||
|
v86disk_addr_packet:
|
||||||
|
db 0x10, 0x00 ; size, reserved
|
||||||
|
dw 0x1 ; blocks
|
||||||
|
dd 0x23000000 ; transfer buffer 0x23000
|
||||||
|
dq 0x1 ; start block
|
||||||
|
|
||||||
|
global v86DiskGetGeometry
|
||||||
|
v86DiskGetGeometry:
|
||||||
|
mov ah, 8
|
||||||
|
mov dl, 0x80
|
||||||
|
int 0x13
|
||||||
|
movzx eax, ch
|
||||||
|
shl eax, 16
|
||||||
|
mov al, cl
|
||||||
|
mov ah, dh
|
||||||
|
int 0x30
|
||||||
|
ud2
|
||||||
|
|
||||||
|
global v86DiskReadCHS
|
||||||
|
v86DiskReadCHS:
|
||||||
|
push 0x2000
|
||||||
|
pop es
|
||||||
|
int 0x13
|
||||||
|
int 0x30
|
||||||
|
ud2
|
||||||
|
|
||||||
|
global v86TextMode
|
||||||
|
v86TextMode:
|
||||||
|
mov ax, 0x3
|
||||||
|
int 0x10
|
||||||
|
int 0x30
|
||||||
|
ud2
|
||||||
|
|
||||||
real_hexprint:
|
real_hexprint:
|
||||||
xor cx, cx
|
xor cx, cx
|
||||||
@ -36,94 +112,48 @@ ret
|
|||||||
|
|
||||||
global v86Test
|
global v86Test
|
||||||
v86Test:
|
v86Test:
|
||||||
mov ax, 0xb814
|
mov ax, (0xB8000 + (80*2)) >> 4
|
||||||
mov es, ax
|
mov es, ax
|
||||||
mov di, 20
|
mov di, 0
|
||||||
|
mov word es:[di+0], 0x1f00 | 'S'
|
||||||
|
mov word es:[di+2], 0x1f00 | 'S'
|
||||||
|
mov word es:[di+4], 0x1f00 | ':'
|
||||||
|
add di, 6
|
||||||
|
mov ax, ss
|
||||||
|
call real_printword
|
||||||
|
add di, 2
|
||||||
|
mov word es:[di+0], 0x1f00 | 'S'
|
||||||
|
mov word es:[di+2], 0x1f00 | 'P'
|
||||||
|
mov word es:[di+4], 0x1f00 | ':'
|
||||||
|
add di, 6
|
||||||
mov ax, sp
|
mov ax, sp
|
||||||
call real_printword
|
call real_printword
|
||||||
add di, 2
|
add di, 2
|
||||||
|
mov word es:[di+0], 0x1f00 | 'D'
|
||||||
|
mov word es:[di+2], 0x1f00 | 'S'
|
||||||
|
mov word es:[di+4], 0x1f00 | ':'
|
||||||
|
add di, 6
|
||||||
mov ax, ds
|
mov ax, ds
|
||||||
call real_printword
|
call real_printword
|
||||||
add di, 2
|
add di, 2
|
||||||
|
mov word es:[di+0], 0x1f00 | 'C'
|
||||||
|
mov word es:[di+2], 0x1f00 | 'S'
|
||||||
|
mov word es:[di+4], 0x1f00 | ':'
|
||||||
|
add di, 6
|
||||||
mov ax, cs
|
mov ax, cs
|
||||||
call real_printword
|
call real_printword
|
||||||
int 3
|
add di, 2
|
||||||
|
mov ax, cs
|
||||||
|
mov ds, ax
|
||||||
|
mov si, .testStr
|
||||||
|
mov ah, 0x1f
|
||||||
|
mov cx, .testStr_end - .testStr
|
||||||
|
.print:
|
||||||
|
lodsb
|
||||||
|
stosw
|
||||||
|
loop .print
|
||||||
|
int 3 ; wait for key
|
||||||
int 0x30 ; exit
|
int 0x30 ; exit
|
||||||
jmp $
|
|
||||||
|
|
||||||
global v86TransFlag
|
|
||||||
v86TransFlag:
|
|
||||||
push cs
|
|
||||||
pop es
|
|
||||||
mov ax, 0x13
|
|
||||||
int 0x10
|
|
||||||
mov ax,0x1012
|
|
||||||
xor bx,bx
|
|
||||||
mov cx,5
|
|
||||||
mov dx,.c
|
|
||||||
int 0x10
|
|
||||||
push 0xa000
|
|
||||||
pop es
|
|
||||||
xor di,di
|
|
||||||
xor ax,ax
|
|
||||||
.loop:
|
|
||||||
mov cx, 12800
|
|
||||||
rep stosb
|
|
||||||
inc ax
|
|
||||||
cmp ax,5
|
|
||||||
jl .loop
|
|
||||||
int 0x30
|
|
||||||
jmp $
|
|
||||||
.c: db `\0263>=*.\?\?\?=*.\0263>`
|
|
||||||
|
|
||||||
global v86TextMode
|
|
||||||
v86TextMode:
|
|
||||||
mov ax, 0x3
|
|
||||||
int 0x10
|
|
||||||
int 0x30
|
|
||||||
jmp $
|
|
||||||
|
|
||||||
global v86VideoInt
|
|
||||||
v86VideoInt:
|
|
||||||
int 0x10
|
|
||||||
int 0x30
|
|
||||||
jmp $
|
|
||||||
|
|
||||||
global v86DiskOp
|
|
||||||
v86DiskOp:
|
|
||||||
xor bx, bx ; TODO fix assuming we're in first 64k
|
|
||||||
mov ds, bx
|
|
||||||
mov dl, 0x80 ; TODO get this from BIOS or something
|
|
||||||
mov si, v86disk_addr_packet ; ds:si
|
|
||||||
int 0x13
|
|
||||||
jc .err
|
|
||||||
int 0x30
|
|
||||||
.err:
|
|
||||||
ud2
|
|
||||||
jmp $
|
|
||||||
global v86disk_addr_packet
|
|
||||||
v86disk_addr_packet:
|
|
||||||
db 0x10, 0x00 ; size, reserved
|
|
||||||
dw 0x1 ; blocks
|
|
||||||
dd 0x23000000 ; transfer buffer 0x23000
|
|
||||||
dq 0x1 ; start block
|
|
||||||
|
|
||||||
global v86DiskGetGeometry
|
|
||||||
v86DiskGetGeometry:
|
|
||||||
mov ah, 8
|
|
||||||
mov dl, 0x80
|
|
||||||
int 0x13
|
|
||||||
movzx eax, ch
|
|
||||||
shl eax, 16
|
|
||||||
mov al, cl
|
|
||||||
mov ah, dh
|
|
||||||
int 0x30
|
|
||||||
ud2
|
|
||||||
|
|
||||||
global v86DiskReadCHS
|
|
||||||
v86DiskReadCHS:
|
|
||||||
push 0x2000
|
|
||||||
pop es
|
|
||||||
int 0x13
|
|
||||||
int 0x30
|
|
||||||
ud2
|
ud2
|
||||||
|
.testStr: db "PRESS ANY KEY"
|
||||||
|
.testStr_end:
|
||||||
|
BIN
virtdisk.bin.ex
BIN
virtdisk.bin.ex
Binary file not shown.
Loading…
Reference in New Issue
Block a user