I want to make an OS (64 bit). I made a compiler in it, input, output, I just need to have a 24 bit graphics mode to make a GUI. I tried to display all of the colors but I just get this mess:
the code which ran it: (just in a test 16 bit environment)
[org 0x7c00]
mov ax,4f02h
mov bx,103h
int 10h
mov ax, 0a000h
mov es, ax
mov al, 0
mov edi, 0
mov eax, 0
sl:
stosw
inc edi
inc eax
jmp sl
times 510-($-$$) db 0
dw 0AA55h
And I need to make it interrupt free because of the cli instruction when switching to 64 bit mode. I hope that I can make it to be compatible with any resolution but I need to output a pixel for now. I hope someone knows how to do it, because I didn't find anything is this topic.
I tried to switch the mov bx, 103h to other things, but it just made it worse. And I can't even run it in 64 bit mode because of the mov es, ax.
First I strongly recommend to read this:
The idea behind pixel rendering is to compute address where pixel lies in VRAM and copy the color or index at that address (using segment where the VRAM is located usually A000h
for video and B800h
for text modes).
address = (x + y*x_resolution) * bytes_per_pixel
However normally we can access only single segment of VRAM so wee need also to select which one it is (page) so:
page = address / 65536
offs = address % 65536
now you switch in page (if not already) and copy the pixel color (1/2/4
bytes) at that address for example by using stosb/w/d
. Now I am not sure if pixel can be at 2 pages at once (the code bellow does not handle that) so if true you should handle that too (however as x resolution for standard video modes is always multiple of 4 I do not think its possible).
Looks like you really a rookie so here is small simple (ugly and slooooow) example (MS-DOS com executable using VESA BIOS in NASM) of rendering pixels in 800x600x32bit mode 115h... just inspect the function pixel
, it expects 800x600x32bit video mode and ax,bx
as x,y and ecx
as 32bit color:
Firs main source file:
[BITS 16]
[ORG 100h]
[SEGMENT .text]
start: pusha
mov ax,115h ; init 800x600 32bit
call vesamod
mov al,0 ; set page to 0
mov [cs:page],al
call vesapag
mainl0: mov ax,10
mov bx,10
mov ecx,003F7FFFh
l0: call pixel
inc ax
inc bx
cmp ax,110
jnz l0
mov ax,256 ; stop on any key hit
int 16h
jz mainl0
mov ax,3 ; return to 80x25 text mode
int 10h
popa
ret
error: mov ax,3
int 10h
popa
popa
ret
pixel: pusha ; ax=x, bx=y, ecx = color
mov di,ax ; eax = ( 800*y + x ) * 4
mov eax,800
and ebx,0FFFFh
mul ebx
mov bx,di
add eax,ebx
shl eax,2
mov di,ax ; di = eax % FFFFh (offset)
mov ax,0A000h ; es = A000h
mov es,ax
shr eax,16 ; ax = eax / FFFFh (page)
cmp al,[cs:page]
jz .pixel0 ; change page if needed
mov [cs:page],al
call vesapag
.pixel0:mov eax,ecx ; eax = color
stosd ; render pixel
popa
ret
page: db 0
%include 'vesa.lib'
and the helper vesa.lib
:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;VESA librrary ver: 1.0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;vesamod set VESA videomode ax
;vesapag al=page switch vesa video page window A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Vesa: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
vesamod:pusha ;set VESA videomode ax
mov bx,ax
mov ax,4f02h
int 16
lea si,[cs:.err]
or ah,ah
jnz near error
popa
ret
.err: db 'VESA mode set error.',0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
vesapag:pusha ;al=page switch vesa video page window A
mov dl,al
sub dh,dh
sub bx,bx
mov ax,4f05h ; window A
int 16
lea si,[cs:.err] ; error msg
or ah,ah
jnz near error
popa
ret
.err: db 'VESA page switch error.',0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; End. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
note that I did not code in asm in ages and have no mod to tweak this in DOS-BOX too much so its ugly and non optimized.
This renders blue diagonal line using function pixel
which means the layout of color is:
ecx = 00RRGGBBh
there are many pusha/popa and I am using slow computation using mul
to improve performance you should have array where you store the starting address and page of each scan line precomputed once (after changing video mode) and then just access it using y
. Also the actual page
variable could be moved directly into vesapag
function but I was not in the mood to edit 2 files as I am really rusty in MS-DOS and asm now and DOS BOX is conflicting key shortcuts with my editors not to mention VC editors stopped working for god knows what reason (took me a lot more time to workaround that than code the example itself)...
Also if you want to use 32/64 bit code you will have to use some kind of extender to have access to VESA BIOS (or any BIOS) functions or their replacement. Have never done such thing but people used DOS4GW for this back in the day...
Also in 32/64 bit mode you can use LFB (linear frame buffer) and forget about page switching completely (improving speed a lot more).
If you want to have this working for any resolution then you should change the hardcoded 800
to real resolution you use. It can be obtained from VESA BIOS (along with starting segment) just disect this:
It obtains all available VESA video modes along with information about them and once you chose one from the list it renders a control image so you see the difference between 8/15/16/32 bit modes...