Compare commits

...

10 Commits

42 changed files with 1834 additions and 920 deletions

2
.gitignore vendored
View File

@ -4,3 +4,5 @@
*.lock
*.com
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
CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding -march=i686 -fno-stack-protector -Wno-int-conversion -nostdlib -c
objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o gdt.o\
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
nasm -f elf32 -o $@ $<
%.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:
dd bs=1M count=32 if=/dev/zero of=virtdisk.bin
echo -n -e '\x55\xaa' | dd bs=1 seek=510 conv=notrunc of=virtdisk.bin
cp virtdisk.bin.ex virtdisk.bin
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
kernelreads equ 0x10000/(512*secreadcnt) ; 64K / Sector Size FIXME This underestimates when kernel size is not divisible by bytes per read
[ORG 0x7c00]
; This boots the active partition.
; Relocates self to 0x7E00, loads the
; first sector of active partition
; to 0x7C00 and jumps
[ORG 0x7C00]
[BITS 16]
xor ax, ax
mov ds, ax
@ -8,68 +10,50 @@ mov es, ax
mov ax, 0x8000
mov ss, ax
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 bx, 0x55AA
int 0x13
jc no_exten
mov cx, kernelreads
read_loop:
jc no_int13
; Find active partition
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
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:
;mov ax,0x2403 ; A20 BIOS Support
;int 0x15
;jb .no_a20
;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
; Jump to partition boot
jmp 0:0x7C00
no_int13:
mov si, no_exten_str
mov cx, no_exten_str_end - no_exten_str
jmp print
err:
mov bx, ax
mov si, string
@ -83,126 +67,17 @@ err_print:
lodsb
stosw
loop err_print
;add di, 2
;mov ax, bx
;call hexprint
hlt_loop:
hlt
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_end:
;no_exten_str: db 'NO INT13 EXTEN'
;no_exten_str_end:
no_exten_str: db 'NO INT13 EXTEN'
no_exten_str_end:
addr_packet:
db 0x10, 0x00 ; size, reserved
dw secreadcnt ; blocks
addr_packet_transfer_buff_off: dw 0x0000 ; transfer buffer offset
addr_packet_transfer_buff_seg: dw 0x2000 ; transfer buffer segment
addr_packet_start_block: dq 1 ; start block
dw 1 ; blocks
addr_packet_transfer_buff_off: dw 0x7C00 ; transfer buffer offset
addr_packet_transfer_buff_seg: dw 0x0000 ; transfer buffer segment
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

47
disk.c
View File

@ -1,22 +1,24 @@
#include "disk.h"
#include "v86defs.h"
#include "print.h"
#include "dosfs/dosfs.h"
#include "stdint.h"
extern void *memcpy(void *restrict dest, const void *restrict src, uintptr_t n);
#define SECTOR_SIZE 512
#define DISKCACHEBLOCKSIZE 0x1000 // 512 * 4
#define DISKCACHESECTORMASK 7
#define DISKCACHESECTORSIZE 8
#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 DiskCacheSector[DISKCACHEBLOCKCOUNT];
extern uint32_t _gpf_eax_save;
extern uint32_t _gpf_eflags_save;
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
uint32_t numHead;
uint32_t secPerTrack;
@ -48,12 +50,6 @@ void Disk_SetupCHS() {
maxCylinder = ((_gpf_eax_save & 0xff0000) >> 16) | ((_gpf_eax_save & 0xc0) << 2);
useCHS = 1;
}
// Init Cache
for (int i = 0; i < DISKCACHEBLOCKCOUNT; i++) {
DiskCacheLastRead[i] = 0;
DiskCacheSector[i] = -1;
}
}
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 DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
// NOTE If the buffer provided is outside the 0x20000-0x2FE00 range,
// the function will use that buffer for the Virtual 8086 process
// and copy to the other buffer after
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
if (useCHS == -1) {
Disk_SetupCHS();
void InitCache() {
for (int i = 0; i < DISKCACHEBLOCKCOUNT; i++) {
DiskCacheLastRead[i] = 0;
DiskCacheSector[i] = -1;
}
}
// NOTE Must be run before reading from disk
void InitDisk() {
InitCache();
Disk_SetupCHS();
}
uint32_t Disk_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
uint8_t *cache = FindInCache(sector);
if (cache) {
memcpy(buffer, cache, count * SECTOR_SIZE);
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
if (!useCHS) {
// 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);
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,
// the function will use copy that buffer into the Virtual 8086 disk range
uint8_t *v86buf = buffer;

View File

@ -16,7 +16,7 @@ mov es, ax
mov ss, ax
mov fs, ax
mov gs, ax
mov ebp, 0x400000
mov ebp, 0x800000
mov esp, ebp
mov eax, 0x1f001f00
mov ecx, (80*25)/2

View File

@ -83,6 +83,7 @@ je .int30
cmp eax, 0x21CD ; int 0x21
je .int21
jmp gpf_unhandled
.int21:
pop eax ; command
cmp al, 0x00 ; get key
@ -94,7 +95,13 @@ jne .s86
call get_scancode
jmp .return_to_offender
.s86: cmp al, 0x86 ; v86 interrupt call
je .v86int
cmp ax, 0x86D8 ; get v86 data pointer
jne .return_to_offender
mov eax, 0x30000 ; V86 Data
jmp .return_to_offender
.v86int:
add esp, 4
add dword [esp+0], 2
; add a new task
@ -120,6 +127,7 @@ push eax ; cs
push 0xFF00 ; sp
push 0x8000 ; ss
jmp _enter_v86_internal_no_task ; NOT a function call
.int30:
pop eax ; return value
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
iret
; from linux 0.0.1
global picInit
picInit:
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)));
}
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) {
// Edit the v8086 code with the interrupt
// Writing 4 bytes to ensure proper code
@ -32,51 +48,6 @@ void SetCursorDisabled() {
V8086Int(0x10, &regs);
}
uint32_t OpenVol(VOLINFO *vi) {
uint8_t *diskReadBuf = (uint8_t *)0x20000;
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;
void GetFileList(DIR *dir, dirent *entries, int32_t *entCount, int32_t maxEntries) {
for ((*entCount) = 0; *entCount < maxEntries && !dir_nextentry(dir, &entries[*entCount]); (*entCount)++);
}

106
hexedit.c
View File

@ -1,3 +1,4 @@
#include "file.h"
#include "progs.h"
#define BLOCKSIZE 0x10000 // 64K
@ -5,17 +6,16 @@
#define BLOCKSHIFT 16 // blockSize = 1 << blockShift
#define MAXFILESIZE 0x80000000 // 2GB
#define TOTALBLOCKS (MAXFILESIZE/BLOCKSIZE)
uint16_t writtenMap[TOTALBLOCKS];
uint32_t blockLenMap[TOTALBLOCKS];
uint16_t writtenMap[TOTALBLOCKS] __attribute__((section(".hexbss")));;
uint32_t blockLenMap[TOTALBLOCKS] __attribute__((section(".hexbss")));;
// NOTE This is linked at the end of program BSS section,
// so that it can be expanded without telling C how much
// it actually needs
uint8_t writeStoreBase[BLOCKSIZE] __attribute__((section(".bss.end")));
void HexEditor(uint8_t *path, VOLINFO *vi) {
uint8_t writeStoreBase[BLOCKSIZE] __attribute__((section(".hexlatebss")));
void HexEditor(char *path) {
uint32_t err;
uint16_t *vga_text = (uint16_t *)0xb8000;
uint32_t screenSize = 80*25;
uint8_t *scratch = (uint8_t *)0x20000;
uint8_t (*writeStore)[BLOCKSIZE] = &writeStoreBase;
for (int i = 0; i < TOTALBLOCKS; i++)
writtenMap[i] = 0;
@ -23,31 +23,39 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
// First two blocks are screen buffer
uint32_t nextFreeBlock = 2;
FILEINFO fi;
vga_text = (uint16_t *)0xb8000;
for (int i = 0; i < 80*50; i++)
vga_text[i] = 0x0f00;
err = DFS_OpenFile(vi, path, DFS_READ | DFS_WRITE, scratch, &fi);
dirent de;
err = path_getinfo(path, &de);
if (err) {
vga_text += printStr("Open Error: ", vga_text);
printDword(err, vga_text);
vga_text += printStr("Error getting file info.", vga_text);
kbd_wait();
return;
}
if (fi.filelen == 0) {
uint32_t filelen = de.size;
if (filelen == 0) {
vga_text += printStr("File ", vga_text);
vga_text += printStr((char*)path, vga_text);
vga_text += printStr(" has no data.", vga_text);
kbd_wait();
return;
}
if (fi.filelen > MAXFILESIZE) {
if (filelen > MAXFILESIZE) {
vga_text += printStr("File ", vga_text);
vga_text += printStr((char*)path, vga_text);
vga_text += printStr(" is too large (> 2GB).", vga_text);
kbd_wait();
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;
char cont = 1;
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.
// Scroll Back
if (cursorScreenOff < 0) {
if (drawOffset - 16 < fi.filelen)
if (drawOffset - 16 < filelen)
drawOffset -= 16;
cursorScreenOff += 16;
}
// Scroll Forward
if (cursorScreenOff >= byteCount) {
if (drawOffset + 16 < fi.filelen)
if (drawOffset + 16 < filelen)
drawOffset += 16;
cursorScreenOff -= 16;
}
@ -84,8 +92,8 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
// Sanity checks
if (cursorScreenOff >= byteCount)
cursorScreenOff = byteCount - 1;
if (cursorScreenOff + drawOffset >= fi.filelen)
cursorScreenOff = fi.filelen - drawOffset - 1;
if (cursorScreenOff + drawOffset >= filelen)
cursorScreenOff = filelen - drawOffset - 1;
if (cursorScreenOff < 0) cursorScreenOff = 0;
if (cursorNibble != lastCursorNibble)
@ -185,16 +193,14 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
} else {
uint32_t blockOffset = drawOffset & BLOCKMASK;
vga_text = &((uint16_t*)0xb8000)[80];
DFS_Seek(&fi, blockOffset, scratch);
if (fi.pointer != blockOffset) {
if (file_seek(&file, blockOffset)) {
vga_text += printStr("Seek Error", vga_text);
kbd_wait();
return;
}
err = DFS_ReadFile(&fi, scratch, screenBuff, &currBuffLength, BLOCKSIZE);
if (err && err != DFS_EOF) {
vga_text += printStr("Read Error: ", vga_text);
printDword(err, vga_text);
currBuffLength = file_read(&file, screenBuff, BLOCKSIZE);
if (!currBuffLength && blockOffset != filelen) {
vga_text += printStr("Read Error", vga_text);
kbd_wait();
return;
}
@ -222,16 +228,14 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
} else {
uint32_t blockOffset = (drawOffset & BLOCKMASK) + BLOCKSIZE;
vga_text = &((uint16_t*)0xb8000)[80];
DFS_Seek(&fi, blockOffset, scratch);
if (fi.pointer != blockOffset) {
if (file_seek(&file, blockOffset)) {
vga_text += printStr("Seek Error", vga_text);
kbd_wait();
return;
}
err = DFS_ReadFile(&fi, scratch, &screenBuff[BLOCKSIZE], &nextBuffLength, BLOCKSIZE);
if (err && err != DFS_EOF) {
vga_text += printStr("Read Error: ", vga_text);
printDword(err, vga_text);
nextBuffLength = file_read(&file, &screenBuff[BLOCKSIZE], BLOCKSIZE);
if (!nextBuffLength && blockOffset != filelen) {
vga_text += printStr("Read Error", vga_text);
kbd_wait();
return;
}
@ -244,11 +248,15 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
}
if (redraw) {
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";
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 = &((uint16_t*)0xb8000)[80];
@ -297,12 +305,12 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
switch (key & 0xff) {
case KEY_DOWN:
// Stay in file
if ((cursorScreenOff + 16 + drawOffset) < fi.filelen)
if ((cursorScreenOff + 16 + drawOffset) < filelen)
cursorScreenOff += 16;
break;
case KEY_UP:
// Stay in file
if ((uint32_t)(cursorScreenOff - 16 + drawOffset) < fi.filelen)
if ((uint32_t)(cursorScreenOff - 16 + drawOffset) < filelen)
cursorScreenOff -= 16;
break;
case KEY_LEFT:
@ -312,7 +320,7 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
cursorNibble = 0;
cursorScreenOff |= 0xF;
// Stay in file
} else if ((cursorScreenOff - 1 + drawOffset) < fi.filelen) {
} else if ((cursorScreenOff - 1 + drawOffset) < filelen) {
cursorScreenOff--;
if (cursorNibble == 1) cursorNibble = 0;
}
@ -324,19 +332,19 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
cursorNibble = 2;
cursorScreenOff &= ~0xF;
// Stay in file
} else if ((cursorScreenOff + 1 + drawOffset) < fi.filelen) {
} else if ((cursorScreenOff + 1 + drawOffset) < filelen) {
cursorScreenOff++;
if (cursorNibble == 0) cursorNibble = 1;
}
break;
case KEY_PGDOWN:
if (drawOffset + byteCount < fi.filelen)
if (drawOffset + byteCount < filelen)
drawOffset += byteCount;
else if ((fi.filelen / byteCount) * byteCount > drawOffset)
drawOffset = (fi.filelen / byteCount) * byteCount;
else if ((filelen / byteCount) * byteCount > drawOffset)
drawOffset = (filelen / byteCount) * byteCount;
break;
case KEY_PGUP:
if (drawOffset - byteCount < fi.filelen)
if (drawOffset - byteCount < filelen)
drawOffset -= byteCount;
else drawOffset = 0;
break;
@ -355,8 +363,8 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
drawOffset = 0;
break;
case KEY_F4: // end of file
if ((fi.filelen / byteCount) * byteCount > drawOffset)
drawOffset = (fi.filelen / byteCount) * byteCount;
if ((filelen / byteCount) * byteCount > drawOffset)
drawOffset = (filelen / byteCount) * byteCount;
break;
case KEY_F6: // TODO write file
break;
@ -407,8 +415,12 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
}
if (!fileChanged) return;
vga_text = (uint16_t*)0xb8000;
vga_text += printStr((char*)path, vga_text);
vga_text += printChar(fileChanged ? '*' : ' ', 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(' ', vga_text);
vga_text += printStr("Save changes to file? (Y/N)", 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());
if ((key & 0xff) != KEY_Y) return;
// 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
uint16_t blockIdx = writtenMap[i];
uint32_t blockLen = blockLenMap[i];
if (!blockIdx) continue;
// Write block to file
uint32_t successcount;
uint32_t blockOff = i << BLOCKSHIFT;
DFS_Seek(&fi, blockOff, scratch);
if (fi.pointer != blockOff) {
if (file_seek(&file, blockOff)) {
vga_text = (uint16_t*)0xb8000;
vga_text += printStr("Seek Error ", vga_text);
kbd_wait();
return;
}
uint32_t err = DFS_WriteFile(&fi, scratch, writeStore[blockIdx], &successcount, blockLen);
if (successcount < blockLen || err) {
uint32_t successcount = file_write(&file, writeStore[blockIdx], blockLen);
if (successcount < blockLen) {
vga_text = (uint16_t*)0xb8000;
vga_text += printStr("Write Error ", vga_text);
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 "v86defs.h"
#include "dosfs/dosfs.h"
#include "file.h"
void V8086Int(uint8_t interrupt, union V86Regs_t *regs);
@ -12,8 +12,6 @@ void SetVideo50Lines();
void SetCursorDisabled();
uint16_t *nextLine(uint16_t *p, uint16_t *b);
void trimPath(char *path, char *buff, uint32_t maxLen);
uint32_t OpenVol(VOLINFO *vi);
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);
void GetFileList(DIR *dir, dirent *entries, int32_t *entCount, int32_t maxEntries);

View File

@ -8,6 +8,6 @@ struct interrupt_frame {
uint32_t es, ds, fs, gs;
};
__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();

View File

@ -5,6 +5,9 @@
__attribute((__no_caller_saved_registers__))
void kbd_wait();
__attribute((__no_caller_saved_registers__))
void kbd_clear();
__attribute((__no_caller_saved_registers__))
uint8_t get_key();
@ -12,7 +15,7 @@ __attribute((__no_caller_saved_registers__))
uint16_t get_scancode();
__attribute__ ((interrupt))
void keyboardHandler(struct interrupt_frame *frame);
void keyboardHandler(struct interrupt_frame volatile *frame);
typedef enum {
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
#include "dosfs/dosfs.h"
#include "print.h"
#include "interrupt.h"
#include "v86defs.h"

View File

@ -14,6 +14,7 @@ extern void v86DiskReadCHS();
union __attribute((__packed__)) V86Regs_t {
struct dword_regs {
uint32_t ebp;
uint32_t edi;
uint32_t esi;
uint32_t ebx;
@ -22,6 +23,7 @@ union __attribute((__packed__)) V86Regs_t {
uint32_t eax;
} d;
struct word_regs {
uint16_t bp, _upper_bp;
uint16_t di, _upper_di;
uint16_t si, _upper_si;
uint16_t bx, _upper_bx;
@ -30,8 +32,9 @@ union __attribute((__packed__)) V86Regs_t {
uint16_t ax, _upper_ax;
} w;
struct byte_regs {
uint16_t di, _upper_di;
uint16_t si, _upper_si;
uint32_t ebp;
uint32_t edi;
uint32_t esi;
uint8_t bl, bh;
uint16_t _upper_bx;
uint8_t dl, dh;

View File

@ -90,19 +90,22 @@ void IRQ_clear_mask(char IRQline) {
outb(port, value);
}
// Mostly from https://web.archive.org/web/20090719085533/http://osdev.berlios.de/v86.html
char v86_if = 0;
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 jmp_usermode_test();
__attribute((__no_caller_saved_registers__))
__attribute__((__no_caller_saved_registers__))
__attribute__((__noreturn__))
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 uint32_t _gpf_eax_save;
#define VALID_FLAGS 0xDFF
__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));
uint8_t *ip;
uint16_t *stack;
@ -209,8 +212,9 @@ void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code) {
else
stack[2] &= ~EFLAG_IF;
frame->cs = ivt[ip[1] * 2 + 1];
frame->eip = ivt[ip[1] * 2];
asm volatile("xchg %bx,%bx");
frame->cs = IVT[ip[1] * 2 + 1];
frame->eip = IVT[ip[1] * 2];
break;
}
goto done;
@ -333,3 +337,11 @@ void setup_interrupts() {
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
" " // 0x39
"\0"; // 0x3A
uint8_t _KBDWAIT;
uint8_t _KEYCAPS = 0, _KEYSHIFT = 0;
uint8_t _LSTKEY_ASCII = 0, _LSTKEY_SCAN = 0;
volatile uint8_t _KBDWAIT;
volatile uint8_t _KEYCAPS = 0;
volatile uint8_t _KEYSHIFT = 0;
volatile uint8_t _LSTKEY_ASCII = 0;
volatile uint8_t _LSTKEY_SCAN = 0;
__attribute__ ((interrupt))
void keyboardHandler(struct interrupt_frame *frame) {
void keyboardHandler(struct interrupt_frame volatile *frame) {
uint16_t old_ds;
asm volatile(
"mov %%ds, %%bx\n"
@ -43,6 +45,7 @@ void keyboardHandler(struct interrupt_frame *frame) {
"mov %%ax, %%ds\n"
:"=b"(old_ds)::"%ax"
);
asm volatile("xchg %bx,%bx");
uint8_t key;
asm volatile("inb $0x60, %%al":"=a"(key));
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__))
void kbd_wait() {
_KBDWAIT = 0;

307
kernel.c
View File

@ -1,6 +1,7 @@
#include <stdint.h>
#include "dosfs/dosfs.h"
#include "file.h"
#include "fs.h"
#include "print.h"
#include "interrupt.h"
#include "kbd.h"
@ -10,6 +11,7 @@
#include "tests.h"
#include "progs.h"
#include "helper.h"
#include "disk.h"
typedef unsigned short word;
@ -63,15 +65,6 @@ uint32_t get_cr4() {
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;
void setup_binary() {
// Put V86 code in proper place based on linker
@ -80,26 +73,11 @@ void setup_binary() {
while (d < &_ev86code)
*d++ = *s++;
LoadUser();
// Clear BSS area
for (d = &_bstart; d < &_bend; d++)
*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
extern uint16_t *ivt;
@ -124,9 +102,19 @@ void ensure_v86env() {
*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();
__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) {
ensure_v86env();
setup_interrupts(); // just in case
@ -158,21 +146,24 @@ void error_environment(uint32_t stack0, uint32_t stack1, uint32_t stack2, uint32
for(;;) {
uint8_t key = get_scancode() & 0xff;
if (key == KEY_E) {
*(uint8_t*)0x800000 = 0x00;
v86_entry = i386LinearToFp(v86TransFlag);
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;
}
// reset error screen
for (int i = 0; i < (80*50)/2; i++)
((uint32_t*)error_screen)[i] = 0x0f000f00;
_ERRORCODE = -1;
return_prev_task();
}
uint32_t GetFreeStack() {
uint32_t stack;
asm volatile("mov %%esp,%%eax":"=a"(stack));
stack = ((stack - 0x4000) / 0x1000) * 0x1000;
stack = ((stack - 0x2000) / 0x1000) * 0x1000;
return stack;
}
@ -183,10 +174,11 @@ Real Mode Accessible (First MB)
01000 - 04000 Free (12kB)
04000 - 07C00 V86 Code (15kB)
07C00 - 08000 Boot & V86 Code (512B)
08000 - 20000 V86 Code (96kB)
08000 - 20000 Free (96kB)
20000 - 30000 Disk Buffer (64kB)
30000 - 80000 Free (320kB)
80000 - 90000 Real Mode Stack (64kB)
30000 - 40000 V86 Data (64kB)
40000 - 80000 Free (256kB)
80000 - 90000 V86 Stack (64kB)
90000 - A0000 Free (64kB)
A0000 - C0000 VGA (128kB)
C0000 - FFFFF BIOS Area (256kB)
@ -194,7 +186,9 @@ Protected Only (1MB+)
100000 - 200000 Kernel Code (1mB)
200000 - 200080 TSS (128B)
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)
300000 - 310000 Task Stack (64kB)
310000 - 320000 Interrupt Stack (64kB)
@ -202,6 +196,7 @@ Protected Only (1MB+)
400000 - 700000 Usermode Code (3mB)
700000 - 800000 Usermode Stack (1mB)
*/
void DrawScreen(uint16_t *vga) {
uint16_t *vga_text = vga;
// clear screen
@ -253,28 +248,29 @@ void RestoreVGA() {
SetPalette();
}
int32_t fileCount;
DIRENT *entries = (DIRENT*)0x400000;
int32_t fileCount, fileOffset;
// 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) {
uint16_t *vga_text = &((uint16_t *)vga)[80*6+3];
for (int i = 0; i < fileCount; i++) {
DIRENT *de = &entries[i];
for (int i = 0; i < 11 && de->name[i]; i++) {
if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3
*(uint8_t *)vga_text = de->name[i];
vga_text++;
}
for (int i = 0; (i + fileOffset) < fileCount && i < MAXDISPFILES; i++) {
dirent *de = &DirEntries[i + fileOffset];
de->name[de->namelen < 20 ? de->namelen : 20] = 0;
vga_text += printStr(de->name, 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);
vga_text += printDec(de->size, vga_text);
*(uint8_t*)vga_text++ = 'B';
vga_text = nextLine(vga_text, vga) + 3;
}
}
char IsDir(DIRENT *de) {
return de->attr & ATTR_DIRECTORY;
char IsDir(dirent *de) {
return de->type == FT_DIR;
}
void ScancodeTest() {
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, ...);
uint16_t FileSelectScreen[80*25];
char ValidFilesystems[256];
void FileSelect() {
uint8_t current_path[80];
ActiveFilesystemBitmap(ValidFilesystems);
uint8_t currentFsId = 0;
char current_path[80];
uintptr_t current_path_end;
for (int i = 0; i < sizeof(current_path); i++)
current_path[i] = 0;
current_path[0] = '/';
current_path_end = 1;
current_path[0] = '0';
current_path[1] = '/';
current_path_end = 2;
fileCount = 5;
uint16_t *vga_text = (uint16_t *)FileSelectScreen;
int32_t fileHovered = 0, lastFileHovered = 0;
int32_t fileHovered = 0;
fileOffset = 0;
for (char reload = 1;;) {
DrawScreen(vga_text);
// Info line (4)
@ -311,25 +312,33 @@ void FileSelect() {
vga += 80;
printStr("O to open directory", vga);
vga += 80;
printStr("S to switch volume", vga);
vga += 80;
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++)
*(uint8_t*)&vga_text[80*5 + i] = '-';
VOLINFO vi; DIRINFO di;
DIR dir;
if (reload) {
OpenVol(&vi);
current_path[current_path_end] = 0;
OpenDir(current_path, &vi, &di);
GetFileList(entries, &fileCount, &vi, &di);
dir_open(&dir, current_path);
GetFileList(&dir, DirEntries, &fileCount, INT32_MAX);
reload = 0;
}
PrintFileList(vga_text);
if (lastFileHovered != fileHovered) {
*(uint8_t*)&vga_text[80*(6+lastFileHovered)+2] = ' ';
lastFileHovered = fileHovered;
if (fileHovered >= fileCount) {
fileOffset = fileCount - MAXDISPFILES;
fileHovered = fileCount - 1;
}
*(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
for (int i = 0; i < 80*25; i++)
((uint16_t*)0xb8000)[i] = vga_text[i];
@ -338,7 +347,7 @@ void FileSelect() {
switch (key & 0xff) { // scancode component
case KEY_DOWN: // down
fileHovered++;
if (fileHovered >= fileCount) fileHovered = 0;
if (fileHovered >= fileCount) { fileHovered = 0; fileOffset = 0; }
break;
case KEY_UP: // up
fileHovered--;
@ -356,33 +365,46 @@ void FileSelect() {
reload = 1;
break;
case KEY_P:
if (IsDir(&entries[fileHovered])) break;
File83ToPath((char*)entries[fileHovered].name, (char*)&current_path[current_path_end]);
create_child(GetFreeStack(), (uintptr_t)ProgramLoadTest, 2, current_path, &vi);
if (IsDir(&DirEntries[fileHovered])) break;
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)ProgramLoadTest, 1, current_path);
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
break;
case KEY_X:
if (IsDir(&entries[fileHovered])) break;
File83ToPath((char*)entries[fileHovered].name, (char*)&current_path[current_path_end]);
ClearProgBss();
create_child(GetFreeStack(), (uintptr_t)HexEditor, 2, current_path, &vi);
if (IsDir(&DirEntries[fileHovered])) break;
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)HexEditor, 1, current_path);
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
break;
case KEY_T:
if (IsDir(&entries[fileHovered])) break;
File83ToPath((char*)entries[fileHovered].name, (char*)&current_path[current_path_end]);
if (IsDir(&DirEntries[fileHovered])) break;
//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();
reload = 1;
break;
case KEY_O:
case 0x9C: // enter release
if (IsDir(&entries[fileHovered])) {
if (IsDir(&DirEntries[fileHovered])) {
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)) {
// Current dir, do nothing
break;
@ -392,6 +414,7 @@ void FileSelect() {
current_path[current_path_end] = 0;
reload = 1;
fileHovered = 0;
fileOffset = 0;
break;
}
for (int i = 0; (i + current_path_end) < sizeof(current_path); i++)
@ -402,8 +425,28 @@ void FileSelect() {
current_path[current_path_end] = 0;
reload = 1;
fileHovered = 0;
fileOffset = 0;
}
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:
ScancodeTest();
reload = 1;
@ -414,17 +457,61 @@ void FileSelect() {
}
}
uint32_t kernel_check= 0x12345678;
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;
void start() {
word *vga_text = (word *)0xb8000;
char h[] = "LuciaOS";
char h[] = "ROSE";
for (int i = 0; i < sizeof(h); i++)
*(char *)&vga_text[i] = h[i];
vga_text = &vga_text[80];
// DL *should* be preserved
uint8_t dl;
asm volatile("nop":"=d"(dl));
uint16_t boot_dx;
asm volatile("nop":"=d"(boot_dx));
if (!check_cmov()) {
char cmov_err[] = "NO CMOV";
@ -433,7 +520,7 @@ void start() {
for (;;) asm volatile("hlt");
}
vga_text += printByte(dl, vga_text);
vga_text += printWord(boot_dx, vga_text);
vga_text++;
uint32_t o;
@ -460,46 +547,40 @@ void start() {
//vga_text += printStr("Y ", vga_text);
//enable_sse();
setup_binary();
// edit
setup_interrupts();
setup_tss();
init_paging();
//print_flags();
vga_text += printStr("CR0:", vga_text);
vga_text += printDword(get_cr0(), vga_text);
vga_text++;
//print_cr3();
//print_cr4();
backup_ivtbios();
//vga_text = &((word *)0xb8000)[160];
//vga_text += printStr("Press T for tests, or any key to continue... ", vga_text);
//uint8_t key = get_key();
//if (key == 't' || key == 'T')
// create_child(GetFreeStack(), (uintptr_t)RunTests, 0);
RestoreVGA();
DrawScreen((uint16_t*)0xb8000);
uint32_t stack;
asm volatile("mov %%esp,%%eax":"=a"(stack));
stack = ((stack - 0x4000) / 0x1000) * 0x1000;
for (;;) {
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;);
}
// 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();
vga_text += printStr("bkup...", vga_text);
vga_text++;
// DL contained disk number, DH contained active partition
uint8_t SystemPartition = boot_dx >> 8;
vga_text = &((uint16_t*)0xb8000)[160];
vga_text += printStr("Starting Shell...", vga_text);
create_child(GetFreeStack(), (uintptr_t)SystemRun, 1, SystemPartition);
// If this returns, something is *very* wrong, reboot the system
// TODO Maybe try to recover?
// Triple fault
triple_fault();
}

47
link.ld
View File

@ -2,13 +2,17 @@ OUTPUT_FORMAT(binary)
ENTRY(entry)
SECTIONS {
IVT = 0x00000;
. = 0x100000;
_USERMODE = 0x800000;
_USERMODE_END = 0x1000000;
.text : {
*(.text);
}
.data : {
*(.data*);
*(.data);
*(.rodata);
*(.rodata*);
@ -16,27 +20,34 @@ SECTIONS {
}
.realmode 0x4000 :
AT ( ADDR(.data) + SIZEOF(.data) )
AT ( _edata )
{ _v86code = .; *(.v86); _ev86code = .; }
. = 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);
. = _edata + SIZEOF(.realmode);
.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"
uint32_t page_directory[1024] __attribute__((aligned(4096)));
uint32_t first_page_table[1024] __attribute__((aligned(4096))); // 0x00000000 - 0x00400000
uint32_t second_page_table[1024] __attribute__((aligned(4096))); // 0x00400000 - 0x00800000
uint32_t page_tables[4][1024] __attribute__((aligned(4096)));
void enable_paging() {
asm(
@ -13,38 +12,52 @@ void enable_paging() {
::"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() {
for (int i = 0; i < 1024; i++)
// Supervisor, R/W, Not Present
page_directory[i] = 2;
// First Page Table
// 1024 Pages = 1MB
// First MB: Real Mode
{
int i;
// 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;
}
// TODO Make some of this not accessible to usermode?
map_pages(0x00000000 >> 12, 256, 0x00000000, USERACCESS);
// Next 3MB: Kernel
for (int i = 256; i < 1024; i++)
// Supervisor, R/W, Present
first_page_table[i] = (i * 0x1000) |2|1;
map_pages(0x00100000 >> 12, 768, 0x00100000, SUPERACCESS);
// Next 4MB: Kernel
map_pages(0x00400000 >> 12, 1024, 0x00400000, SUPERACCESS);
// Usermode Page Table
for (int i = 0; i < 1024; i++)
// User, R/W, Present
second_page_table[i] = (i * 0x1000 + 0x400000) |4|2|1;
// Next 8MB: Usermode
map_pages(0x00800000 >> 12, 1024, 0x00800000, USERACCESS);
map_pages(0x00C00000 >> 12, 1024, 0x00C00000, USERACCESS);
// User, R/W, Present
page_directory[0] = ((uintptr_t)first_page_table)|4|2|1;
page_directory[1] = ((uintptr_t)second_page_table)|4|2|1;
// We aren't using page directory permissions
for (int i = 0; i < 4; i++)
page_directory[i] = ((uintptr_t)&page_tables[i]) | USERACCESS;
enable_paging();
}

221
progs.c
View File

@ -1,224 +1,41 @@
#include "progs.h"
#include "helper.h"
#include "kbd.h"
#include "file.h"
void TextViewTest(uint8_t *path, VOLINFO *vi) {
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 char _USERMODE, _USERMODE_END;
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;
for (int i = 0; i < 80*25; i++)
vga_text[i] = 0x0f00;
uint32_t successcount;
uint8_t *diskReadBuf = (uint8_t *)0x400000;
uint8_t *diskReadBuf = (uint8_t *)&_USERMODE;
{
uint32_t err;
uint8_t *scratch = (uint8_t *)0x20000;
FILEINFO fi;
err = DFS_OpenFile(vi, path, DFS_READ, scratch, &fi);
dirent de;
err = path_getinfo(path, &de);
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) {
vga_text += printStr("Open Error: ", vga_text);
printDword(err, vga_text);
return;
}
if (fi.filelen > 0x300000) {
vga_text += printStr("File too large.", vga_text);
kbd_wait();
return;
}
DFS_Seek(&fi, 0, scratch);
if (fi.pointer != 0) {
err = file_seek(&file, 0);
if (err) {
vga_text += printStr("Seek Error", vga_text);
return;
}
err = DFS_ReadFile(&fi, scratch, diskReadBuf, &successcount, fi.filelen);
if (err && err != DFS_EOF) {
vga_text += printStr("Read Error: ", vga_text);
successcount = err = file_read(&file, diskReadBuf, de.size);
if (!err && de.size > 0) {
vga_text += printStr("Read Error", vga_text);
printDword(err, vga_text);
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((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 += printStr("Press any key to run.", vga_text);
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;
regs.w.ax = 3; // text mode
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
_enter_v86_internal_no_task:
mov ebp, esp ; save stack pointer
mov eax, dword [ebp+16] ; regs
test eax, eax
jz .no_regs
; load regs: edi, esi, ebx, edx, ecx, eax
mov edi, dword [eax+0]
mov esi, dword [eax+4]
mov ebx, dword [eax+8]
mov edx, dword [eax+12]
mov ecx, dword [eax+16]
mov eax, dword [eax+20]
.no_regs:
; push v86 stuff for iret
mov eax, 0x3000
push eax ; gs
push eax ; fs
push eax ; ds
push eax ; es
push dword [ebp+0] ; ss
push dword [ebp+4] ; esp
pushfd ; eflags
@ -170,6 +165,19 @@ or dword [esp], (1 << 17) ; set VM flags
;or dword [esp], (3 << 12) ; IOPL 3
push dword [ebp+8] ; cs
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
; return address in eax, return stack in ebp

View File

@ -1,5 +1,5 @@
[BITS 32]
[ORG 0x400000]
[ORG 0x800000]
xchg bx,bx
mov edi, 0xB8000
mov ecx, 80*25

306
tests.c
View File

@ -13,18 +13,21 @@ void TestV86() {
regs.d.eax = 0x66666666;
FARPTR v86_entry = i386LinearToFp(v86Test);
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() {
// Put Usermode code in proper place based on linker
char *s = &_loadusercode;
char *d = &_usercode;
while (d < &_eusercode)
char *s = &_binary_usermode_bin_start;
char *d = (char *)&_USERMODE;
while (s < &_binary_usermode_bin_end)
*d++ = *s++;
}
char TestUser() {
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) {
return 1;
}
@ -34,24 +37,40 @@ char TestUser() {
return 0;
}
void TestDiskRead() {
//vga_text += printStr("Starting Disk Read... ", vga_text);
union V86Regs_t regs;
char *diskReadBuf = (char *)0x20000;
v86disk_addr_packet.transfer_buffer =
(uintptr_t)diskReadBuf & 0x000F |
(((uintptr_t)diskReadBuf & 0xFFFF0) << 12);
regs.h.ah = 0x42;
FARPTR v86_entry = i386LinearToFp(v86DiskOp);
enter_v86(0x0000, 0x8000, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
uint16_t *vga_text = (uint16_t *)0xb8000;
for (int i = 0; i < (80*25)/2; i++) {
printByte(diskReadBuf[i], &vga_text[i*2]);
v86disk_addr_packet.transfer_buffer =
(uintptr_t)diskReadBuf & 0x000F |
(((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;
FARPTR v86_entry = i386LinearToFp(v86DiskOp);
enter_v86(0x0000, 0x8000, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
uint16_t *vga_text = (uint16_t *)0xb8000;
for (int i = 0; i < 25; i++) {
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_eflags_save;
void TestCHS() {
uint16_t *vga_text = (uint16_t*)0xb8000;
for (int i = 0; i < 80*25; i++)
vga_text[i] = 0x0f00;
printStr("CHS Test ", vga_text);
// CHS Read
union V86Regs_t regs;
@ -103,127 +122,150 @@ 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;
uint32_t pstart, psize;
pstart = DFS_GetPtnStart(0, diskReadBuf, 0, &pactive, &ptype, &psize);
vga_text = (uint16_t *)0xb8000;
vga_text += printStr("PartStart: ", vga_text);
vga_text += printDword(pstart, vga_text);
vga_text += 2;
vga_text += printStr("PartSize: ", vga_text);
vga_text += printDword(psize, vga_text);
vga_text += 2;
vga_text += printStr("PartActive: ", vga_text);
vga_text += printByte(pactive, vga_text);
vga_text += 2;
vga_text += printStr("PartType: ", vga_text);
vga_text += printByte(ptype, vga_text);
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
//asm ("xchgw %bx, %bx");
DFS_GetVolInfo(0, diskReadBuf, pstart, &vi);
vga_text += printStr("Label: ", vga_text);
vga_text += printStr((char*)vi.label, vga_text);
vga_text += 2;
vga_text += printStr("Sec/Clus: ", vga_text);
vga_text += printByte(vi.secperclus, vga_text);
vga_text += 2;
vga_text += printStr("ResrvSec: ", vga_text);
vga_text += printWord(vi.reservedsecs, vga_text);
vga_text += 2;
vga_text += printStr("NumSec: ", vga_text);
vga_text += printDword(vi.numsecs, vga_text);
vga_text += 2;
vga_text += printStr("Sec/FAT: ", vga_text);
vga_text += printDword(vi.secperfat, vga_text);
vga_text += 2;
vga_text += printStr("FAT1@: ", vga_text);
vga_text += printDword(vi.fat1, vga_text);
vga_text += 2;
vga_text += printStr("ROOT@: ", vga_text);
vga_text += printDword(vi.rootdir, vga_text);
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
//asm ("xchgw %bx, %bx");
vga_text += printStr("Files in root:", vga_text);
DIRINFO di;
di.scratch = diskReadBuf;
DFS_OpenDir(&vi, (uint8_t*)"", &di);
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
DIRENT de;
while (!DFS_GetNext(&vi, &di, &de)) {
if (de.name[0]) {
for (int i = 0; i < 11 && de.name[i]; i++) {
if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3
*(uint8_t *)vga_text = de.name[i];
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 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;
// uint32_t pstart, psize;
// pstart = DFS_GetPtnStart(0, diskReadBuf, SystemPartition, &pactive, &ptype, &psize);
// vga_text = (uint16_t *)0xb8000;
// vga_text += printStr("PartStart: ", vga_text);
// vga_text += printDword(pstart, vga_text);
// vga_text += 2;
// vga_text += printStr("PartSize: ", vga_text);
// vga_text += printDword(psize, vga_text);
// vga_text += 2;
// vga_text += printStr("PartActive: ", vga_text);
// vga_text += printByte(pactive, vga_text);
// vga_text += 2;
// vga_text += printStr("PartType: ", vga_text);
// vga_text += printByte(ptype, vga_text);
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
// //asm ("xchgw %bx, %bx");
//
// DFS_GetVolInfo(0, diskReadBuf, pstart, &vi);
// vga_text += printStr("Label: ", vga_text);
// vga_text += printStr((char*)vi.label, vga_text);
// vga_text += 2;
// vga_text += printStr("Sec/Clus: ", vga_text);
// vga_text += printByte(vi.secperclus, vga_text);
// vga_text += 2;
// vga_text += printStr("ResrvSec: ", vga_text);
// vga_text += printWord(vi.reservedsecs, vga_text);
// vga_text += 2;
// vga_text += printStr("NumSec: ", vga_text);
// vga_text += printDword(vi.numsecs, vga_text);
// vga_text += 2;
// vga_text += printStr("Sec/FAT: ", vga_text);
// vga_text += printDword(vi.secperfat, vga_text);
// vga_text += 2;
// vga_text += printStr("FAT1@: ", vga_text);
// vga_text += printDword(vi.fat1, vga_text);
// vga_text += 2;
// vga_text += printStr("ROOT@: ", vga_text);
// vga_text += printDword(vi.rootdir, vga_text);
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
// //asm ("xchgw %bx, %bx");
//
// vga_text += printStr("Files in root:", vga_text);
// DIRINFO di;
// di.scratch = diskReadBuf;
// DFS_OpenDir(&vi, (uint8_t*)"", &di);
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
// DIRENT de;
// while (!DFS_GetNext(&vi, &di, &de)) {
// if (de.name[0]) {
// for (int i = 0; i < 11 && de.name[i]; i++) {
// if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3
// *(uint8_t *)vga_text = de.name[i];
// 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() {
char doTests = 1;
uint16_t *vga_text = (uint16_t*)0xb8000;
for (int i = 0; i < 80*25; i++)
vga_text[i] = 0x1f00;
uint8_t key;
vga_text += printStr("V86 Test... ", vga_text);
//asm ("xchgw %bx, %bx");
TestV86(); // has int 3 wait in v86
vga_text = (uint16_t *)0xb8000 + (80*3);
vga_text += printStr("Done. Press 'N' for next test.", vga_text);
for(;;) {
key = get_key();
if (key == 'N' || key == 'n') break;
*vga_text = (*vga_text & 0xFF00) | key;
vga_text++;
}
char userResult = TestUser();
union V86Regs_t regs;
regs.w.ax = 3; // text mode
V8086Int(0x10, &regs);
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);
}
kbd_wait();
TestCHS();
kbd_wait();
TestDiskRead();
kbd_wait();
TestFAT();
for (char l = 1;l;) {
if (doTests) {
vga_text = (uint16_t*)0xb8000;
for (int i = 0; i < 80*25; i++)
vga_text[i] = 0x1f00;
vga_text += printStr("V86 Test... ", vga_text);
//asm ("xchgw %bx, %bx");
TestV86(); // has int 3 wait in v86
vga_text = (uint16_t *)0xb8000 + (80*3);
vga_text += printStr("Press 'N' for next test.", vga_text);
for(;;) {
key = get_key();
if (key == 'N' || key == 'n') break;
*vga_text = (*vga_text & 0xFF00) | key;
vga_text++;
}
if (TestUser()) {
union V86Regs_t regs;
regs.w.ax = 3; // text mode
V8086Int(0x10, &regs);
vga_text = (uint16_t *)0xb8000 + (80*5);
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;
}
vga_text = &((uint16_t*)0xB8000)[80*16];
vga_text += printStr("Press E for a flagrant system error. Press C to continue... ", vga_text);
for (char l = 1;l;) { switch (key = get_key()) {
case 'e':
case 'E':
// flagrant system error
*((uint8_t*)0x1000000) = 0;
break;
case 'c':
case 'C':
// continue
l = 0;
break;
default:
*vga_text = (*vga_text & 0xFF00) | key;
vga_text++;
break;
}}
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 += printStr("Press R to repeat tests. ", vga_text);
vga_text = &((uint16_t*)0xB8000)[80*17];
vga_text += printStr("Press C to continue... ", vga_text);
switch (key = get_key()) {
case 'e':
case 'E':
// flagrant system error
*((uint8_t*)0x1000000) = 0;
break;
case 'c':
case 'C':
// continue
l = 0;
break;
case 'd':
case 'D':
// disk tests
TestCHS();
kbd_wait();
TestDiskRead();
//TestFAT();
break;
case 'r':
case 'R':
doTests = 1;
break;
default:
*vga_text = (*vga_text & 0xFF00) | key;
vga_text++;
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
user_test:
mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16
@ -42,6 +43,7 @@ push 0x00000000 ; edx
push 0x00000000 ; ebx
push 0x00000000 ; esi
push 0x00000000 ; edi
push 0x00000000 ; ebp
push esp ; regs
push 0x10 ; interrupt
mov eax, 0x86 ; command = 86h, virtual 8086 call

192
v86.nasm
View File

@ -4,7 +4,83 @@ global v86Interrupt
v86Interrupt:
int 0x00
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:
xor cx, cx
@ -36,94 +112,48 @@ ret
global v86Test
v86Test:
mov ax, 0xb814
mov ax, (0xB8000 + (80*2)) >> 4
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
call real_printword
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
call real_printword
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
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
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
.testStr: db "PRESS ANY KEY"
.testStr_end:

Binary file not shown.