Compare commits

...

10 Commits

42 changed files with 1834 additions and 920 deletions

2
.gitignore vendored
View File

@ -4,3 +4,5 @@
*.lock *.lock
*.com *.com
bx_enh_dbg.ini bx_enh_dbg.ini
.cache
compile_commands.json

View File

@ -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

View File

@ -1,2 +1,3 @@
# luciaos # ROSE
in progress toy OS
i work on stream at <https://twitch.tv/mcrrox>

219
boot.nasm
View File

@ -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
View 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
View File

@ -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;

View File

@ -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

View File

@ -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
View 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
View 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
View 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;
}

View File

@ -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

View File

@ -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, &regs); V8086Int(0x10, &regs);
} }
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
View File

@ -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
View 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
View 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
View 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
View 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);

View File

@ -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);

View File

@ -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();

View File

@ -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
View 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);

View File

@ -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"

View File

@ -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;

View File

@ -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
View File

@ -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
View File

@ -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), &regs); enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
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*)&current_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*)&current_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*)&current_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), &regs);
}
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), &regs);
}
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
View File

@ -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*)
} }
} }

View File

@ -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
View File

@ -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, &regs); V8086Int(0x10, &regs);

12
progs.h
View File

@ -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
View 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"

View File

@ -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

View File

@ -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
View File

@ -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), &regs); enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
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), &regs); enter_v86(0x0000, 0x8000, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
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, &regs); V8086Int(0x10, &regs);
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, &regs);
}
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
View 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;
}
}
}

View File

@ -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
View File

@ -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:

Binary file not shown.