summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bios/bios.ha41
-rw-r--r--bios/drive/+x86_64/drive.s7
-rw-r--r--bios/drive/drive.ha5
-rw-r--r--drive/drive.ha20
-rw-r--r--main.ha17
-rw-r--r--real/real.ha22
-rw-r--r--rt/+x86_64/realcall.S74
-rw-r--r--rt/+x86_64/stage0.s1
-rw-r--r--rt/+x86_64/stage0_drive.S3
-rw-r--r--rt/hare.sc2
10 files changed, 139 insertions, 53 deletions
diff --git a/bios/bios.ha b/bios/bios.ha
new file mode 100644
index 0000000..afae0f6
--- /dev/null
+++ b/bios/bios.ha
@@ -0,0 +1,41 @@
+// Struct defining the contents of the register state used
+// for bios calls
+export type state = struct {
+ @offset(0) eax: u32,
+ @offset(4) ebx: u32,
+ @offset(8) ecx: u32,
+ @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
+};
+
+// The set real mode registers
+export let regs: state;
+
+// The address of a 512 bytes workspace that is located below 0xFFFFF and can be used to store the results
+// of various bios calls
+export const @symbol("_ws") ws: u16;
+
+// The boot drive number as given by the BIOS at boot time
+export const @symbol("drive_no") drive_number: u8;
+
+// The amount of sectors per track that the boot drive has
+export const @symbol("drive_spt") drive_sectors_per_track: u8;
+
+// The amount of heads that the boot drive has
+export const @symbol("drive_heads") drive_heads: u8;
+
+// Clears the BIOS mode registers
+export fn clearregs() void = {
+ regs = state {
+ ...
+ };
+};
+
+// Call a BIOS interrupt
+export fn call(intno: u8) void;
diff --git a/bios/drive/+x86_64/drive.s b/bios/drive/+x86_64/drive.s
new file mode 100644
index 0000000..1f3828e
--- /dev/null
+++ b/bios/drive/+x86_64/drive.s
@@ -0,0 +1,7 @@
+.code16
+
+.globl bios.drive.read
+bios.drive.read:
+ mov $0x2, %ah
+ int $0x13
+ ret
diff --git a/bios/drive/drive.ha b/bios/drive/drive.ha
new file mode 100644
index 0000000..35cccca
--- /dev/null
+++ b/bios/drive/drive.ha
@@ -0,0 +1,5 @@
+export let @symbol("drive_no") drive_no: u8;
+export let @symbol("drive_spt") drive_spt: u8;
+export let @symbol("drive_heads") drive_heads: u8;
+
+export fn read() void;
diff --git a/drive/drive.ha b/drive/drive.ha
new file mode 100644
index 0000000..42cef43
--- /dev/null
+++ b/drive/drive.ha
@@ -0,0 +1,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;
+
+ return (cylinder, head, sector);
+};
+
+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;
+};
diff --git a/main.ha b/main.ha
index edd4607..e5b2e7c 100644
--- a/main.ha
+++ b/main.ha
@@ -1,22 +1,23 @@
use vga;
use term;
use rt;
-use real;
+use bios;
+use bios::drive;
+use drive;
export fn main() void = {
let text = vga::attach(0xb8000, 80, 25);
term::clear(&text);
term::setcolors(&text, (term::color::LMAGENTA, term::color::BLACK));
- term::print(&text, "hello hare world!");
+ term::print(&text, "hello hare world!\n");
for (let i = 0z; i < 10; i += 1) {
term::print(&text, "a");
- for (let j = 0z; j < 10000000; j += 1) {
- yield;
- };
};
- real::regs.edi = 0;
- real::regs.esi = 0x7c00;
- real::call((&real::testt): uintptr: u16);
+ bios::regs.eax = 6 << 8 | 1;
+ bios::regs.ebx = 0x43 << 8;
+ bios::regs.ecx = 0;
+ bios::regs.edx = 5 << 8 | 5;
+ bios::call(0x10);
};
diff --git a/real/real.ha b/real/real.ha
deleted file mode 100644
index ee42523..0000000
--- a/real/real.ha
+++ /dev/null
@@ -1,22 +0,0 @@
-export type state = struct {
- @offset(0) eax: u32,
- @offset(4) ebx: u32,
- @offset(8) ecx: u32,
- @offset(12) edx: u32,
- @offset(16) edi: u32,
- @offset(20) esi: u32
-};
-
-export let regs: state;
-
-
-export fn clearregs() void = {
- regs = state {
- ...
- };
-};
-
-export @symbol("real.call") fn call(addr: u16) void;
-
-export @symbol("testt") fn testt() void;
-export @symbol("drive_read_lba") fn drive_read_lba() void;
diff --git a/rt/+x86_64/realcall.S b/rt/+x86_64/realcall.S
index 46745f8..9e9afb4 100644
--- a/rt/+x86_64/realcall.S
+++ b/rt/+x86_64/realcall.S
@@ -1,7 +1,7 @@
.code64
-.globl real.regs
-real.regs:
+.globl bios.regs
+bios.regs:
reax:
.int 0x0
rebx:
@@ -14,6 +14,17 @@ redi:
.int 0x0
resi:
.int 0x0
+rds:
+ .short 0x0
+res:
+ .short 0x0
+rss:
+ .short 0x0
+rgs:
+ .short 0x0
+rfs:
+ .short 0x0
+
# :real_call
@@ -26,9 +37,9 @@ resi:
# above.
# The procedure to go from Long Mode back to Real Mode is explained in much details
# in the AMD64 Programmer's Manual Vol. 2, in particular, the figure 1-6. in section 1.3.
-.globl real.call
-real.call:
- # :Push all the segments registers
+.globl bios.call
+bios.call:
+ xchg %bx, %bx
push %rbx
push %r12
push %r13
@@ -80,27 +91,44 @@ real_call_to_16bits_rmode_down:
mov %ax, %gs
mov %ax, %fs
- # :real mode, yay
-
lidt bios_idtr
-
sti
- mov rebx, %ebx
- mov recx, %ecx
- mov redx, %edx
- mov redi, %edi
- mov resi, %esi
-
- pop %ax
- call *%ax
-
- mov %eax, reax
- mov %ebx, rebx
- mov %ecx, recx
- mov %edx, redx
- mov %edi, redi
- mov %esi, resi
+ # :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
+ mov (recx), %ecx
+ 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
+
+real_call_int:
+ int $0x0
+
+ pop %ds
+ mov %ds:(rfs), %fs
+ mov %ds:(rgs), %gs
+ mov %ds:(rss), %ss
+ mov %ds:(res), %es
+ mov %eax, (reax)
+ mov %ebx, (rebx)
+ mov %ecx, (recx)
+ mov %edx, (redx)
+ mov %edi, (redi)
+ mov %esi, (resi)
cli
diff --git a/rt/+x86_64/stage0.s b/rt/+x86_64/stage0.s
index de0b0e4..e17c06b 100644
--- a/rt/+x86_64/stage0.s
+++ b/rt/+x86_64/stage0.s
@@ -13,6 +13,7 @@ _stage0:
# :Clear segment registers
# this is important if memory accesses are done later before proper segmentation
# as these registers can have arbitrary values
+ xchg %bx, %bx
xor %ax, %ax
mov %ax, %ds
mov %ax, %es
diff --git a/rt/+x86_64/stage0_drive.S b/rt/+x86_64/stage0_drive.S
index 1b6a801..c376b6b 100644
--- a/rt/+x86_64/stage0_drive.S
+++ b/rt/+x86_64/stage0_drive.S
@@ -1,12 +1,15 @@
# :Boot drive number
+.globl drive_no
drive_no:
.byte 0
# :Boot drive sectors per track
+.globl drive_spt
drive_spt:
.byte 0
# :Boot drive number of heads
+.globl drive_heads
drive_heads:
.byte 0
diff --git a/rt/hare.sc b/rt/hare.sc
index 0cb9c02..3de964c 100644
--- a/rt/hare.sc
+++ b/rt/hare.sc
@@ -20,6 +20,8 @@ SECTIONS {
. += 4096;
_p1 = .;
. += 4096;
+ _ws = .;
+ . += 512;
. = 0x7c00;
stack_top = .;