summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Sior <aho@sior.be>2022-05-20 10:33:27 +0200
committerAlejandro Sior <aho@sior.be>2022-05-20 10:33:27 +0200
commit74d0e8c1f9527054a012aa9937c590537f9d3d5b (patch)
treea83448feac9e803c3844ba8eb8137aef8c26239d
parent776a3710652f78b44718450406d0683974aef72a (diff)
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.
-rw-r--r--bios/bios.ha6
-rw-r--r--drive/drive.ha19
-rw-r--r--rt/+x86_64/realcall.S81
-rw-r--r--rt/+x86_64/stage0.s1
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"