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
# no floppyb
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
ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15
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
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:
;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
@ -39,15 +39,41 @@ mov eax, cr0 ; set pmode bit
or al, 1
mov cr0, eax
jmp 08h:Pmode
no_exten:
; read with CHS
; FIXME This only reads up to sector count
mov ah,8
int 0x13 ; geometry
and cx, 0x3f
push cx
push 0x0080 ; DH=head,DL=disk
push 0x2000 ; buffer seg
push 2 ; sector
.loop:
mov ax, [esp]
push 0xb800
pop es
xor di,di
call hexprint
mov ax, [esp+2]
mov es, ax
mov ax, 0x0201
mov cx, [esp]
xor bx,bx
mov dx, [esp+4]
int 0x13
jc err
add word [esp+2], 0x20
mov cx, [esp]
inc cl
mov [esp], cx
cmp cl, [esp+6]
jg entry
jmp .loop
err:
mov bx, ax
mov si, 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:
push 0xb800
pop es
@ -57,9 +83,9 @@ err_print:
lodsb
stosw
loop err_print
add di, 2
mov ax, bx
call hexprint
;add di, 2
;mov ax, bx
;call hexprint
hlt_loop:
hlt
jmp hlt_loop
@ -100,20 +126,57 @@ mov [esi], esi
mov [edi], edi
cmpsd
jne .kernel
in al, 0x92 ; fast A20
test al, 2
jnz .fa20_end
or al, 2
and al, 0xFE
out 0x92, al
.fa20_end:
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 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 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
@ -134,12 +197,12 @@ 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 0x0800 ; transfer buffer segment
addr_packet_transfer_buff_seg: dw 0x2000 ; transfer buffer segment
addr_packet_start_block: dq 1 ; start block

View File

@ -11,7 +11,17 @@
#include "dosfs.h"
#include "tmpstring.c"
#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) {
// NOTE If the buffer provided is outside the 0x20000-0x2FE00 range,
// 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;
if ((uintptr_t)v86buf < 0x20000 || (uintptr_t)v86buf > 0x2FE00)
v86buf = (uint8_t *)0x20000;
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);
// TODO This check should probably happen at the kernel level
if (useCHS == -1) {
union V86Regs_t regs;
// Check for INT 13 Extensions support
regs.h.ah = 0x41;
regs.w.bx = 0x55AA;
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)
memcpy(buffer, v86buf, count * SECTOR_SIZE);
return 0;

View File

@ -1,5 +1,8 @@
global 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
jmp 08h:Pmodecode
@ -19,9 +22,19 @@ mov eax, 0x1f001f00
mov ecx, (80*25)/2
mov edi, 0xb8000
rep stosd ; clear screen
mov eax, dword [kernel_check]
cmp eax, 0x12345678
jne err
call start
hlt_loop:
hlt
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 kernel_check

View File

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

View File

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

View File

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

70
tests.c
View File

@ -34,23 +34,74 @@ char TestUser() {
return 0;
}
void TestDiskRead() {
//vga_text += printStr("Starting Disk Read... ", vga_text);
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;
v86disk_addr_packet.transfer_buffer =
(uintptr_t)diskReadBuf & 0x000F |
(((uintptr_t)diskReadBuf & 0xFFFF0) << 12);
FARPTR v86_entry = i386LinearToFp(v86DiskRead);
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++) {
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() {
uint16_t *vga_text = (uint16_t *)0xb8000;
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);
}
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();
kbd_wait();
TestFAT();

View File

@ -108,3 +108,23 @@ 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

View File

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