Skip to content

Commit

Permalink
check VRAM size, and recognize QXL video card as well
Browse files Browse the repository at this point in the history
  • Loading branch information
camthesaxman committed Mar 25, 2022
1 parent 7083746 commit e7cc877
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 67 deletions.
122 changes: 81 additions & 41 deletions bga.asm
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,14 @@ EXTERN _wYResolution : WORD
EXTERN _wBPP : WORD
EXTERN _wFrameBufSelector : WORD

EXTERN pci_config_read_dword : NEAR
EXTERN pci_find_device : NEAR
EXTERN pci_config_read_dword : NEAR
EXTERN pci_config_write_dword : NEAR
EXTERN pci_get_device_config_base : NEAR

;-------------------------------------------------------------------------------
; Defines
;-------------------------------------------------------------------------------
GET_VM_HANDLE EQU 1683h
GET_DEVICE_API_ENTRY_POINT EQU 1684h
STOP_IO_TRAP EQU 4000h
START_IO_TRAP EQU 4007h
VFLATD_VXD EQU 11Fh

; Bochs Graphics Adapter ports
Expand All @@ -49,11 +47,12 @@ VBE_DISPI_INDEX_BANK EQU 0005h
;-------------------------------------------------------------------------------
; Variables
;-------------------------------------------------------------------------------
PUBLIC _vflatdEntry
PUBLIC _dwFrameBufAddr
_DATA_BSS SEGMENT PUBLIC 'FAR_DATA'
_vflatdEntry DD 0
_dwFrameBufAddr DD 0
PUBLIC _vflatdEntry
PUBLIC _dwFrameBufAddr
_vflatdEntry DD 0 ; vflatd.vxd entry point
_dwFrameBufAddr DD 0
dwPhysFrameBufAddr DD 0 ; physical address of the linear frame buffer
_DATA_BSS ENDS
ASSUME ds:_DATA_BSS

Expand All @@ -63,6 +62,73 @@ ASSUME ds:_DATA_BSS
;-------------------------------------------------------------------------------
_INIT SEGMENT WORD PUBLIC USE16 'CODE'

; Detects the Bochs Graphics adapter and the size and location of its VRAM
; Called from the DriverInit on startup
; Returns
; 1 on success, 0 on failure
bga_hardware_detect_ PROC FAR PUBLIC
push esi
cli ; disable interrupts so we don't get preempted while manipulating ports

; check ID of adapter (must be between 0xB0C0 and 0xB0C5)
mov ax, VBE_DISPI_INDEX_ID
call bga_read_reg
cmp ax, 0B0C0h
jb failure
cmp ax, 0B0C5h
ja failure

; probe for PCI device
mov eax, 11111234h
call pci_get_device_config_base
cmp eax, -1
jne found_pci
mov eax, 01001B36h ; QEMU QXL also supports this
call pci_get_device_config_base
cmp eax, -1
je failure

found_pci:

mov al, 10h
mov esi, eax ; save config address of BAR0

; Read the frame buffer address from BAR0
call pci_config_read_dword
push eax ; save original BAR0
and al, 0F0h ; clear lower 4 bits to get the actual address
mov dwPhysFrameBufAddr, eax

; Get the size of the frame buffer by writing all 1s, then reading it back
; to see what is masked
mov eax, esi
xor ebx, ebx
not ebx
call pci_config_write_dword
mov eax, esi
call pci_config_read_dword
and al, 0F0h
not eax
inc eax
mov _dwVideoMemSize, eax

; Restore original BAR0 value
mov eax, esi
pop ebx
call pci_config_write_dword

success:
mov ax, 1
jmp done
failure:
xor ax, ax
done:

sti ; re-enable interrupts
pop esi
retf
bga_hardware_detect_ ENDP

; Enables the Bochs Graphics Adapter hardware
; Returns:
; 1 on success, 0 on failure
Expand All @@ -75,25 +141,14 @@ bga_phys_enable_ PROC FAR PUBLIC
retf
bga_phys_enable_ ENDP

; Resets the Bochs Graphics Adapter hardware
; Resets the Bochs Graphics Adapter hardware and applies the current resolution
; settings
; Returns:
; 1 on success, 0 on failure
bga_phys_reset PROC NEAR
cli ; disable interrupts so we don't get preempted while manipulating ports

; check ID of adapter (must be between 0xB0C0 and 0xB0C5)
mov ax, VBE_DISPI_INDEX_ID
call bga_read_reg
cmp ax, 0B0C0h
jb failure
cmp ax, 0B0C5h
ja failure

; TODO: find some way to determine actual memory size
; assume 16 MB for now
mov _dwVideoMemSize, (16 * 1024 * 1024)

; disable VBE extensions
; temporarily disable VBE extensions
mov ax, VBE_DISPI_INDEX_ENABLE
xor bx, bx
call bga_write_reg
Expand All @@ -114,15 +169,8 @@ bga_phys_reset PROC NEAR
mov bx, 1
call bga_write_reg

success:
mov ax, 1
jmp done
failure:
xor ax, ax
done:

sti ; re-enable interrupts

ret
bga_phys_reset ENDP

Expand All @@ -149,17 +197,9 @@ bga_vflatd_init PROC NEAR
mov dx, VflatD_Query
call DWORD PTR _vflatdEntry

; Find PCI device of adapter (ven=1234, dev=1111)

mov eax, 11111234h
call pci_find_device
cmp ax, -1
jz no_linear_fb ; device not found

; Read the PCI base address 0 (BAR0)
mov bx, 1000h ; func 0x00, offset 0x10
call pci_config_read_dword
and ax, 0FFF0h ; clear lower 4 bits to get the actual address
mov eax, dwPhysFrameBufAddr
test eax, eax ; can we use the linear framebuffer
jz no_linear_fb

; Get a selector for the linear framebuffer
; dl = function number
Expand Down
27 changes: 20 additions & 7 deletions display.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define STOP_IO_TRAP 0x4000
#define START_IO_TRAP 0x4007

extern int bga_hardware_detect(void);
extern int bga_phys_enable(void);

DWORD dwVideoMemSize = 16 * 1024 * 1024;
Expand Down Expand Up @@ -73,10 +74,19 @@ void bga_set_palette(const RGBQUAD* colors, BYTE startIndex, int nColors)
}
}

WORD calc_scanline_size(WORD w, WORD bpp)
{
return (w * bpp + 7) >> 3;
}

DWORD calc_framebuffer_size(WORD w, WORD h, WORD bpp)
{
return (DWORD)calc_scanline_size(w, bpp) * h;
}

int is_supported_mode(int w, int h, int bpp)
{
return (w >= 320 && h >= 240
// paletted modes currently don't work
&& (bpp == 4 || bpp == 8 || bpp == 16 || bpp == 32));
}

Expand Down Expand Up @@ -109,7 +119,8 @@ void load_display_settings(void)
break;
case 0: // success
debug_print("got resolution settings\n");
if (is_supported_mode(wXResolution, wYResolution, wBPP))
if (is_supported_mode(dispInfo.diXRes, dispInfo.diYRes, dispInfo.diBpp)
&& dwVideoMemSize >= calc_framebuffer_size(dispInfo.diXRes, dispInfo.diYRes, dispInfo.diBpp))
{
wXResolution = dispInfo.diXRes;
wYResolution = dispInfo.diYRes;
Expand Down Expand Up @@ -164,6 +175,10 @@ int DLLFUNC display_driver_init(void)
}
PRINTVAR(wVMHandle);

if (!bga_hardware_detect())
return 0;

PRINTVAR(dwVideoMemSize);
load_display_settings();

return 1;
Expand Down Expand Up @@ -318,9 +333,9 @@ UINT DLLFUNC Enable(LPVOID lpDevice, UINT style, LPSTR lpDeviceType, LPSTR lpOut

lpDriverPDevice = lpDevice;
// compute size of scanline in bytes (rounded up)
wScanlineSize = (wXResolution * wBPP + 7) >> 3;
wScanlineSize = calc_scanline_size(wXResolution, wBPP);
// compute size of framebuffer in bytes
dwFrameBufSize = wScanlineSize * wYResolution;
dwFrameBufSize = calc_framebuffer_size(wXResolution, wYResolution, wBPP);
PRINTVAR(wScanlineSize);
PRINTVAR(dwFrameBufSize);

Expand Down Expand Up @@ -451,14 +466,12 @@ int DLLFUNC Disable(LPPDEVICE lpDevice)

UINT DLLFUNC ValidateMode(DISPVALMODE FAR *lpValMode)
{
WORD lineSize;
DWORD scrnSize;

if (!is_supported_mode(lpValMode->dvmXRes, lpValMode->dvmYRes, lpValMode->dvmBpp))
return VALMODE_NO_UNKNOWN;
// do we have enough memory?
lineSize = (lpValMode->dvmXRes * lpValMode->dvmBpp + 7) >> 3;
scrnSize = lineSize * lpValMode->dvmYRes;
scrnSize = calc_framebuffer_size(lpValMode->dvmXRes, lpValMode->dvmYRes, lpValMode->dvmBpp);
if (dwVideoMemSize < scrnSize)
return VALMODE_NO_NOMEM;
return VALMODE_YES;
Expand Down
29 changes: 28 additions & 1 deletion init.asm
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,35 @@ DriverInit ENDP
PUBLIC _big_code_
_big_code_ LABEL FAR

_INIT ENDS
;========================================================================
;== Name: I4M,U4M ==
;== Operation: integer four byte multiply ==
;== Inputs: DX;AX integer M1 ==
;== CX;BX integer M2 ==
;== Outputs: DX;AX product ==
;== Volatile: CX, BX destroyed ==
;========================================================================
__U4M PROC PUBLIC
xchg ax,bx ; swap low(M1) and low(M2)
push ax ; save low(M2)
xchg ax,dx ; exchange low(M2) and high(M1)
or ax,ax ; if high(M1) non-zero
jz @f ; then
mul dx ; - low(M2) * high(M1)
@@: ; endif
xchg ax,cx ; save that in cx, get high(M2)
or ax,ax ; if high(M2) non-zero
jz @f ; then
mul bx ; - high(M2) * low(M1)
add cx,ax ; - add to total
@@: ; endif
pop ax ; restore low(M2)
mul bx ; low(M2) * low(M1)
add dx,cx ; add previously computed high part
ret ; and return!!!
__U4M ENDP

_INIT ENDS

; Set DriverInit as the DLL entry point
END DriverInit
Loading

0 comments on commit e7cc877

Please sign in to comment.