0

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:

this is the 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.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Xulum12
  • 19
  • 4
  • 2
    VESA mode 103h is 800x600 256 colors, so it is 1 byte per pixel. – dimich Nov 05 '22 at 17:20
  • 2
    There is no VESA 24-bit video mode that you can operate on via the usual video aperture at A000h without using **bank-switching**. You need to fetch the video mode's characteristics from VESA and especially learn about the **Linear Frame Buffer**. To get an idea about what you're facing, read the accepted answer at https://stackoverflow.com/questions/62029926/incorrect-results-drawing-horizontal-and-vertical-lines-to-the-lfb-returned-by-v/62123304?r=SearchResults&s=1%7C40.0618#62123304 – Sep Roland Nov 05 '22 at 17:27
  • I don't care about what video mode are we in (vga, vesa...), I just want to make it compatible with all monitors (all resolutions), and that i could edit pixels in real color mode (24 bits). – Xulum12 Nov 05 '22 at 20:42
  • 1
    Have you considered using UEFI since you want to be in 64-bit mode? Instead of booting with legacy BIOS 16-bit mode. With UEFI, you have some portable interfaces that work in 64-bit mode, unlike with BIOS where no `int imm8` calls work after switching to protected mode. (There might be some way to still access VESA BIOS calls, so maybe you wouldn't need to write mode-setting drivers for every actual video card...) – Peter Cordes Nov 05 '22 at 22:48
  • @Spektre I changed it to 115h, Now it gave a less-mess thing. (less-mess thing : https://ibb.co/ccNZBfG )If i change the numbers (starting pont is not 0) then it gets brighter up to a point ((eax set to 300000) https://ibb.co/dmJ38Pv ) when it changes from green->blue to red -> blue.((both eax, edi set to 300000) https://ibb.co/CVDR12H ) And i'm aware that i'm not thesting it in 64 bit enviroment, i did not find anything how to output a pixel in 64 bit mode. But if the code works here then i just need to find how to output a pixel and i'm finaly done. – Xulum12 Nov 12 '22 at 16:36
  • And I want to make it compatible with all types of resolutions. There are so many that I'm sure there is something that detects your monitor size and generates a code to run it. – Xulum12 Nov 12 '22 at 16:49
  • @Spektre But i don't understand how to set colors. It's (pseudo) random. And i don't know how to output pure white, pure black, purple, yellow, etc... And i meant compatible with all resolutions as like I could connect every type of monitor, it would automatically detect it, and set the right mode/set some special mode wich can be used on any monitor. – Xulum12 Nov 15 '22 at 15:57
  • @Spektre What do i do after i done that calculation? (Add them together and output it? Set them into eax?...) And what does xs stand for? (Sorry, I'm very new to graphical assembly). – Xulum12 Nov 15 '22 at 20:41
  • I moved the comments into answer and added simple example of pixel rendering I just busted in DOS-BOX and NASM ... – Spektre Nov 16 '22 at 08:20

1 Answers1

0

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...

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Hello Spektre, can you join the chat room ? https://chat.stackoverflow.com/rooms/249677/3d-graphics – andre_lamothe Nov 16 '22 at 18:54
  • Hello, sorry, I meant compatible with all resolutions, so it can output up to 8K, but I looked it up and discovered that 1600x1200 is the limit. How can I overcome that? I'm sure there is a way to make my own graphics or an equation to make it happen. I mean windows somehow does it. @Spektre – Xulum12 Dec 02 '22 at 19:18
  • @Xulum12 that will be a huge problem because 8K is not possible with VESA (at least to my knowledge) ... you know you need HDMI to transmit such video signal to monitor ... old VGA,DVI has not such bandwith meaning you need driver code for your gfx card which is IIRC not part of VESA/VBE ... that is why old VESA VBE does not support higher resolutions they simply do not fit the cables bandwith ... and to write your own gfx driver you need a lot of docs from manufactor of the gfx card and its chips which you will most likely not obtain anywhere ... – Spektre Dec 02 '22 at 21:32
  • @Xulum12 probably easier would be to use existing drivers from some OS and emulate that OS to extend so the drivers are usable ... still huge ammount of work but its more likely achievable ... I recommend linux as its source codes are available – Spektre Dec 02 '22 at 21:35
  • @Spektre I have an idea. If it's possible i could divide the monitor into smaller "monitors" what the OS could handle. And it would work even if a higher resolution is released. Do you think it's possible? – Xulum12 Dec 04 '22 at 16:05
  • @Xulum12 I do not think so its not that OS could not handle it its that VESA/VBE was created for gfx chips/cards supporting VGA and DVI, and those are not physically capable of transmitting image of higher resolution (even if you do partial image its still the same frequency)... the HDMI output is driven by completely different circuits/chips that have nothing common with old VESA/VBE ... on modern cards those even does not exist and are just emulated ... that is why OSes are used as manufactors provide drivers for them and we just use unified gfx API provided by OS like GDI,OpenGL,DirectX – Spektre Dec 04 '22 at 17:27
  • @Spektre I meant that I could break the monitor up into, e.g., two 1200x800 "areas" so I could have a 2400x1600 monitor. – Xulum12 Dec 04 '22 at 18:21
  • @Xulum12 I got it the first time ... that is simply not how video output and gfx chips work ... thats why I wrote I do not think so ... – Spektre Dec 04 '22 at 20:58