From 74d0e8c1f9527054a012aa9937c590537f9d3d5b Mon Sep 17 00:00:00 2001 From: Alejandro Sior Date: Fri, 20 May 2022 10:33:27 +0200 Subject: bios.call: clean and avoid hardcoding the gdt and idt when returning to long mode Do not make assumptions on the previous gdt and idt, as well as the state of the flags when operating. --- bios/bios.ha | 6 +--- drive/drive.ha | 19 ++++++------ rt/+x86_64/realcall.S | 81 +++++++++++++++++++++++++-------------------------- rt/+x86_64/stage0.s | 1 - 4 files changed, 50 insertions(+), 57 deletions(-) diff --git a/bios/bios.ha b/bios/bios.ha index afae0f6..aa69f8a 100644 --- a/bios/bios.ha +++ b/bios/bios.ha @@ -7,11 +7,7 @@ export type state = struct { @offset(12) edx: u32, @offset(16) edi: u32, @offset(20) esi: u32, - @offset(24) ds: u16, - @offset(26) es: u16, - @offset(28) ss: u16, - @offset(30) gs: u16, - @offset(32) fs: u16 + @offset(24) es: u16, }; // The set real mode registers diff --git a/drive/drive.ha b/drive/drive.ha index 42cef43..259e7f5 100644 --- a/drive/drive.ha +++ b/drive/drive.ha @@ -2,19 +2,20 @@ use bios; use bios::drive; fn lba_to_chs(lba: u16) (u16, u16, u16) = { - let temp = lba / bios::drive::drive_spt; - let sector = (lba % bios::drive::drive_spt) + 1; - let head = temp % bios::drive::drive_heads; - let cylinder = temp / bios::drive::drive_heads; + //let temp = lba / bios::drive::drive_spt; + //let sector = (lba % bios::drive::drive_spt) + 1; + //let head = temp % bios::drive::drive_heads; + //let cylinder = temp / bios::drive::drive_heads; - return (cylinder, head, sector); + //return (cylinder, head, sector); + return (0, 0, 0); }; export fn read(sector: u16, dest: uintptr) void = { let chs = lba_to_chs(sector); - bios::regs.eax = 1 | 0x2 << 8; - bios::regs.ebx = ws; - bios::regs.ecx = chs.2 | chs.0 << 8; - bios::regs.edx = bios::drive::drive_no | chs.1 << 8; + //bios::regs.eax = 1 | 0x2 << 8; + //bios::regs.ebx = ws; + //bios::regs.ecx = chs.2 | chs.0 << 8; + //bios::regs.edx = bios::drive::drive_no | chs.1 << 8; }; diff --git a/rt/+x86_64/realcall.S b/rt/+x86_64/realcall.S index 9e9afb4..ffbc0a9 100644 --- a/rt/+x86_64/realcall.S +++ b/rt/+x86_64/realcall.S @@ -14,18 +14,13 @@ redi: .int 0x0 resi: .int 0x0 -rds: - .short 0x0 res: .short 0x0 -rss: - .short 0x0 -rgs: - .short 0x0 -rfs: - .short 0x0 - +prev_idt: + .quad 0x0 +prev_gdt: + .quad 0x0 # :real_call # This function is intended to be called from long mode @@ -45,12 +40,25 @@ bios.call: push %r13 push %r14 push %r15 + pushf + + # :Save code segment (and second push to prepare for far return) + mov %cs, %ax + push %ax + push %ax + + # :Save data segment + mov %ds, %ax + push %ax + # :Save the interrupt number push %di cli + sidt (prev_idt) + sgdt (prev_gdt) - lgdt gdtr32 + lgdt (gdtr32) pushq $(gdt32_code - gdt32) pushq $real_call_to_pmode_down retfq @@ -92,15 +100,12 @@ real_call_to_16bits_rmode_down: mov %ax, %fs lidt bios_idtr - sti # :Self modifying code to call arbitrary interrupts pop %ax mov $real_call_int, %bx mov %al, 1(%bx) - push %ds - # :Load registers mov (reax), %eax mov (rebx), %ebx @@ -108,29 +113,22 @@ real_call_to_16bits_rmode_down: mov (redx), %edx mov (redi), %edi mov (resi), %esi - mov %ds:(res), %es - mov %ds:(rss), %ss - mov %ds:(rgs), %gs - mov %ds:(rfs), %fs - mov %ds:(rds), %ds - xchg %bx, %bx + mov (res), %es + + sti real_call_int: int $0x0 - - pop %ds - mov %ds:(rfs), %fs - mov %ds:(rgs), %gs - mov %ds:(rss), %ss - mov %ds:(res), %es + + cli + + mov %es, (res) mov %eax, (reax) mov %ebx, (rebx) mov %ecx, (recx) mov %edx, (redx) mov %edi, (redi) mov %esi, (resi) - - cli # :Restore protected mode mov %cr0, %eax @@ -157,33 +155,32 @@ real_call_to_pmode_up: or $1 << 31, %eax mov %eax, %cr0 - lgdt gdtr64 - ljmp $(gdt64_code - gdt64), $real_call_to_longmode_up + lgdt (prev_gdt) + + # :At this point %ds is latest in stack + pop %ax + + # :At this point %cs is latest in stack + # Do a long jump + push $real_call_to_longmode_up + retf .code64 real_call_to_longmode_up: - mov $(gdt64_data - gdt64), %ax mov %ax, %fs mov %ax, %gs mov %ax, %ss mov %ax, %es mov %ax, %ds + # :Avoid doing this until the bootloader loads a 64 bits IDT + # XXX + #idt (prev_idt) + real_call_end: + popf pop %r15 pop %r14 pop %r13 pop %r12 pop %rbx ret - -.globl testt -testt: - mov $1, %al - mov $0x43, %bh - mov $0x6, %ah - mov $0, %ch - mov $0, %cl - mov $5, %dh - mov $5, %dl - int $0x10 - ret diff --git a/rt/+x86_64/stage0.s b/rt/+x86_64/stage0.s index e17c06b..2961a10 100644 --- a/rt/+x86_64/stage0.s +++ b/rt/+x86_64/stage0.s @@ -89,5 +89,4 @@ bios_idtr: .org 510 .word 0xaa55 - .include "rt/+x86_64/stage1.S" -- cgit v1.2.3