From 6a4c1908bb69dd3b8bdfbf05f05bf47d68b7cb33 Mon Sep 17 00:00:00 2001 From: Lucia Ceionia Date: Wed, 8 Feb 2023 10:33:49 -0600 Subject: [PATCH] Preliminary support for CHS disks. --- bochsrc | 2 +- boot.nasm | 117 ++++++++++++++++++++++++++++++++++++++------------ dosfs/dosfs.c | 73 +++++++++++++++++++++++++++---- entry.nasm | 13 ++++++ fault.nasm | 3 ++ kernel.c | 1 + link.ld | 4 +- tests.c | 70 +++++++++++++++++++++++++++--- v86.nasm | 20 +++++++++ v86defs.h | 2 + 10 files changed, 261 insertions(+), 44 deletions(-) diff --git a/bochsrc b/bochsrc index f496470..52e59c2 100644 --- a/bochsrc +++ b/bochsrc @@ -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 diff --git a/boot.nasm b/boot.nasm index 897e5a3..42384bf 100644 --- a/boot.nasm +++ b/boot.nasm @@ -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 diff --git a/dosfs/dosfs.c b/dosfs/dosfs.c index 74d15ed..f9bccea 100755 --- a/dosfs/dosfs.c +++ b/dosfs/dosfs.c @@ -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), ®s); + + // 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, ®s); + // 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), ®s); + // 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), ®s); + } 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), ®s); + } if (v86buf != buffer) memcpy(buffer, v86buf, count * SECTOR_SIZE); return 0; diff --git a/entry.nasm b/entry.nasm index e7d439c..41c1f8b 100644 --- a/entry.nasm +++ b/entry.nasm @@ -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 diff --git a/fault.nasm b/fault.nasm index 9affccd..cf2ef21 100644 --- a/fault.nasm +++ b/fault.nasm @@ -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 diff --git a/kernel.c b/kernel.c index e9fc16d..ead2cf1 100644 --- a/kernel.c +++ b/kernel.c @@ -297,6 +297,7 @@ void FileSelect() { } } +uint32_t kernel_check= 0x12345678; void start() { word *vga_text = (word *)0xb8000; char h[] = "LuciaOS"; diff --git a/link.ld b/link.ld index c175a20..d708308 100644 --- a/link.ld +++ b/link.ld @@ -4,11 +4,11 @@ ENTRY(entry) SECTIONS { . = 0x100000; - .text : ALIGN(0x1000) { + .text : { *(.text); } - .data : ALIGN(0x1000) { + .data : { *(.data); *(.rodata); *(.rodata*); diff --git a/tests.c b/tests.c index a556435..a1b37cd 100644 --- a/tests.c +++ b/tests.c @@ -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, ®s); - //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), ®s); - 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), ®s); + // 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), ®s); + // 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, ®s); + TestCHS(); + kbd_wait(); TestDiskRead(); kbd_wait(); TestFAT(); diff --git a/v86.nasm b/v86.nasm index 4ec03c3..818e893 100644 --- a/v86.nasm +++ b/v86.nasm @@ -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 diff --git a/v86defs.h b/v86defs.h index 0b409e3..e3cf4a2 100644 --- a/v86defs.h +++ b/v86defs.h @@ -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 {