I have searched far and wide but can't find the answer I'm looking for, my problem is that I use outb
to try and set the position of my VGA text mode cursor in my 64-bit operating system kernel and it does not move at all. Trying to hide it does also not work.
That said I've tried to enable the cursor beforehand, and it changed nothing.
My Code for the cursor is as follows:
void Terminal::SetCursor(WORD x, WORD y)
{
WORD pos = y * VGA_WIDTH + x;
outb(0x3D4, 0x0F);
outb(0x3D5, (WORD)(pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (WORD)((pos >> 8) & 0xFF));
}
void Terminal::HideCursor()
{
outb(0x03D4, 0x0A);
outb(0x03D5, 0x20);
}
And my implementations for outb
and inb
:
static inline void outb(BYTE value, WORD port)
{
__asm volatile ("outb %0, %1" : : "a" (value), "Nd" (port));
}
static inline BYTE inb(WORD port)
{
BYTE value;
__asm volatile ("inb %1, %0" : "=a" (value) : "Nd" (port));
return value;
}
And my kernel main looks like this:
extern "C" void kmain(void* memmap)
{
Terminal::HideCursor(); //TODO: Look into why this is not working!
Terminal::Clear();
}
I use a GCC cross compiler for 64-bit I mad using cygwin and these entries in the make file compile the kernel sources:
bin/kernel.bin: tmp/kernel_entry.o tmp/kernel.o tmp/Terminal.o
i686-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
tmp/kernel.o: src/kernel/main.cpp
i686-elf-gcc -ffreestanding -g -c $^ -o $@
tmp/Terminal.o: src/kernel/Terminal.cpp
i686-elf-gcc -ffreestanding -g -c $^ -o $@
Any help would be much appreciated and I can't wait for people to tell me how much of an idiot I am. Thanks in advance.
EDIT: boot.asm
[bits 16]
[org 0x7C00]
KERNEL_LOC equ 0x8FD0
_start:
mov [_BootDisk], dl
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov bp, 0x7BFF
mov sp, bp
push 0x7E00 ; buffer
push 1 ; sectors to read
push 2 ; sector num
call DiskRead
jc .error
push ebx
pushfd
pop eax
mov ebx, eax
xor eax, 0x200000
push eax
popfd
pushfd
pop eax
cmp eax, ebx
jnz .supported
push _CpuErrorString
call Print
jmp .error
.supported:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .no64
mov eax, 0x80000001
cpuid
test edx, 1 << 29
jnz .is64
.no64:
push _64ErrorString
call Print
jmp .error
.is64:
push 0x8000
call MapMem
push KERNEL_LOC ; buffer
push 8 ; sectors to read
push 3 ; sector num
call DiskRead
jc .error
cli
lgdt [GDT_descriptor]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp CODE_SEG:protected_mode
.error:
jmp $
Print:
push bp
mov bp, sp
mov bx, [bp+4]
mov ah, 0x0E
.loop:
mov al, [bx]
cmp al, 0
je .end
int 0x10
inc bx
jmp .loop
.end:
mov sp, bp
pop bp
ret 2
DiskRead:
push bp
mov bp, sp
mov ah, 0x02
mov al, [bp+6]
mov ch, 0
mov cl, [bp+4]
mov dh, 0
mov dl, [_BootDisk]
mov bx, [bp+8]
int 0x13
jnc .end
push _DiskErrorString
call Print
.end:
mov sp, bp
pop bp
ret 6
MapMem:
push bp
mov bp, sp
mov si, [bp+4]
mov di, [bp+4]
add di, 4
xor ebx, ebx
mov edx, 0x0534D4150
mov eax, 0xE820
mov [di+20], dword 1
mov ecx, 24
int 0x15
jc .failed
mov edx, 0x0534D4150
cmp eax, edx
jne .failed
test ebx, ebx
je .failed
.loop:
mov eax, 0xE820
mov [di+20], dword 1
mov ecx, 24
int 0x15
jc .finish
mov edx, 0x0534D4150
.jmpin:
jcxz .skip
cmp cl, 20
jbe .notext
test byte [di+20], 1
je .skip
.notext:
mov ecx, [di+8]
or ecx, [di+12]
jz .skip
inc dword [si]
add di, 24
.skip:
test ebx, ebx
jne .loop
.finish:
clc
jmp .end
.failed:
push _MemErrorString
call Print
stc
jmp .end
.end:
mov sp, bp
pop bp
ret 2
_BootDisk: db 0
_DiskErrorString: db "Disk read error!", 13, 10, 0
_MemErrorString: db "Memory mapping failed!", 13, 10, 0
_CpuErrorString: db "CPUID not supported!", 13, 10, 0
_64ErrorString: db "x64 bits not supported!", 13, 10, 0
CODE_SEG equ GDT_code - GDT_start
DATA_SEG equ GDT_data - GDT_start
GDT_start:
GDT_null:
dd 0x0
dd 0x0
GDT_code:
dw 0xffff
dw 0x0
db 0x0
db 0b10011010
db 0b11001111
db 0x0
GDT_data:
dw 0xffff
dw 0x0
db 0x0
db 0b10010010
db 0b11001111
db 0x0
GDT_end:
GDT_descriptor:
dw GDT_end - GDT_start - 1
dd GDT_start
times 510-($-$$) db 0
dw 0xAA55
[bits 32]
protected_mode:
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000
mov esp, ebp
call Clear
mov ebx, VGA_MEM
mov byte [ebx], 'P'
inc ebx
mov byte [ebx], 14
mov eax, cr0
and eax, ~(1 << 31)
mov cr0, eax
mov edi, 0x1000
mov cr3, edi
xor eax, eax
mov ecx, 4096
rep stosd
mov edi, cr3
mov dword [edi], 0x2003
add edi, 0x1000
mov dword [edi], 0x3003
add edi, 0x1000
mov dword [edi], 0x4003
add edi, 0x1000
mov ebx, 0x00000003
mov ecx, 512
.set_entry:
mov dword [edi], ebx
add ebx, 0x1000
add edi, 8
loop .set_entry
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
lgdt [GDT.Pointer]
jmp GDT.Code:long_mode
jmp $
Clear:
push ebp
mov ebp, esp
mov ecx, VGA_SIZE
mov eax, VGA_MEM
.loop:
mov byte [eax], 0
inc eax
loop .loop
mov esp, ebp
pop ebp
ret
PRESENT equ 1 << 7
NOT_SYS equ 1 << 4
EXEC equ 1 << 3
RW equ 1 << 1
ACCESSED equ 1 << 0
GRAN_4K equ 1 << 7
SZ_32 equ 1 << 6
LONG_MODE equ 1 << 5
GDT:
.Null: equ $ - GDT
dq 0
.Code: equ $ - GDT
dd 0xFFFF
db 0
db PRESENT | NOT_SYS | EXEC | RW
db GRAN_4K | LONG_MODE | 0xF
db 0
.Data: equ $ - GDT
dd 0xFFFF
db 0
db PRESENT | NOT_SYS | RW
db GRAN_4K | SZ_32 | 0xF
db 0
.TSS: equ $ - GDT
dd 0x00000068
dd 0x00CF8900
.Pointer:
dw $ - GDT - 1
dq GDT
[bits 64]
long_mode:
cli
mov ax, GDT.Data
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov rbx, VGA_MEM
mov byte [rbx], 'L'
inc rbx
mov byte [rbx], 2
jmp KERNEL_LOC
VGA_MEM equ 0xB8000
VGA_WIDTH equ 80
VGA_HEIGHT equ 25
VGA_STRIDE equ 2
VGA_SIZE equ VGA_WIDTH * VGA_STRIDE * VGA_HEIGHT
VGA_LENGTH equ VGA_WIDTH * VGA_HEIGHT
times 1024-($-$$) db 0
As requested he's my boot loader. (its probably terrible)
And hers the complete makefile:
all: bin/UmbrellaOS.img
clear:
rm -rfv bin/*
rm -rfv tmp/*
rebuild: clear bin/UmbrellaOS.img
bin/UmbrellaOS.img: bin/boot.bin bin/kernel.bin bin/zeros.bin
cat $^ > $@
bin/boot.bin: src/boot/boot.asm
nasm $< -f bin -o $@
bin/zeros.bin: src/boot/zeros.asm
nasm $< -f bin -o $@
tmp/kernel_entry.o: src/kernel/kernel_entry.asm
nasm $< -f elf -o $@
bin/kernel.bin: tmp/kernel_entry.o tmp/kernel.o tmp/Terminal.o
i686-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
tmp/kernel.o: src/kernel/main.cpp
i686-elf-gcc -ffreestanding -g -c $^ -o $@
tmp/Terminal.o: src/kernel/Terminal.cpp
i686-elf-gcc -ffreestanding -g -c $^ -o $@
This problem can be solved by not using the wrong kind of cross compiler. I was using an i686-elf cross compiler which still generates 32-bit code, after building an x86_64-elf cross compiler as suggested by @MichaelPetch it now works how I want it to.
Just in case anyone is curious about her are the new makefile lines that I needed to change:
tmp/kernel_entry.o: src/kernel/kernel_entry.asm
nasm $< -f elf64 -o $@
tmp/kernel.o: src/kernel/main.cpp
x86_64-elf-g++ -ffreestanding -m64 -g -c $^ -o $@
tmp/Terminal.o: src/kernel/Terminal.cpp
x86_64-elf-g++ -ffreestanding -m64 -g -c $^ -o $@
As you can see I needed to add arguments like elf64
and -m64
to tell both NASM and g++ that I wanted to have 64-bit code. This works with GCC too you don't have to use g++.
Thank you again to @MichaelPetch for helping out! I had no idea that i686-elf cross compilers still generated 32-bit code.