To implement a linear framebuffer, I wanted to use the pre-registered VBE LFB, at address 0xE0000000. Note that I am using Bochs 2.7, Assembly using NASM, and C using GCC.
I am using a regular char pointer to attempt to point at the address:
char* m = (char*)VIDEO_ADDRESS; //0xE0000000
Though when calling char* m to draw pixels, the OS wouldn't boot - it would be stuck trying in a flashing sequence until it finally gave an error stating
[BXVGA ]
update: select_high_bank != 1
which was when it terminated. This is the code for my display settings in my assembly bootloader (found on a Stack Overflow post):
mov ax, 4F02h ; set vbe mode
mov bx, 118h ; mode 1024*768*24
or bx, 0100000000000000b ; set bit 14th (use LFB)
int 10h
EDIT: I have four files: boot.asm, loader.asm, kernel.asm, and main.c. Here they are, for a complete reproducible example.
boot.asm:
[BITS 16]
[ORG 0x7c00]
start:
xor ax,ax
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0x7c00
TestDiskExtension:
mov [DriveId],dl
mov ah,0x41
mov bx,0x55aa
int 0x13
jc NotSupport
cmp bx,0xaa55
jne NotSupport
LoadLoader:
mov si,ReadPacket
mov word[si],0x10
mov word[si+2],5
mov word[si+4],0x7e00
mov word[si+6],0
mov dword[si+8],1
mov dword[si+0xc],0
mov dl,[DriveId]
mov ah,0x42
int 0x13
jc ReadError
mov dl,[DriveId]
jmp 0x7e00
ReadError:
NotSupport:
mov ah,0x13
mov al,1
mov bx,0xa
xor dx,dx
mov bp,Message
mov cx,MessageLen
int 0x10
End:
hlt
jmp End
DriveId: db 0
Message: db "We have an error in boot process"
MessageLen: equ $-Message
ReadPacket: times 16 db 0
times (0x1be-($-$$)) db 0
db 80h
db 0,2,0
db 0f0h
db 0ffh,0ffh,0ffh
dd 1
dd (20*16*63-1)
times (16*3) db 0
db 0x55
db 0xaa
loader.asm:
[BITS 16]
[ORG 0x7e00]
start:
mov [DriveId],dl
mov eax,0x80000000
cpuid
cmp eax,0x80000001
jb NotSupport
mov eax,0x80000001
cpuid
test edx,(1<<29)
jz NotSupport
test edx,(1<<26)
jz NotSupport
LoadKernel:
mov si,ReadPacket
mov word[si],0x10
mov word[si+2],100
mov word[si+4],0
mov word[si+6],0x1000
mov dword[si+8],6
mov dword[si+0xc],0
mov dl,[DriveId]
mov ah,0x42
int 0x13
jc ReadError
GetMemInfoStart:
mov eax,0xe820
mov edx,0x534d4150
mov ecx,20
mov edi,0x9000
xor ebx,ebx
int 0x15
jc NotSupport
GetMemInfo:
add edi,20
mov eax,0xe820
mov edx,0x534d4150
mov ecx,20
int 0x15
jc GetMemDone
test ebx,ebx
jnz GetMemInfo
GetMemDone:
TestA20:
mov ax,0xffff
mov es,ax
mov word[ds:0x7c00],0xa200
cmp word[es:0x7c10],0xa200
jne SetA20LineDone
mov word[0x7c00],0xb200
cmp word[es:0x7c10],0xb200
je End
SetA20LineDone:
xor ax,ax
mov es,ax
SetVideoMode:
;mov ax,4f02h ;set vesa 1.0 screen mode
;mov bx,81feh ; FOR 800X600 THIS SHOULD BE "103h", for 1024x768 it should be "105h"
;int 10h
;mov ax,3
;int 0x10
mov ax, 4F02h ; set vbe mode
mov bx, 118h ; mode 1024*768*24
or bx, 0100000000000000b ; set bit 14th (use LFB)
int 10h
;mov ax, 13h
;int 10h
mov ah,2
mov dl,7
int 21h
cli
lgdt [Gdt32Ptr]
lidt [Idt32Ptr]
mov eax,cr0
or eax,1
mov cr0,eax
jmp 8:PMEntry
ReadError:
NotSupport:
End:
hlt
jmp End
[BITS 32]
PMEntry:
mov ax,0x10
mov ds,ax
mov es,ax
mov ss,ax
mov esp,0x7c00
cld
mov edi,0x70000
xor eax,eax
mov ecx,0x10000/4
rep stosd
mov dword[0x70000],0x71007
mov dword[0x71000],10000111b
lgdt [Gdt64Ptr]
mov eax,cr4
or eax,(1<<5)
mov cr4,eax
mov eax,0x70000
mov cr3,eax
mov ecx,0xc0000080
rdmsr
or eax,(1<<8)
wrmsr
mov eax,cr0
or eax,(1<<31)
mov cr0,eax
jmp 8:LMEntry
PEnd:
hlt
jmp PEnd
[BITS 64]
LMEntry:
mov rsp,0x7c00
cld
mov rdi,0x200000
mov rsi,0x10000
mov rcx,51200/8
rep movsq
jmp 0x200000
LEnd:
hlt
jmp LEnd
DriveId: db 0
ReadPacket: times 16 db 0
Gdt32:
dq 0
Code32:
dw 0xffff
dw 0
db 0
db 0x9a
db 0xcf
db 0
Data32:
dw 0xffff
dw 0
db 0
db 0x92
db 0xcf
db 0
Gdt32Len: equ $-Gdt32
Gdt32Ptr: dw Gdt32Len-1
dd Gdt32
Idt32Ptr: dw 0
dd 0
Gdt64:
dq 0
dq 0x0020980000000000
Gdt64Len: equ $-Gdt64
Gdt64Ptr: dw Gdt64Len-1
dd Gdt64
kernel.asm:
section .data
Gdt64:
dq 0
dq 0x0020980000000000
dq 0x0020f80000000000
dq 0x0000f20000000000
TssDesc:
dw TssLen-1
dw 0
db 0
db 0x89
db 0
db 0
dq 0
Gdt64Len: equ $-Gdt64
Gdt64Ptr: dw Gdt64Len-1
dq Gdt64
Tss:
dd 0
dq 0x190000
times 88 db 0
dd TssLen
TssLen: equ $-Tss
section .text
extern KMain
global start
start:
lgdt [Gdt64Ptr]
SetTss:
mov rax,Tss
mov [TssDesc+2],ax
shr rax,16
mov [TssDesc+4],al
shr rax,8
mov [TssDesc+7],al
shr rax,8
mov [TssDesc+8],eax
mov ax,0x20
ltr ax
InitPIT:
mov al,(1<<2)|(3<<4)
out 0x43,al
mov ax,11931
out 0x40,al
mov al,ah
out 0x40,al
InitPIC:
mov al,0x11
out 0x20,al
out 0xa0,al
mov al,32
out 0x21,al
mov al,40
out 0xa1,al
mov al,4
out 0x21,al
mov al,2
out 0xa1,al
mov al,1
out 0x21,al
out 0xa1,al
mov al,11111110b
out 0x21,al
mov al,11111111b
out 0xa1,al
push 8
push KernelEntry
db 0x48
retf
KernelEntry:
mov rsp,0x200000
call KMain
End:
hlt
jmp End
main.c:
#include <string.h>
#define SCREEN_HEIGHT 768
#define SCREEN_WIDTH 1024
#define VIDEO_ADDRESS 0xe0000000
#define VBE_DISPI_ID5 0xB0C5
void pixel8bit(int x, int y, int color)
{
long *v = (long*)VIDEO_ADDRESS;
int offset = ((y * SCREEN_WIDTH) + x);
v[offset] = color;
}
void pixel(int x, int y, int color)
{
long *v = (long*)VIDEO_ADDRESS;
int offset = ((y * SCREEN_WIDTH) + x) * 3;
v[offset] = color;
}
void line(int x, int y, int length, int color)
{
for(int i = 0; i < length; i++)
{
pixel(x+i, y, color);
}
}
void vLine(int x, int y, int length, int color)
{
for(int i = 0; i < length; i++)
{
pixel(x, y+i, color);
}
}
void box(int x, int y, int l, int w, int color)
{
char* v = (char*)VIDEO_ADDRESS;
line(x,y,l,color);
vLine(x,y,w,color);
line(x,y+w-1,l,color);
vLine(x+l-1,y,w,color);
}
void fillScreen(int color)
{
char* v = (char*)VIDEO_ADDRESS;
for(int i = 0; i < SCREEN_WIDTH*SCREEN_HEIGHT; i++) {
v[i] = color;
}
}
void coloredBars()
{
char* v = (char*)VIDEO_ADDRESS;
int j = 0;
for(int i = 0; i < SCREEN_WIDTH*SCREEN_HEIGHT; i++) {
if (j > 255)
{
j = 0;
v[i] = j;
}
else
{
j++;
v[i] = j;
}
}
}
void text(int x, int y, int size, char* text, int color, int length)
{
for (int i = 0; i < length; i++)
{
}
}
void KMain(void)
{
//coloredBars(); //debug only
pixel(1,1,0x0f);
}
I also have a build script:
nasm -f bin -o boot.bin boot.asm
nasm -f bin -o loader.bin loader.asm
nasm -f elf64 -o kernel.o kernel.asm
gcc -std=c99 -mcmodel=large -ffreestanding -fno-stack-protector -mno-red-zone -c main.c
ld -T link.lds -o kernel kernel.o main.o
objcopy -O binary kernel kernel.bin
dd if=boot.bin of=boot.img bs=512 count=1 conv=notrunc
dd if=loader.bin of=boot.img bs=512 count=5 seek=1 conv=notrunc
dd if=kernel.bin of=boot.img bs=512 count=100 seek=6 conv=notrunc
My boot.img, which is 10MB, and bochsrc.bxrc:
# configuration file generated by Bochs
plugin_ctrl: voodoo=false, unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, busmouse=false, e1000=false, es1370=false, gameport=true, ne2k=false, sb16=false, usb_uhci=false, usb_ohci=false, usb_ehci=false, usb_xhci=false
config_interface: win32config
display_library: win32
memory: host=1024, guest=1024
romimage: file="C:\Program Files\Bochs-2.7/BIOS-bochs-latest", address=0x00000000, options=none
vgaromimage: file="C:\Program Files\Bochs-2.7/VGABIOS-lgpl-latest"
boot: disk
floppy_bootsig_check: disabled=0
floppya: type=1_44
# no floppyb
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path="C:\Users\{USER}\Desktop\1\boot.img", mode=flat, cylinders=20, 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
ata1-slave: type=none
ata2: enabled=false
ata3: enabled=false
optromimage1: file=none
optromimage2: file=none
optromimage3: file=none
optromimage4: file=none
optramimage1: file=none
optramimage2: file=none
optramimage3: file=none
optramimage4: file=none
pci: enabled=1, chipset=i440fx, slot1=none, slot2=none, slot3=none, slot4=none, slot5=none
vga: extension=vbe, update_freq=60, realtime=1, ddc=builtin
cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string=" Intel(R) Pentium(R) 4 CPU "
cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true
cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, x86_64=true
cpuid: 1g_pages=true, pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true
cpuid: vmx=1
print_timestamps: enabled=0
port_e9_hack: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local, rtc_sync=0
# no cmosimage
log: -
logprefix: %t%e%d
debug: action=ignore
info: action=report
error: action=report
panic: action=ask
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
mouse: type=ps2, enabled=false, toggle=ctrl+mbutton
sound: waveoutdrv=win, waveout=none, waveindrv=win, wavein=none, midioutdrv=win, midiout=none
speaker: enabled=true, mode=sound, volume=15
parport1: enabled=true, file=none
parport2: enabled=false
com1: enabled=true, mode=null
com2: enabled=false
com3: enabled=false
com4: enabled=false
How can I stop this code from crashing with a triple fault when writing to the video memory at 0xe0000000?