Preliminary support for CHS disks.

This commit is contained in:
Lucia Ceionia 2023-02-08 10:33:49 -06:00
parent d1f1bfa974
commit 6a4c1908bb
10 changed files with 261 additions and 44 deletions

View File

@ -11,7 +11,7 @@ floppy_bootsig_check: disabled=0
floppya: type=none floppya: type=none
# no floppyb # no floppyb
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path="virtdisk.bin", mode=flat, cylinders=2, heads=16, spt=63, sect_size=512, model="Generic 1234", biosdetect=auto, translation=auto ata0-master: type=disk, path="virtdisk.bin", mode=flat, cylinders=8, heads=16, spt=63, sect_size=512, model="Generic 1234", biosdetect=auto, translation=auto
ata0-slave: type=none ata0-slave: type=none
ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15 ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata1-master: type=none ata1-master: type=none

117
boot.nasm
View File

@ -23,14 +23,14 @@ add word [addr_packet_transfer_buff_seg], (secreadcnt*512)/16
add word [addr_packet_start_block], secreadcnt add word [addr_packet_start_block], secreadcnt
loop read_loop loop read_loop
entry: entry:
mov ax,0x2403 ; A20 BIOS Support ;mov ax,0x2403 ; A20 BIOS Support
int 0x15 ;int 0x15
jb .no_a20 ;jb .no_a20
cmp ah,0 ;cmp ah,0
jnz .no_a20 ;jnz .no_a20
mov ax,0x2401 ; A20 BIOS Activate ;mov ax,0x2401 ; A20 BIOS Activate
int 0x15 ;int 0x15
.no_a20: ;.no_a20:
cli ; no interrupts cli ; no interrupts
xor ax,ax xor ax,ax
mov ds, ax mov ds, ax
@ -39,15 +39,41 @@ mov eax, cr0 ; set pmode bit
or al, 1 or al, 1
mov cr0, eax mov cr0, eax
jmp 08h:Pmode jmp 08h:Pmode
no_exten:
; read with CHS
; FIXME This only reads up to sector count
mov ah,8
int 0x13 ; geometry
and cx, 0x3f
push cx
push 0x0080 ; DH=head,DL=disk
push 0x2000 ; buffer seg
push 2 ; sector
.loop:
mov ax, [esp]
push 0xb800
pop es
xor di,di
call hexprint
mov ax, [esp+2]
mov es, ax
mov ax, 0x0201
mov cx, [esp]
xor bx,bx
mov dx, [esp+4]
int 0x13
jc err
add word [esp+2], 0x20
mov cx, [esp]
inc cl
mov [esp], cx
cmp cl, [esp+6]
jg entry
jmp .loop
err: err:
mov bx, ax mov bx, ax
mov si, string mov si, string
mov cx, string_end - string mov cx, string_end - string
jmp print
no_exten:
mov bx, ax
mov si, no_exten_str
mov cx, no_exten_str_end - no_exten_str
print: print:
push 0xb800 push 0xb800
pop es pop es
@ -57,9 +83,9 @@ err_print:
lodsb lodsb
stosw stosw
loop err_print loop err_print
add di, 2 ;add di, 2
mov ax, bx ;mov ax, bx
call hexprint ;call hexprint
hlt_loop: hlt_loop:
hlt hlt
jmp hlt_loop jmp hlt_loop
@ -100,20 +126,57 @@ mov [esi], esi
mov [edi], edi mov [edi], edi
cmpsd cmpsd
jne .kernel jne .kernel
in al, 0x92 ; fast A20 call enable_A20
test al, 2 ;in al, 0x92 ; fast A20
jnz .fa20_end ;test al, 2
or al, 2 ;jnz .fa20_end
and al, 0xFE ;or al, 2
out 0x92, al ;and al, 0xFE
.fa20_end: ;out 0x92, al
;.fa20_end:
jmp .a20 jmp .a20
.kernel: .kernel:
mov esi, 0x8000 ;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 edi, 0x100000
mov ecx, 0x10000 mov ecx, 0x10000
rep movsb rep movsb
jmp 08h:0x100000 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: gdt_desc:
dw gdt_end - gdt dw gdt_end - gdt
@ -134,12 +197,12 @@ gdt_end:
string: db 'DISK ERROR' string: db 'DISK ERROR'
string_end: string_end:
no_exten_str: db 'NO INT13 EXTEN' ;no_exten_str: db 'NO INT13 EXTEN'
no_exten_str_end: ;no_exten_str_end:
addr_packet: addr_packet:
db 0x10, 0x00 ; size, reserved db 0x10, 0x00 ; size, reserved
dw secreadcnt ; blocks dw secreadcnt ; blocks
addr_packet_transfer_buff_off: dw 0x0000 ; transfer buffer offset addr_packet_transfer_buff_off: dw 0x0000 ; transfer buffer offset
addr_packet_transfer_buff_seg: dw 0x0800 ; transfer buffer segment addr_packet_transfer_buff_seg: dw 0x2000 ; transfer buffer segment
addr_packet_start_block: dq 1 ; start block addr_packet_start_block: dq 1 ; start block

View File

@ -11,7 +11,17 @@
#include "dosfs.h" #include "dosfs.h"
#include "tmpstring.c" #include "tmpstring.c"
#include "../v86defs.h" #include "../v86defs.h"
#include "../print.h"
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__))
extern void error_environment(); // defined in kernel.c
uint32_t numHead;
uint32_t secPerTrack;
uint32_t maxCylinder;
char useCHS = -1;
uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) { 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, // NOTE If the buffer provided is outside the 0x20000-0x2FE00 range,
// the function will use that buffer for the Virtual 8086 process // the function will use that buffer for the Virtual 8086 process
@ -19,14 +29,61 @@ uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t
uint8_t *v86buf = buffer; uint8_t *v86buf = buffer;
if ((uintptr_t)v86buf < 0x20000 || (uintptr_t)v86buf > 0x2FE00) if ((uintptr_t)v86buf < 0x20000 || (uintptr_t)v86buf > 0x2FE00)
v86buf = (uint8_t *)0x20000; v86buf = (uint8_t *)0x20000;
v86disk_addr_packet.start_block = sector;
v86disk_addr_packet.blocks = count; // TODO This check should probably happen at the kernel level
v86disk_addr_packet.transfer_buffer = if (useCHS == -1) {
(uintptr_t)v86buf & 0x000F | union V86Regs_t regs;
(((uintptr_t)v86buf & 0xFFFF0) << 12); // Check for INT 13 Extensions support
union V86Regs_t regs; regs.h.ah = 0x41;
FARPTR v86_entry = i386LinearToFp(v86DiskRead); regs.w.bx = 0x55AA;
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs); regs.h.dl = 0x80;
V8086Int(0x13, &regs);
// LBA supported if CF clear
if (!(_gpf_eflags_save & 0x1)) {
useCHS = 0;
} else {
FARPTR v86_entry = i386LinearToFp(v86DiskGetGeometry);
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
// check CF for error
if (_gpf_eflags_save & 0x1) {
uint16_t *vga = error_screen;
vga += printStr("Could not get Disk Geometry.", vga);
error_environment();
for(;;);
}
numHead = ((_gpf_eax_save & 0xff00) >> 8) + 1;
secPerTrack = _gpf_eax_save & 0x3f;
maxCylinder = ((_gpf_eax_save & 0xff0000) >> 16) | ((_gpf_eax_save & 0xc0) << 2);
useCHS = 1;
}
}
// TODO Do error handling
if (!useCHS) {
// LBA Read
v86disk_addr_packet.start_block = sector;
v86disk_addr_packet.blocks = count;
v86disk_addr_packet.transfer_buffer =
(uintptr_t)v86buf & 0x000F |
(((uintptr_t)v86buf & 0xFFFF0) << 12);
union V86Regs_t regs;
FARPTR v86_entry = i386LinearToFp(v86DiskRead);
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
} else {
uint32_t tmp = sector / secPerTrack;
uint32_t sec = (sector % (secPerTrack)) + 1;
uint32_t head = tmp % numHead;
uint32_t cyl = tmp / numHead;
union V86Regs_t regs;
regs.w.ax = 0x0201;
regs.h.ch = cyl & 0xff;
regs.h.cl = sec | ((cyl >> 2) & 0xc0);
regs.h.dh = head;
regs.h.dl = 0x80;
regs.w.bx = (uintptr_t)v86buf & 0xFFFF;
FARPTR v86_entry = i386LinearToFp(v86DiskReadCHS);
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
}
if (v86buf != buffer) if (v86buf != buffer)
memcpy(buffer, v86buf, count * SECTOR_SIZE); memcpy(buffer, v86buf, count * SECTOR_SIZE);
return 0; return 0;

View File

@ -1,5 +1,8 @@
global entry global entry
entry: entry:
mov dword [0xb8000], 0x07000700 | 'E' | 'N' << 16
mov dword [0xb8004], 0x07000700 | 'T' | 'R' << 16
mov dword [0xb8008], 0x07000700 | 'Y' | ' ' << 16
lgdt [gdt_desc] ; load gdt register lgdt [gdt_desc] ; load gdt register
jmp 08h:Pmodecode jmp 08h:Pmodecode
@ -19,9 +22,19 @@ mov eax, 0x1f001f00
mov ecx, (80*25)/2 mov ecx, (80*25)/2
mov edi, 0xb8000 mov edi, 0xb8000
rep stosd ; clear screen rep stosd ; clear screen
mov eax, dword [kernel_check]
cmp eax, 0x12345678
jne err
call start call start
hlt_loop: hlt_loop:
hlt hlt
jmp hlt_loop jmp hlt_loop
err:
mov dword [0xb8000], 0x07000700 | 'L' | 'O' << 16
mov dword [0xb8004], 0x07000700 | 'A' | 'D' << 16
mov dword [0xb8008], 0x07000700 | 'F' | 'A' << 16
mov dword [0xb800C], 0x07000700 | 'I' | 'L' << 16
jmp hlt_loop
extern start extern start
extern kernel_check

View File

@ -24,6 +24,8 @@ jmp .hlt
global _gpf_eax_save global _gpf_eax_save
_gpf_eax_save: dd 0 _gpf_eax_save: dd 0
global _gpf_eflags_save
_gpf_eflags_save: dd 0
extern gpf_handler_v86 extern gpf_handler_v86
global gpfHandler global gpfHandler
gpfHandler: gpfHandler:
@ -52,6 +54,7 @@ pop ecx
pop ebx pop ebx
sti ; we shouldn't crash now? sti ; we shouldn't crash now?
mov eax, dword [esp+16] ; EFLAGS mov eax, dword [esp+16] ; EFLAGS
mov dword [_gpf_eflags_save], eax ; save
and eax, 1 << 17 ; VM flag and eax, 1 << 17 ; VM flag
test eax, eax test eax, eax
pop eax pop eax

View File

@ -297,6 +297,7 @@ void FileSelect() {
} }
} }
uint32_t kernel_check= 0x12345678;
void start() { void start() {
word *vga_text = (word *)0xb8000; word *vga_text = (word *)0xb8000;
char h[] = "LuciaOS"; char h[] = "LuciaOS";

View File

@ -4,11 +4,11 @@ ENTRY(entry)
SECTIONS { SECTIONS {
. = 0x100000; . = 0x100000;
.text : ALIGN(0x1000) { .text : {
*(.text); *(.text);
} }
.data : ALIGN(0x1000) { .data : {
*(.data); *(.data);
*(.rodata); *(.rodata);
*(.rodata*); *(.rodata*);

70
tests.c
View File

@ -34,23 +34,74 @@ char TestUser() {
return 0; return 0;
} }
void TestDiskRead() { void TestDiskRead() {
//vga_text += printStr("Starting Disk Read... ", vga_text);
union V86Regs_t regs; union V86Regs_t regs;
uint16_t *vga_text = (uint16_t *)0xb8000 + (80*5);
vga_text += printStr("Setting Text Mode... ", vga_text);
regs.w.ax = 3; // text mode
V8086Int(0x10, &regs);
//vga_text += printStr("Done. Starting Disk Read... ", vga_text);
char *diskReadBuf = (char *)0x20000; char *diskReadBuf = (char *)0x20000;
v86disk_addr_packet.transfer_buffer = v86disk_addr_packet.transfer_buffer =
(uintptr_t)diskReadBuf & 0x000F | (uintptr_t)diskReadBuf & 0x000F |
(((uintptr_t)diskReadBuf & 0xFFFF0) << 12); (((uintptr_t)diskReadBuf & 0xFFFF0) << 12);
FARPTR v86_entry = i386LinearToFp(v86DiskRead); FARPTR v86_entry = i386LinearToFp(v86DiskRead);
enter_v86(0x0000, 0x8000, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs); enter_v86(0x0000, 0x8000, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
vga_text = (uint16_t *)0xb8000; uint16_t *vga_text = (uint16_t *)0xb8000;
for (int i = 0; i < (80*25)/2; i++) { for (int i = 0; i < (80*25)/2; i++) {
printByte(diskReadBuf[i], &vga_text[i*2]); printByte(diskReadBuf[i], &vga_text[i*2]);
} }
} }
extern uint32_t _gpf_eax_save;
extern uint32_t _gpf_eflags_save;
void TestCHS() {
uint16_t *vga_text = (uint16_t*)0xb8000;
printStr("CHS Test ", vga_text);
// CHS Read
union V86Regs_t regs;
FARPTR v86_entry = i386LinearToFp(v86DiskGetGeometry);
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
// check CF for error
if (_gpf_eflags_save & 0x1) {
uint16_t *vga = &((uint16_t*)0xb8000)[80];
vga += printStr("Could not get Disk Geometry.", vga);
return;
}
uint32_t numHead = ((_gpf_eax_save & 0xff00) >> 8) + 1;
uint32_t secPerTrack = _gpf_eax_save & 0x3f;
uint32_t maxCyl = ((_gpf_eax_save & 0xff0000) >> 16) | ((_gpf_eax_save & 0xc0) << 2);
uint32_t maxLBA = numHead * secPerTrack * (maxCyl + 1);
for (uint32_t sector = 0; sector < maxLBA && sector < 0x8000 /* don't bother reading huge disks */; sector += (sector + secPerTrack < maxLBA) ? secPerTrack : 1) {
uint16_t *vga = &((uint16_t*)0xb8000)[9];
vga += printWord(sector, vga); vga++;
// LBA -> CHS
uint32_t tmp = sector / secPerTrack;
uint32_t sec = (sector % (secPerTrack)) + 1;
uint32_t head = tmp % numHead;
uint32_t cyl = tmp / numHead;
vga += printWord(cyl, vga); vga += printChar(':', vga);
vga += printByte(head, vga); vga += printChar(':', vga);
vga += printByte(sec, vga); vga += printChar(' ', vga);
vga += printStr("/ ", vga);
vga += printWord(maxCyl, vga); vga += printChar(':', vga);
vga += printByte(numHead - 1, vga); vga += printChar(':', vga);
vga += printByte(secPerTrack, vga); vga += printChar(' ', vga);
regs.w.ax = 0x0201;
regs.h.ch = cyl & 0xff;
regs.h.cl = sec | ((cyl >> 2) & 0xc0);
regs.h.dh = head;
regs.h.dl = 0x80;
regs.w.bx = 0x0000;
v86_entry = i386LinearToFp(v86DiskReadCHS);
enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), &regs);
// if CF was set, we have error
if (_gpf_eflags_save & 0x1) {
uint16_t *vga = &((uint16_t*)0xb8000)[80];
vga += printStr("Disk Error: ", vga);
vga += printByte(_gpf_eax_save & 0xff, vga);
vga += printStr(" CHS=", vga);
vga += printWord(cyl, vga); vga += printChar(':', vga);
vga += printByte(head, vga); vga += printChar(':', vga);
vga += printByte(sec, vga);
return;
}
}
}
void TestFAT() { void TestFAT() {
uint16_t *vga_text = (uint16_t *)0xb8000; uint16_t *vga_text = (uint16_t *)0xb8000;
uint8_t *diskReadBuf = (uint8_t *)0x22400; uint8_t *diskReadBuf = (uint8_t *)0x22400;
@ -144,6 +195,13 @@ void RunTests() {
vga_text += printStr("Usermode test failed! Press any key to continue.", vga_text); vga_text += printStr("Usermode test failed! Press any key to continue.", vga_text);
} }
kbd_wait(); kbd_wait();
union V86Regs_t regs;
vga_text = (uint16_t *)0xb8000 + (80*5);
vga_text += printStr("Setting Text Mode... ", vga_text);
regs.w.ax = 3; // text mode
V8086Int(0x10, &regs);
TestCHS();
kbd_wait();
TestDiskRead(); TestDiskRead();
kbd_wait(); kbd_wait();
TestFAT(); TestFAT();

View File

@ -108,3 +108,23 @@ db 0x10, 0x00 ; size, reserved
dw 0x1 ; blocks dw 0x1 ; blocks
dd 0x23000000 ; transfer buffer 0x23000 dd 0x23000000 ; transfer buffer 0x23000
dq 0x1 ; start block 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

View File

@ -9,6 +9,8 @@ extern void v86TransFlag();
extern void v86Interrupt(); extern void v86Interrupt();
extern void v86TextMode(); extern void v86TextMode();
extern void v86DiskRead(); extern void v86DiskRead();
extern void v86DiskGetGeometry();
extern void v86DiskReadCHS();
union __attribute((__packed__)) V86Regs_t { union __attribute((__packed__)) V86Regs_t {
struct dword_regs { struct dword_regs {