Adding SVGA checks

This commit is contained in:
Harry Culpan 2026-07-30 19:46:05 -04:00
parent 8b01cc8538
commit 8c37936d56
7 changed files with 338 additions and 2 deletions

1
.gitignore vendored
View file

@ -1,6 +1,7 @@
# ---> C
# Prerequisites
*.d
deploy_image.sh
# Object files
*.o

View file

@ -2,5 +2,9 @@
#define _UTIL_H_
void displayMessage(int n);
int check_trio_chip();
int get_trio_memory();
int int386x_real(int intnum, union REGS *in, union REGS *out, struct SREGS *sregs);
const char *vbe_mode_description(unsigned mode);
#endif

7
include/vbe12gr.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef _VBE12GR_H_
#define _VBE12GR_H_
int get_current_vbe_mode(unsigned *mode_out);
int get_vbe_version(void);
#endif

3
main.err Normal file
View file

@ -0,0 +1,3 @@
src/main.c(56): Warning! E1178: Type qualifier mismatch
src/main.c(56): Note! I2003: source conversion type is 'char const *'
src/main.c(56): Note! I2004: target conversion type is 'char *'

View file

@ -1,14 +1,60 @@
#include <stdio.h>
#include "util.h"
#include "vbe12gr.h"
void main() {
int i = 0;
unsigned prevMode = 0xFFFF;
char *descr;
printf("DSPACE starting...\n");
for (i = 0; i < 10; i++) {
displayMessage(i + 1);
if (check_trio_chip()) {
printf("S3 Trio64 detected\n");
} else {
printf("S3 Trio64 video card not found, exiting.\n");
return;
}
i = get_trio_memory();
printf("Video DRAM: ");
switch (i) {
case 7:
printf("0.5 MB\n");
break;
case 6:
printf("1 MB\n");
break;
case 4:
printf("2 MB\n");
break;
case 0:
printf("4 MB\n");
break;
default:
printf("Unable to determine ram\n");
}
i = get_vbe_version();
if (i < 0) {
printf("Error on determining VBE version: %d\n", i);
return;
} else if (i == 0) {
printf("VBE not supported, exiting\n");
return;
} else if (i < 200) {
printf("VBE 1.2 supported\n");
} else {
printf("VBE 2.0 supported\n");
}
if (get_current_vbe_mode(&prevMode)) {
printf("Unable to get current mode\n");
} else {
descr = vbe_mode_description(prevMode);
printf("Current mode = %s\n", descr);
}
return;

View file

@ -1,5 +1,183 @@
#include <stdio.h>
#include <conio.h>
#include <i86.h>
#include <string.h>
void displayMessage(int n) {
printf("%02d: Hello MS-DOS!\n", n);
}
int check_trio_chip() {
unsigned char cr30_value;
/* 1. Unlock the S3 VGA Registers (CR30-CR3F) */
// Select the CR38 index register via the address port (0x3D4)
outp(0x3D4, 0x38);
// Write the unlocking code (0x48) to the data port (0x3D5)
outp(0x3D5, 0x48);
/* 2. Read the Chip ID/REV register (CR30) */
// Select the CR30 index register via the address port (0x3D4)
outp(0x3D4, 0x30);
// Read the contents of CR30 from the data port (0x3D5)
cr30_value = inp(0x3D5);
/* 3. Check the Chip ID */
// Mask out the lower nibble (revision status) and compare to 0xE0
if ((cr30_value & 0xF0) == 0xE0) {
return 1; // Chip ID matches
} else {
return 0; // Chip ID does not match, abort
}
}
int get_trio_memory() {
/* 1. Read the Chip ID/REV register (CR36) */
// Select the CR30 index register via the address port (0x3D4)
outp(0x3D4, 0x36);
// Read the contents of CR36 from the data port (0x3D5)
return inp(0x3D5) >> 5;
}
#pragma pack(push, 1)
typedef struct {
unsigned long edi;
unsigned long esi;
unsigned long ebp;
unsigned long reserved;
unsigned long ebx;
unsigned long edx;
unsigned long ecx;
unsigned long eax;
unsigned short flags;
unsigned short es;
unsigned short ds;
unsigned short fs;
unsigned short gs;
unsigned short ip;
unsigned short cs;
unsigned short sp;
unsigned short ss;
} RMCS;
#pragma pack(pop)
/*
* int386x_real - simulate a real-mode interrupt via DPMI (int 0x31, AX=0x0300).
* Same calling shape as int386x(), but intnum is dispatched in real mode
* (BIOS/DOS calls), not as a protected-mode interrupt.
*
* Returns 0 on success, -1 if the DPMI call itself failed (check regs
* are otherwise untouched in that case).
*/
int int386x_real(int intnum, union REGS *in, union REGS *out, struct SREGS *sregs)
{
RMCS rmi;
union REGS dregs;
struct SREGS dsregs;
memset(&rmi, 0, sizeof(rmi));
rmi.eax = in->x.eax;
rmi.ebx = in->x.ebx;
rmi.ecx = in->x.ecx;
rmi.edx = in->x.edx;
rmi.esi = in->x.esi;
rmi.edi = in->x.edi;
rmi.es = sregs->es;
rmi.ds = sregs->ds;
rmi.fs = sregs->fs;
rmi.gs = sregs->gs;
/* SS:SP left as 0:0 -> DPMI host provides a temporary real-mode stack */
memset(&dregs, 0, sizeof(dregs));
memset(&dsregs, 0, sizeof(dsregs));
dregs.w.ax = 0x0300; /* DPMI: Simulate Real Mode Interrupt */
dregs.h.bl = (unsigned char)intnum;
dregs.h.bh = 0;
dregs.w.cx = 0; /* no words to copy onto real-mode stack */
dsregs.es = FP_SEG(&rmi);
dregs.x.edi = FP_OFF(&rmi);
int386x(0x31, &dregs, &dregs, &dsregs);
if (dregs.w.cflag) {
return -1; /* DPMI call itself failed */
}
out->x.eax = rmi.eax;
out->x.ebx = rmi.ebx;
out->x.ecx = rmi.ecx;
out->x.edx = rmi.edx;
out->x.esi = rmi.esi;
out->x.edi = rmi.edi;
out->w.cflag = rmi.flags & 0x0001; /* real-mode call's own carry flag */
sregs->es = rmi.es;
sregs->ds = rmi.ds;
sregs->fs = rmi.fs;
sregs->gs = rmi.gs;
return 0;
}
const char *vbe_mode_description(unsigned mode)
{
/* Strip VBE mode-set flag bits (bit 15 = LFB request, bit 14 =
refresh rate control) before lookup -- these aren't part of
the mode number itself. */
unsigned base_mode = mode & 0x01FF;
switch (base_mode) {
/* Standard VGA modes */
case 0x00: return "40x25 16-color (mono) text";
case 0x01: return "40x25 16-color text";
case 0x02: return "80x25 16-color (mono) text";
case 0x03: return "80x25 16-color text";
case 0x04: return "320x200 4-color graphics (CGA)";
case 0x05: return "320x200 4-color (mono) graphics";
case 0x06: return "640x200 2-color graphics";
case 0x07: return "80x25 monochrome text";
case 0x0D: return "320x200 16-color graphics (EGA)";
case 0x0E: return "640x200 16-color graphics";
case 0x0F: return "640x350 monochrome graphics";
case 0x10: return "640x350 16-color graphics (EGA/VGA)";
case 0x11: return "640x480 2-color (mono) graphics (VGA)";
case 0x12: return "640x480 16-color graphics (VGA)";
case 0x13: return "320x200 256-color graphics (Mode 13h)";
/* VESA SVGA modes */
case 0x100: return "640x400 256-color (VESA)";
case 0x101: return "640x480 256-color (VESA)";
case 0x102: return "800x600 16-color (VESA)";
case 0x103: return "800x600 256-color (VESA)";
case 0x104: return "1024x768 16-color (VESA)";
case 0x105: return "1024x768 256-color (VESA)";
case 0x106: return "1280x1024 16-color (VESA)";
case 0x107: return "1280x1024 256-color (VESA)";
case 0x108: return "80x60 text (VESA)";
case 0x109: return "132x25 text (VESA)";
case 0x10A: return "132x43 text (VESA)";
case 0x10B: return "132x50 text (VESA)";
case 0x10C: return "132x60 text (VESA)";
/* VBE 1.2 direct color modes */
case 0x10D: return "320x200 15bpp direct color (VESA)";
case 0x10E: return "320x200 16bpp direct color (VESA)";
case 0x10F: return "320x200 24bpp direct color (VESA)";
case 0x110: return "640x480 15bpp direct color (VESA)";
case 0x111: return "640x480 16bpp direct color (VESA)";
case 0x112: return "640x480 24bpp direct color (VESA)";
case 0x113: return "800x600 15bpp direct color (VESA)";
case 0x114: return "800x600 16bpp direct color (VESA)";
case 0x115: return "800x600 24bpp direct color (VESA)";
case 0x116: return "1024x768 15bpp direct color (VESA)";
case 0x117: return "1024x768 16bpp direct color (VESA)";
case 0x118: return "1024x768 24bpp direct color (VESA)";
case 0x119: return "1280x1024 15bpp direct color (VESA)";
case 0x11A: return "1280x1024 16bpp direct color (VESA)";
case 0x11B: return "1280x1024 24bpp direct color (VESA)";
default: return "Unknown/unsupported mode";
}
}

97
src/vbe12gr.c Normal file
View file

@ -0,0 +1,97 @@
#include <i86.h>
#include <string.h>
#include "util.h"
#define VBE_SIG_SIZE 4
int get_current_vbe_mode(unsigned *mode_out) {
union REGS regs;
struct SREGS sregs;
memset(&regs, 0, sizeof(regs));
memset(&sregs, 0, sizeof(sregs));
regs.w.ax = 0x4F03;
int386x_real(0x10, &regs, &regs, &sregs);
if (regs.w.ax != 0x004F) {
return -1;
}
*mode_out = regs.w.bx;
return 0;
}
int get_vbe_version(void)
{
union REGS regs;
struct SREGS sregs;
unsigned dos_segment;
unsigned dos_selector;
unsigned char *buf;
unsigned version_bcd;
int result;
memset(&regs, 0, sizeof(regs));
memset(&sregs, 0, sizeof(sregs));
regs.w.ax = 0x0100; /* DPMI: Allocate DOS Memory Block */
regs.w.bx = 0x0020; /* 0x20 paragraphs = 512 bytes */
int386x(0x31, &regs, &regs, &sregs); /* direct DPMI call, not _real */
if (regs.w.cflag) {
return -1;
}
dos_segment = regs.w.ax;
dos_selector = regs.w.dx;
buf = (unsigned char *)(dos_segment << 4);
memset(buf, 0, 512);
memcpy(buf, "VBE2", 4);
memset(&regs, 0, sizeof(regs));
memset(&sregs, 0, sizeof(sregs));
regs.w.ax = 0x4F00;
sregs.es = dos_segment;
regs.w.di = 0x0000;
int386x_real(0x10, &regs, &regs, &sregs); /* real BIOS call - correct as-is */
result = 0;
if ((regs.w.ax & 0x00FF) != 0x4F) {
result = 0;
} else if (((regs.w.ax >> 8) & 0xFF) != 0x00) {
result = 0;
} else {
if (memcmp(buf, "VESA", 4) != 0) {
result = 0;
} else {
version_bcd = *(unsigned short *)(buf + 4);
if (version_bcd >= 0x0200) {
result = 200;
} else if (version_bcd >= 0x0102) {
result = 102;
} else {
result = 0;
}
}
}
memset(&regs, 0, sizeof(regs));
memset(&sregs, 0, sizeof(sregs));
regs.w.ax = 0x0101; /* DPMI: Free DOS Memory Block */
regs.w.dx = dos_selector;
int386x(0x31, &regs, &regs, &sregs); /* direct DPMI call, not _real */
if (regs.w.cflag && result == 0) {
return -2;
}
return result;
}