NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)

NeXT Computer, Inc. -> Intel White Hardware

Title: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: Torsten on July 18, 2017, 05:04:14 AM
Hi all,

after some investigation, I've found a method how NeXTStep 3.3 can
use the VBE20DisplayDriver, and successfully run in 1280x1024x16bpp.

As Morgon explained on Feb 12, 2009 in
http://www.nextcomputers.org/forums/index.php?topic=1988&start=15 ,
NeXTStep 3.3's kernel lacks the ability to set up VESA VBE modes.
The more, it uses an older driver model than Openstep and thus
cannot make use of the latter's drivers.

Although I had once purchased an Openstep package, I never installed
it on x86 (only on a sst5, as I missed NeXTStep's SPARC edition).
NeXTStep was my very first Unix installation, the S3 or Matrox display
drivers on x86 worked fine. No need to switch to Openstep.

The S3 and Matrox graphics boards are gone (almost). Several threads
in this forum deal with the VESA VBE driver included in Openstep
User's latest patch. A good thing, for recent hardware and / or
software emulators. When I examined my Openstep software package
(for first time this millenium ;-), I discovered an Openstep 4.2 CD.
A friend with a fast academic internet connection had even loaded
it's latest patches in 2001. Sorry for my ignorance ...

Installation of Openstep 4.2 and User Path 4 were straightforward.
Difficulties in setting up the VESA VBE driver had been reported. I
didn't encounter any, on the first reboot, the driver initialized in
1280x1024x16bpp (both the VGA and the VESA driver were selected in
Configure.app - surprisingly, no resource conflicts were detected).

Integrating this driver into NeXTStep 3.3 is a three-step-procedure.
I did it with disk images in a software emulation (VirtualBox 5.0.2),
but it should be applicable to real hardware as well (disk handling
more laborious here, though). As cited above, the latest available
Mach 3.3 mk-171.14 1999/07/13 kernel cannot handle Openstep drivers
(fails due to missing functions). What if NeXTStep 3.3 instead used
Mach 4.2 mk-183.34.4 1999/01/26?

It's not a matter of just adding /mach_kernel 1117920 bytes 99/03/23
and Openstep 4.2' /mnt/private/Drivers/i386 directory into a running
NeXTStep 3.3 system. The proper kernel initialization seems to depend
upon the boot loader files located in Openstep's /usr/standalone/i386
directory. With only it's /mach_kernel and drivers copied on the
NeXTStep drive, the kernel boots from the *old* 3.3.3.8 loader. Drivers
load as well, but graphics modes and hence the WindowManager fail to
initialize. Just adding Openstep' /usr/standalone/i386 directory won't
overcome this, it seems that the boot sector points to the *physical*
location of these files, similar to Linux' LILO or GRUB loaders (even
in DOS =< 7.0, the location of it's kernel files is crucial). Small
boot code in a disk's start sector cannot handle sophisticated file
system structures, this seems obvious.

As I did not know about NeXTStep's boot sector tools (must exist) and
their configuration, I started a brute force approach:
1.) Made a copy of the Openstep 4.2 disk image. Mounted this as a
second disk in an Openstep session. Deleted all files from this
second image, except /mach_kernel, /mnt/private/Drivers/i386 and
/usr/standalone/i386.
2.) Mounted a NeXTStep 3.3 image as a second disk, or as a virtual
drive in Linux ("mount -t ufs -o ufstype=nextstep <image> <mountpt>").
Created tarballs from the entire's disk content, except the files /
directories mentioned above.
3.) Unpacked these tarballs onto the nearly emptied second Openstep
disk (in either NeXTStep or Openstep, the Linux 2.6.37.1 kernel can
just mount their filesystem read-only). Make sure that the owner
of the files in /me is set accordingly (the Workspace Manager
cannot save changes if they are owned by root). Reboot.

If everything went correctly, the kernel should now initialize the
configured VESA mode, as with Openstep 4.2 (in fact, the boot process
now relies on pure Openstep code, until NeXTStep 3.3' WindowManager,
daemons and apps are started). When the WindowManager really starts -
enjoy! Your may consider to correct data in the /NextLibrary/Receipts
folder, i.e. to remove references to no-longer existent NeXTStep 3.3
drivers, and to add OS42MachUserPatch4.pkg there, to indicate that
the system is running the very latest kernel (cosmetical).

I have created a compressed version of my 337 MB image file, it's "raw"
format should be supported by several emulators. Some helpful files are
joined (a minimalistic dummy ISO image to speed up booting, VirtualBox
.vmdk file, Readme), if someone was interested. Thanks to Openstep's
Am79C970 driver, networking now works in VirtualBox sessions, at
reasonable speed (faster than Apple's System V Unix). Running a
VESA-enabled NeXTStep 3.3 on real hardware would be interesting.

The described procedure reminds me of a proposal Lars Erdmann had made.
He develops and maintains USB drivers for OS/2. Alas, for Warp4 only,
which uses a more complex kernel than Warp3. I prefer the latter, and
Lars' drivers won't load here. He thus asked me to start Warp3 with a
Warp4 kernel (and his drivers). This is impossible, a "You are using
the wrong version of the operating system." message was displayed.
With Openstep's kernel, I was more optimistic. In fact, Mach 4.2
reveals as quite tolerant. Old operating systems are fascinating!

Greetings, Torsten
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: Stephen9569 on September 14, 2020, 09:08:16 AM
Hi Torsten,
Able to share me the vesa driver for NS3.3?
Thanks
Stephen
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on September 06, 2024, 07:12:47 PM
So about this VESA driver. I (like many other users) don't think that there can be a clean driver up and running on NS3.3 as people would like.

By Clean driver, I mean just double click it and it install to /private/Drivers/i386 and use /NextAdmin/Configure.app/Configure to configure it.

As others have said on this board the VESA code in /usr/standalone/i386/boot/ gets run and gets the VESA information and copies it to KernBootStruct.

https://github.com/evolver56k/Darwin-0.3/blob/745305afd074437bb660bcf02146a2754eeef5ae/boot-2/i386/boot2/graphics.c#L176 (https://github.com/evolver56k/Darwin-0.3/blob/745305afd074437bb660bcf02146a2754eeef5ae/boot-2/i386/boot2/graphics.c#L176)

void
setMode(int mode)
{
unsigned short vmode;
char *vmode_name;

if (currentMode() == mode)
    return;

if (initMode(mode) == NO) {
    /* Couldn't go into requested mode. */
    return;
}

if (mode == GRAPHICS_MODE &&
(vmode_name = newStringForKey(G_MODE_KEY)) != 0)
{
    textBuf = malloc(TEXTBUFSIZE);
    bufIndex = showText = 0;

    if (!convert_vbe_mode(vmode_name, &vmode))
vmode = mode1024x768x256;   /* default mode */

    set_linear_video_mode(vmode);

    clearRect(0, 0, SCREEN_W, SCREEN_H, SCREEN_BG);
    copyImage(bitmapList[PANEL_BITMAP].bitmap, BOX_X, BOX_Y);

    kernBootStruct->graphicsMode = GRAPHICS_MODE;
    kernBootStruct->video.v_baseAddr    = (unsigned long)frame_buffer;
    kernBootStruct->video.v_width       = SCREEN_W;
    kernBootStruct->video.v_height      = SCREEN_H;
    kernBootStruct->video.v_depth       = bits_per_pixel;
    kernBootStruct->video.v_rowBytes    = (SCREEN_W * bits_per_pixel) >> BYTE_SHIFT;
} else {
    showText = 1;
    set_video_mode(2);
    if (textBuf) {
int i;
for (i = 0; bufIndex; bufIndex--)
putchar(textBuf[i++]);
free(textBuf);
textBuf = (char *)0;
    }
}
currentIndicator = 0;
}
It seems that only two BIOS calls are needed at boot to get VESA information (Frame Buffer location, modes supported, amount of memory) (https://wiki.osdev.org/VESA_Video_Modes)
If you can get find that, then you should be able to get a VESA drive up and running with a bit of difficulty. The good news is there already is a open source driver available (https://github.com/vcarosadev/VBoxVideo) that looks like it supports VESA.

I need to find some code probes my VESA card and says what modes are supported and RAM locations so I can modify the source and try it.
External Links
Virtual Box Frame Buffer driver by Vittorio which uses VESA calls (https://github.com/vcarosadev/VBoxVideo)
Darwin 0.3 boot-2/i386/boot2/graphics.c (https://github.com/evolver56k/Darwin-0.3/blob/master/boot-2/i386/boot2/graphics.c)
Apple boot-93/i386/boot2/graphics.c (https://web.archive.org/web/20151102103819/http://www.opensource.apple.com/source/boot/boot-93/i386/boot2/graphics.c)
The VESA VBE 3.0 Specification (http://www.petesqbsite.com/sections/tutorials/tuts/vbe3.pdf)
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on March 04, 2025, 11:48:51 AM
Using Ghidra on VBE20DisplayDriver.config/VBE20DisplayDriver_reloc

- (void)enterLinearMode
{
    return;
}

- (void)revertToVGAMode
{
    return;
}

  The code just returns, it doesn't do anything else as the screen set up code is run when boot2 executes, VBE20DisplayDriver is "Boot Driver" = "Yes";. It also creates the table so you can see what to choose from in /NextAdmin/Configure.app/Configure. I think there was missing code in the RhapsodyDR2 Kernal when you try to run the driver on RhapsodyDR2 but that was a long time ago when I tried that so memory is a bit hazy  ::) .
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on March 11, 2025, 01:13:22 PM
Great just managed to install boot from the OpenStep 4.2 final patch with the VESA code on my VirtualBox NextStep 3.3 set up and it seems to boot in to NextStep 3.3 fine :). Now to find out how to get it into VESA mode as I posted in post #2 above (https://www.nextcomputers.org/forums/index.php?msg=32667), it is going to be a nasty patch for sure  ;D

bootv40.13.1.2 44848 667053606
bootv3.3.3.8 35504 3742572669

# /usr/etc/disk -b /dev/rsd0a
disk name: VBOX HARDDISK 1.0
disk type: fixed_rw_scsi
Writing /usr/standalone/i386/boot
Writing /usr/standalone/i386/boot1
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on March 15, 2025, 08:07:11 PM
Very frustrating as Darwin 0.3 source for /usr/standalone/i386/boot is different to the one that comes with the patched 4.2 boot.

I am using Ghidra on it at the moment.

/boot2/graphics.c/setMode is different, The VBE init code gets called in /boot2/boot.c/getBootString(char *name) routine when it is reading table parameters.

/boot2/graphics.c/convert_vbe_mode(char *mode_name, int *mode) is still in there.
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on March 16, 2025, 06:38:44 PM
Slowly using ghidra on bootv40.13.1.2 to see what I can patch or what functions to use.

You can use the following on the boot command line to get a list of support VESA screen modes. The below screen shot is from VirtualBox.

"VBE Check"="Yes"



EDIT: On OpenSTEP if you are using the VESA driver after getting the list of supported you could boot using the following to boot into 640x480x256 with verbose mode.
"VBE Mode"=257 -v

Need to work on creating a template drive with some builtin VESA modes, Ugly yes, but if it works it works...
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on March 21, 2025, 01:52:56 AM
From i386/boot2/boot.c (https://github.com/evolver56k/Darwin-0.3/blob/745305afd074437bb660bcf02146a2754eeef5ae/boot-2/i386/boot2/boot.c#L563)
the getBootString() calls the VBE Initialize routine, also the execKernel() routine also calls the VBE Initialize routine, will post it when I finish them in Ghidra. Also &kernbootstruct.VBELAB_00001870 and &kernbootstruct.VBELAB_00001875+1 is kernbootstruct+0x1870 and kernbootstruct+0x1876 respectively.

static int getBootString(char *name)
{
    char line[BOOT_STRING_LEN];
    char *cp, *val;
    register char *namep;
    int count, ret;
    static int timeout = BOOT_TIMEOUT;

    undefined2 *VBE_mode;
    undefined4 uVar3; (depth)
    ushort *puVar4;
    int ivar2;
    int ivar5;

top:    cp = line;
    line[0] = '\0';

    /* If there have been problems, don't go on. */
    if (errors)
        timeout = 0;
    errors = 0;
       
    /* Wait a few seconds for user to input string. */
    printf("\n");
    ret = Gets(line, sizeof(line), timeout, "boot: ", "");
    flushdev();

    /* If something was typed, don't use automatic boot again.
     */
    if (ret)
        timeout = 0;
   
    skipblank(&cp);

    if (*cp == '?')
    {
        usage();
        goto top;
    }
// VBE START
    printf("\n");
    val = 0;
    getValueForBootKey(cp, "VBE Check", &val, &count);
    if ((count <1) || ((*val != 'Y' && (*val != 'y'))))
        break;
    count = first_VBERoutine();
    if (!count)
    {
        localPrintf("The VBE video driver can not be used with this display adapter.\n");
    }
    else
    {
        VBE_mode = &kernbootstruct.VBELAB_00001870;
        localPrintf("Usable VBE modes:\n");
        ivar5 = 0;
        if (0 < count)
        {
            puvar4 = (unsigned short*)(&kernbootstruct.VBELAB_00001876);
            do {
                if (*(char *)((int)puVar4 + 5) == '\x06') {
                    depth = "555";
                    if (*(char *)(puVar4 + 3) == '\b') {
                        depth = "888";
                    }
                }
                else {
                    depth = "256";
                }
                localPrintf("%d = %dx%dx%s     ", *VBEmode, puVar4[-1], *puVar4, depth);
                if (puVar4[-1] < 1000) {
                    localPrintf(" ");
                }
                if (*puVar4 < 1000) {
                    localPrintf(" ");
                }
                if (iVar5 % 3 == 2) {
                    localPrintf("\n");
                }
                iVar5 = iVar5 + 1;
                puVar4 = puVar4 + 12;
                VBE_mode = VBE_mode + 12;
            } while (ivar5 < count);
        }
    }       
                   
               
// VBE End
    if (!isKernel(cp))
    {
        printf("\n");

        val = 0;
        getValueForBootKey(cp, "config", &val, &count);
#if 0
        printf("calling load system config\n");
        //sleep(2);
#endif 1
        useDefaultConfig = loadSystemConfig(val,count);

#if 0
        printf("Got default config %d\n", useDefaultConfig);
        //sleep(2);
#endif 1
       
        if (!sysConfigValid)
            goto top;


        if (getValueForKey( "Kernel",
            &val, &count))
        {
            strncpy(name,val,count);
#if 0
        printf("Got kernel name");
        //sleep(2);
#endif 1
        }

        // if nothing was typed,
        // and there were no errors,
        // and (Bootgraphics == Yes),
        // then do graphics mode
        if (*line == '\0' && (errors == 0) &&
            getBoolForKey("Boot Graphics"))
        {
#if 1
            wantBootGraphics = YES;
            /*
             * Ensure that we will be able to enter
             * graphics mode later.
             */
            initMode(GRAPHICS_MODE);
#else
            printf("Graphic boot disabled\n");
        sleep(5);
#endif
        }
    }
    else
    {
#if 0
        printf("No kernel cp\n");
        sleep(5);
#endif 1
        // file name
        namep = name;
        while (*cp && !(*cp == ' ' || *cp == '\t'))
            *namep++ = *cp++;
        *namep = '\0';
    }
    verbose_mode = getValueForBootKey(cp, "-v", &val, &count);
#if 0
    verbose_mode = TRUE;   
    printf("Verbose mode set %d\n", verbose_mode);
        //sleep(5);
#endif 1

    strcpy(kernBootStruct->bootString, cp);
#if 0
    printf("Completed get boot string\n");
        //sleep(5);
#endif 1
    return 0;
}

EDIT: Corrected the following &kernbootstruct.VBELAB_00001875+1 to &kernbootstruct.VBELAB_00001876. Need to find out what that is in the kernbootstruct file.

Corrected the following one line from the incorrect:
localPrintf("%d = %dx%dx%s     ", *VBEmode, *puVar4, depth);

to the correct which has all four variables:
localPrintf("%d = %dx%dx%s     ", *VBEmode, puVar4[-1], *puVar4, depth);
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on March 23, 2025, 05:20:36 AM
From i386/boot2/boot.c (https://github.com/evolver56k/Darwin-0.3/blob/745305afd074437bb660bcf02146a2754eeef5ae/boot-2/i386/boot2/boot.c#L157)
the static int execKernel(int fd, int installMode) routine has been finished in Ghidra.

#if NOTYET
popupPanel(
    "Insert file system media"
    " and press Return");
#else NOTYET
localPrintf("Insert file system media"
" and press Return");
while(getc() != '\r');
printf("\n");
#endif NOTYET
}
}
// VBE initialise Start
// char *vmode_name;
// unsigned short mode;
// extern int num_loaded;
// extern struct driver_info *loaded_drivers;
mode = 0;
first_VBERoutine();
if (num_loaded)
{
int count = 0;
for (i = 0; i < num_loaded; i++) {
if (getValueForStringTableKey(loaded_drivers[i].configTable,
"VBE Mode", &val, &size); {
if ((vmode_name = newStringForKey("VBE Mode")) == 0) {
vmode_name = val;
}
}
convert_vbe_mode(vmode_name, &mode);
break;
}
}
// VBE initialise End
if (errors)
{
setMode(TEXT_MODE);
localPrintf("Errors encountered while starting up the computer.\n");
localPrintf("Pausing %d seconds...\n",BOOT_TIMEOUT);
sleep(BOOT_TIMEOUT);
}

if (wantBootGraphics)
    setMode(GRAPHICS_MODE);
message("Starting Rhapsody",0);

removeLinkEditSegment(
    (struct mach_header *)kbp->kaddr );

if (kbp->eisaConfigFunctions)
    kbp->first_addr0 = EISA_CONFIG_ADDR +
(kbp->eisaConfigFunctions * sizeof(EISA_func_info_t));

clearActivityIndicator();
turnOffFloppy();
if (getBoolForKey("APM")) {
    if (APMPresent()) {
APMConnect32();
    }
}
// VBE Final routine Start
if (mode) {
setMode(TEXT_MODE);
if (set_linear_video_mode(mode & 0xffff)); {
sleep(5);
}

}
// VBE Final routine END
startprog(kernelEntry);
/* Not reached */
return 0;
}

Just find the matching code and replace. Only two more routines left to do the one that initializes and the one that gets called before the kernel gets executed. Just need to find the addresses in kernbootstruct where the VESA code gets written too and we are home free. 8). So yeah it looks for a boot driver with a table entry with VBE MODE and sets the VESA to do that before booting.

EDIT: renamed function FinalVBERoutine to set_linear_video_mode which can be found in // libsaio/vbe.c (https://github.com/evolver56k/Darwin-0.3/blob/745305afd074437bb660bcf02146a2754eeef5ae/boot-2/i386/libsaio/vbe.c#L54) as they are very similar but not identical.
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: rjnf on March 23, 2025, 04:12:18 PM
Hello guys,
I'm also trying to know something in order to start my analisys.
I allways wanted to boot nextstep 3.3 with graphics greater than 640x480. In your opinion do you think it worth to invest on analysis and tryouts? I was thinking at boot get vbe modes and initialise then load the proprietary driver, when wm starts
Does this makes sense? I was targeting having the graphics loader instead of the boot text with that higher resolution.

Thanks for you comments
Ricardo
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on March 24, 2025, 04:20:18 AM
Quote from: rjnf on March 23, 2025, 04:12:18 PMHello guys,
I'm also trying to know something in order to start my analisys.
I always wanted to boot NextStep 3.3 with graphics greater than 640x480. In your opinion do you think it worth to invest on analysis and tryouts? I was thinking at boot get VBE modes and initialise then load the proprietary driver, when wm starts
Does this makes sense? I was targeting having the graphics loader instead of the boot text with that higher resolution.

Thanks for you comments
Ricardo
Yes @Ricardo come and join the fun  8) I know a lot of us want a VBE driver for NeXTSTEP 3.3. I'm just posting my notes and what I have found in this thread so if other people see it they don't have to re invent the wheel.

My approach to this problem is the same as you Ricardo, Get VBE modes at the beginning before the Kernel starts.

I have found out quite a lot by using Ghidra on boot and on VBE20DisplayDriver.config/VBE20DisplayDriver_reloc. I am just going to use the boot that comes with OpenStep 4.2 patched as it can still load and RUN NS3.3 and has all the VBE code in it.

If you have any more questions do ask and I will try to answer the best I can. I'm just having trouble trying to find where boot stores the frame buffer in kernbootstruct.
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on March 29, 2025, 09:30:19 PM
Did some more memory dumping in 0xE000 after seeing in Ghidra which is similar to libsaio/vbe.c/set_linear_video_mode() (https://github.com/evolver56k/Darwin-0.3/blob/745305afd074437bb660bcf02146a2754eeef5ae/boot-2/i386/libsaio/vbe.c#L54). After looking at libsa/memory.h (https://github.com/evolver56k/Darwin-0.3/blob/745305afd074437bb660bcf02146a2754eeef5ae/boot-2/i386/libsa/memory.h) the boot loader is loaded from 0x3000 max length 0xB000.
undefined4 set_linear_video_mode(ushort mode)

{
  int err;
  int ivar3;
  int i_kbs_0x1858;
  undefined4 uVar1;
  undefined4 local_108;
  undefined minfo [16];
  undefined2 local_f4;
  undefined2 local_f2;
  undefined2 local_f0;
  undefined local_eb;
  char local_e9;
  byte local_dc;
  byte local_db;
  byte local_da;
  byte local_d9;
 
  ivar3 = _kernbootstruct;
  local_108 = 0;
  i_kbs_0x1858 = _kernbootstruct + 0x1858;
  err = first_VBERoutine();
  if (err == 0) {
    uVar1 = 0xd464;
LAB_00006dfb:
    reallyPrint(uVar1);
    local_108 = 1;
  }
  else {
    err = getVBEModeInfo(mode,minfo);
    if (err == 0) {
      err = CheckVBEModeInfoBlock(minfo);
      if (err == 0) goto LAB_00006dda;
    }
    else {
LAB_00006dda:
      reallyPrint(0xd479,mode);
      mode = *(ushort *)(&VBELAB_00001870 + ivar3);
      if (*(short *)(&LAB_00001872+2 + ivar3) == 0) {
        uVar1 = 0xd4a9;
        goto LAB_00006dfb;
      }
      reallyPrint(0xd495,mode);
      getVBEModeInfo(mode,minfo);
      sleep(5);
    }
    ivar3 = setVBEMode(mode | 0x4000);
    if (ivar3 == 0) {
      UpdateVBEData(i_kbs_0x1858,mode,minfo);
      *(undefined4 *)(_kernbootstruct + 0x14c) = 0;
      if (local_e9 == '\x04') {
        ivar3 = setVBEPalette(0xdaac);
        if (ivar3 != 0) {
          local_108 = 1;
          reallyPrint(0xd4fb,ivar3);
        }
      }
      in_linear_modeDAT_0000eb84 = 1;
      _screen_widthDAT_0000e49c = local_f2;
      _screen_heightDAT_0000e498 = local_f0;
      BitsPerPixelDAT_0000eb7c = local_eb;
      _DAT_0000eb80_frame_buffer =
           (uint)local_d9 << 24 | (uint)local_da << 16 | (uint)local_db << 8 | (uint)local_dc;
      _tBytesPerScanlineDAT_0000eb88 = local_f4;
    }
    else {
      reallyPrint(0xd4d0,ivar3);
      local_108 = 1;
    }
  }
  return local_108;
}

Shell terminal in photo is of kernbootstruct+0xc00 with a bunch of VBE/VESA modes. The edit window is of 0xE000 offsets with the screen resolution and possible VBE mode. I can't find the frame buffer address though. Getting there slowly.


EDIT: Arrrrgghh. You need to multiply by two the hex  addresses you see on the left hand side as when I did my hex dump code I forgot to multiply the address by 2 as I was displaying unsigned short's. Because of this the 0xE000 memory block data and the kernbootstruct at 0x11000 lined up perfectly with the code. For those who want to look at the 0xE000 (0xE000 -> 0xEFFF memory block area here are some offsets:

// libsaio/console.c
in_linear_mode = 0xb84 //BOOL in_linear_mode;
frame_buffer = 0xb80 //unsigned char *frame_buffer;
screen_width = 0x49c //unsigned short screen_width;
screen_height = 0x498 //unsigned short screen_height;
bits_per_pixel = 0xb7c //unsigned char bits_per_pixel

bytesPerScanLine = 0xb88
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on April 05, 2025, 05:18:54 AM
So I am having trouble trying to build a struct for this 24 bytes of data so would like some assistance from the forum.


So this data is from Virtual Box of the VBE/VESA mode it detects, the boot writes 24 bytes of data for each mode it finds at kernbootstruct+0x1870 (https://github.com/evolver56k/Darwin-0.3/blob/master/boot-2/i386/libsa/kernBootStruct.h#L160) which is in the kernbootstruct._reserved(7500) section. The data you see at address kernbootstruct+0x1856 is the final mode that gets selected and loaded from the VBE driver. So far this is what I have:

typedef struct _vesa_mode { // 24 bytes
unsigned short mode;
unsigned short temp;
unsigned short width;
unsigned short height;
unsigned short rowBytes;
..
unsigned long BitsPerPixel; //example 0x50505
unsigned short ??
unsigned long frame_buffer;
}

Here is the Ghidra code that sets up the block of memory of 24 bytes. It is NOT in the boot source that was released by Apple. the mode is the VESA mode number. The VBEModeInfoBlock can be found here (https://github.com/evolver56k/Darwin-0.3/blob/master/boot-2/i386/libsaio/vbe.h).

void UpdateVBEData(undefined2 *kbs_vesaModeBlock,short mode,undefined2 *VBEModeInfoBlock)

{
  *kbs_vesaModeBlock = mode;
  kbs_vesaModeBlock[1] = *VBEModeInfoBlock;
  kbs_vesaModeBlock[2] = VBEModeInfoBlock[9];
  kbs_vesaModeBlock[3] = VBEModeInfoBlock[10];
  kbs_vesaModeBlock[4] = VBEModeInfoBlock[8];
  *(undefined *)(kbs_vesaModeBlock + 5) = *(undefined *)((int)VBEModeInfoBlock + 25);
  *(undefined *)((int)kbs_vesaModeBlock + 11) = *(undefined *)((int)VBEModeInfoBlock + 27);
  *(undefined *)(kbs_vesaModeBlock + 6) = *(undefined *)((int)VBEModeInfoBlock + 31);
  *(undefined *)((int)kbs_vesaModeBlock + 13) = *(undefined *)(VBEModeInfoBlock + 16);
  *(undefined *)(kbs_vesaModeBlock + 7) = *(undefined *)((int)VBEModeInfoBlock + 33);
  *(undefined *)((int)kbs_vesaModeBlock + 15) = *(undefined *)(VBEModeInfoBlock + 17);
  *(undefined *)(kbs_vesaModeBlock + 8) = *(undefined *)((int)VBEModeInfoBlock + 35);
  *(undefined *)((int)kbs_vesaModeBlock + 17) = *(undefined *)(VBEModeInfoBlock + 18);
  *(uint *)(kbs_vesaModeBlock + 10) =
       (uint)*(byte *)(VBEModeInfoBlock + 20) |
       (uint)*(byte *)((int)VBEModeInfoBlock + 41) << 8 |
       (uint)*(byte *)(VBEModeInfoBlock + 21) << 16 |
       (uint)*(byte *)((int)VBEModeInfoBlock + 43) << 24;
  return;
}

the count value that has the number of VESA modes can be read as a unsigned short at memory address 0xdeac.

Thanks  :)

EDIT: This was solved by ChatGPT after feeding in the VBEModeInfoBlock struct and the routine from Ghidra.
typedef struct {
unsigned short Mode; // 0-1
unsigned short ModeAttributes; // 2-3
unsigned short XResolution; // 4-5
unsigned short YResolution; // 6-7
unsigned short BytesPerScanline; // 8-9

unsigned char BitsPerPixel; // 10
unsigned char NumberOfBanks; // 11
unsigned char MemoryModel; // 12
unsigned char XCharSize; // 13
unsigned char BankSize; // 14
unsigned char YCharSize; // 15
unsigned char NumberOfImagePages; // 16
unsigned char NumberOfPlanes; // 17

unsigned short Padding; // 18-19 (manual padding)

unsigned long PhysBasePtr; // 20-23
} KBS_VBEDataBlock;
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: user217 on April 05, 2025, 02:02:08 PM
Quote from: pTeK on April 05, 2025, 05:18:54 AMSo I am having trouble trying to build a struct for this 24 bytes of data so would like some assistance from the forum.

I assume you want help identifying what the other values in the struct are?

According to everything I can find from the OSDev people on VESA/VBE (see here (https://forum.osdev.org/viewtopic.php?t=30186), here (https://wiki.osdev.org/VESA_Video_Modes)), if the struct's contents come from the video card, most of the other stuff in it may be irrelevant junk created for backward compatibility with antique 80s PC graphics. Just because Ghidra shows it being copied doesn't mean it's necessarily important data—that's probably just the asm that gcc generated for x = y.

I would recommend filling in the missing 12 bytes with 6 shorts called "unused" for now, and carrying on.
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on April 05, 2025, 09:29:24 PM
Will do this and carry on plodding along.
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on April 07, 2025, 05:23:56 AM
Here is some code which display the VESA modes compatible with your hardware.
I hope it works as I have no way to copy this from my IBM Thinkpad.

/*
 * VBE-modes.c
 * compile with cc -o VBE-modes VBE-modes.c -DMISSING_HEADERS
 *
 * Needs to be run as root.
 * Requires bootv40.13.1.2 installed and running that comes with
 * OpenStep 4.2 Patch 3.
 *
 * No warranties and liabilites given, use at your own risk.
 * tab space = 4;
 *
 * 0xdeac is a hardcoded address where the count of VBE drivers found.
 * kernbootstruct+0x1870 is where the VBE modes and data is stored in
 * struct _vesa_mode;
 */
 
#define DRIVER_PRIVATE
#include <bsd/sys/fcntl.h>
#include <libc.h>
#include <stdlib.h>
#include <stdio.h>
#if MISSING_HEADERS
#include "kernBootStruct.h"
#else
#include <machdep/i386/kernBootStruct.h>
#endif

KERNBOOTSTRUCT kernbootstruct;

typedef struct _vesa_mode {
    unsigned short    Mode;                // 0-1
    unsigned short    ModeAttributes;        // 2-3
    unsigned short    XResolution;        // 4-5
    unsigned short    YResolution;        // 6-7
    unsigned short    BytesPerScanline;    // 8-9

    unsigned char    BitsPerPixel;        // 10
    unsigned char    NumberOfBanks;        // 11
    unsigned char    MemoryModel;        // 12
    unsigned char    XCharSize;            // 13
    unsigned char    BankSize;            // 14
    unsigned char    YCharSize;            // 15
    unsigned char    NumberOfImagePages;    // 16
    unsigned char    NumberOfPlanes;        // 17

    unsigned short    Padding;                // 18-19 (manual padding)

    unsigned long    PhysBasePtr;            // 20-23
} KBS_VBEDataBlock;

void bomb(char *s1)
{
    fprintf(stderr,s1);
    exit(-1);
}

int main()
{
    int    kmfd, i;
    unsigned short systemCount, *VBEmode, *YResolution;
    char *depth;
    if ((kmfd = open("/dev/kmem", O_RDONLY)) <0)
    {
        bomb("kbsread: can't get kernal boot structure or not root\n");
    }   
    lseek(kmfd, (off_t)KERNSTRUCT_ADDR, L_SET);
    read(kmfd, &kernbootstruct, sizeof(KERNBOOTSTRUCT));
    if (kernbootstruct.magicCookie != KERNBOOTMAGIC)
    {
        bomb("kbsread: kernBootStruct invalid\n");
    }
    lseek(kmfd, (off_t)0xdeac, L_SET);    // Number of VBE drivers found
    read(kmfd, &systemCount, 1);
    printf("The following VBE modes and resolutions are supported\n");
    VBEmode = (unsigned short*)&kernbootstruct+0x1870/2;
    YResolution = (unsigned short*)&kernbootstruct+0x1876/2;
    for (i = 0; i < systemCount; i++) {
        if (*(char *)((int)YResolution + 5) == 6){
            depth = "555";
            if (*(char *)(YResolution + 3) == 8) {
                depth = "888";
            }
        }
        else
            depth = "256";
        printf("%d = %dx%dx%s \n", *VBEmode, YResolution[-1],
                    *YResolution, depth);
        VBEmode += 12;
        YResolution += 12;
    }
    printf("\n");
    exit(0);
}


EDIT: (Sunday 27/April/2025) Fixed code so it should now work, the two fixes are mentioned in the next couple of posts.
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: user217 on April 07, 2025, 05:47:59 PM
Quote from: pTeK on April 07, 2025, 05:23:56 AMHere is some code which display the VESA modes compatible with your hardware.
I hope it works as I have no way to copy this from my IBM Thinkpad.

I managed to run it on my VirtualBox VM, but it's using the VGA driver, so the gibberish output probably isn't indicative of anything:

However, there is a typo: line 60 has a semicolon after systemCount, but it should be a comma.

EDIT: Same results under VBoxSVGA:

EDIT 2: And also the same results under VMSVGA. Maybe QEMU would give less useless data. Or is there a specific video driver I should have loaded for this to work? (Or am I an idiot for doing this under OS4.2, since this thread is really about NS3.3?)
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on April 08, 2025, 03:13:08 AM
Quote from: Rhetorica on April 07, 2025, 05:47:59 PMI managed to run it on my VirtualBox VM, but it's using the VGA driver, so the gibberish output probably isn't indicative of anything:

However, there is a typo: line 60 has a semicolon after systemCount, but it should be a comma.

Thank you for spotting that, and that is correct the second typo was the incorrect following line.

YResolution = (unsigned short*)&kernbootstruct+0x1976/2;

The correct code is the following:
YResolution = (unsigned short*)&kernbootstruct+0x1876/2;

The VBE structs of data start at &kernbootstruct+0x1870. Also you need to have install OpenStep 4.2 with Patchs 3 with the /usr/standalone/i386/boot which executes the VESA code at boot. Can you tell me how the fixes work. Thanks  :)

EDIT: Attached image of results in VirtualBox.
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: user217 on April 08, 2025, 03:27:53 PM
Quote from: pTeK on April 08, 2025, 03:13:08 AMCan you tell me how the fixes work. Thanks  :)

It's alive!

EDIT: I fiddled with the code after taking this screenshot. It made me realize you were going about getting the bit depth in a weird way—if you replace the contents of the for() loop like this:

for (i = 0; i < systemCount; i++) {
        int depth = *(char *)((intYResolution + 4);
        printf(%d = %dx%d (%ibpp)\n", *VBEmode, YResolution[-1],
                  *YResolution, depth);
        VBEmode += 12;
        YResolution += 12;
}

...then you get slightly cleaner results and don't have to interpret the return values:

Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on April 27, 2025, 05:32:36 AM
I'm still working on this very slowly, when ever I do a update to test the driver I have to reset the machine and use IOLog() a lot. I'm not a programmer as my day job so this is taking a lot longer.

// VBE End
undefined4 set_linear_video_mode(ushort mode)
// console.h
// extern BOOL in_linear_mode;
// extern unsigned char  *frame_buffer;
// extern unsigned short screen_width;
// extern unsigned short screen_height;
// extern unsigned char  bits_per_pixel;

{
  int err;
  int ivar3;
  undefined2 *i_kbs_0x1858;
  undefined4 uVar1;
  undefined4 local_108;
  undefined2 minfo [8];
  undefined2 local_f4;
  undefined2 local_f2;
  undefined2 local_f0;
  undefined local_eb;
  char local_e9;
  byte local_dc;
  byte local_db;
  byte local_da;
  byte local_d9;
 
  ivar3 = _kernbootstruct;
  local_108 = 0;
  i_kbs_0x1858 = (undefined2 *)(_kernbootstruct + 0x1858);
  err = first_VBERoutine();
  if (err == 0) {
    uVar1 = "VESA not available.\n";
LAB_00006dfb:
    reallyPrint(uVar1);
    local_108 = 1;
  }
  else {
    err = getVBEModeInfo(mode,minfo);
    if (err == 0) {
      err = CheckVBEModeInfoBlock(minfo);
      if (err == 0) goto LAB_00006dda;
    }
    else {
LAB_00006dda:
      reallyPrint("VBE mode %d not supported.\n", mode);
      mode = *(ushort *)(&VBELAB_00001870 + ivar3);
      if (*(short *)(&LAB_00001874 + ivar3) == 0) {
        uVar1 = "No usable VBE mode. Reverting to VGA.\n";
        goto LAB_00006dfb;
      }
      reallyPrint("Using VBE Mode %d.\n", mode);
      getVBEModeInfo(mode,minfo);
      sleep(5);
    }
    ivar3 = setVBEMode(mode | 0x4000);
    if (ivar3 == 0) {
      UpdateVBEData(i_kbs_0x1858,mode,minfo);
      *(undefined4 *)(_kernbootstruct + 0x14c) = 0;
      if (local_e9 == '\x04') {
        ivar3 = setVBEPalette(0xdaac);
        if (ivar3 != 0) {
          local_108 = 1;
          reallyPrint("Error in setting palette. VESA VBE error #%d\n" ,ivar3);
        }
      }
      in_linear_modeDAT_0000eb84 = 1; // bool
      _screen_widthDAT_0000e49c = local_f2; // unsigned short
      _screen_heightDAT_0000e498 = local_f0; // unsigned short
      BitsPerPixelDAT_0000eb7c = local_eb; // unsigned short
      _DAT_0000eb80_frame_buffer = // unsigned long
           (uint)local_d9 << 24 | (uint)local_da << 16 | (uint)local_db << 8 | (uint)local_dc;
      _tBytesPerScanlineDAT_0000eb88 = local_f4; // unsigned short
    }
    else {
      reallyPrint("Error in setting mode. VESA VBE error #%d\n",ivar3);
      local_108 = 1;
    }
  }
  return local_108;
}

  All the addressess seem to be populated except for kernBootStruct+0x1858, kernBootStruct+0x185c and kernBootStruct+0x185e which is VBEMode, x resolution, y resolution, I don't know why, more debugging. I can't seen any code in the boot loader that relies on the kernal because the kernel hasn't been booted yet. All the 0xexx addresses are populated as you can see above.
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on April 28, 2025, 02:20:34 PM
Quick post before work, So I've started running the VESA patched OpenStep Kernel in Ghidra. So there is a VESA version of the following routine that gets called at the beginning which checks the memory address 0x12858 and 0x1286c and then gets executed, it will make it slightly harder so have to start looking at how to patch system calls  :'( . I did see in the kernel there is code to make BIOS calls but don't know if that is private. Fun times.
https://github.com/evolver56k/Darwin-0.3/blob/745305afd074437bb660bcf02146a2754eeef5ae/kernel-7/bsd/dev/i386/FBConsole.c#L1354 (https://github.com/evolver56k/Darwin-0.3/blob/745305afd074437bb660bcf02146a2754eeef5ae/kernel-7/bsd/dev/i386/FBConsole.c#L1354)

Following is the normal FBAllocateCosole not the VESA one.
//
// END:        Implementation of IOConsoleInfo functions
//


//
// BEGIN:    Exported routines
//
IOConsoleInfo *FBAllocateConsole(IODisplayInfo *display)
{
    IOConsoleInfo *cso = (IOConsoleInfo *)IOMalloc(sizeof(IOConsoleInfo));
   
    if (cso == NIL)
        return NIL;
    cso->priv = (void *)IOMalloc(sizeof(ConsoleRep));
    if (cso->priv == NIL)
    {
        IOFree(cso, sizeof(IOConsoleInfo));
    return NIL;
    }
    cso->Free = Free;
    cso->Init = Init;
    cso->Restore = Restore;
    cso->DrawRect = DrawRect;
    cso->EraseRect = EraseRect;
    cso->PutC = PutC;
    cso->GetSize = GetSize;
    ((ConsolePtr)cso->priv)->display = *display;
    ((ConsolePtr)cso->priv)->window_type = SCM_UNINIT;
    return cso;
}
//
// END:        Exported routines
//
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on April 29, 2025, 02:22:31 PM
These are functions in the OpenStep 4.2 User Patch 2 kernel that get called() on the way to the kernal function _VBEModeInfo2IODisplayInfo() which is missing in the VBE20DisplayDriver. These routines can be found in the Kernel archive that comes with the Darwin0.1 or Darwin0.3 sources. This is why you get that VESA display mode from the beginning with the console.

/bsd/dev/i386/km.m
void
kminit()
{
    KERNBOOTSTRUCT *kernbootstruct = KERNSTRUCT_ADDR;

    initialized = TRUE;

basicConsole = _FBAllocateVBEConsole();
if (!basicConsole) {
basicConsole = BasicAllocateConsole();
}
    if (kernbootstruct->graphicsMode) {
basicConsoleMode = SCM_GRAPHIC;
(*basicConsole->Init)(
    basicConsole, SCM_GRAPHIC, FALSE, FALSE, mach_title);
    } else {
basicConsoleMode = SCM_TEXT;
(*basicConsole->Init)(
    basicConsole, SCM_TEXT, TRUE, TRUE, mach_title);
    }
}

/bsd/dev/i386/BasicConsole.c
IOConsoleInfo *BasicAllocateConsole()
{
    IODisplayInfo di;
    KERNBOOTSTRUCT *kernbootstruct = KERNSTRUCT_ADDR;
   
    if (!FBAllocateVBEConsole()) {
    bzero(&di, sizeof(di));
    di.width = 640;
    di.height = 480;
    return( VGAAllocateConsole(&di) );
    }
}

/bsd/dev/i386/VGAConsole.c
// modified, removed SVGA code from original.
IOConsoleInfo *_VGAAllocateConsole(IODisplayInfo *display)
{
    IOConsoleInfo *cso = (IOConsoleInfo *)IOMalloc(sizeof(IOConsoleInfo));
    ConsolePtr console = (ConsolePtr)IOMalloc(sizeof(ConsoleRep));
   
    if (cso == NIL)
        return NIL;
    cso->priv = console;
    if (cso->priv == NIL) {
    IOFree(cso, sizeof(IOConsoleInfo));
    return NIL;
    }
    cso->Free = Free;
    cso->Init = Init;
    cso->Restore = Restore;
    cso->DrawRect = DrawRect;
    cso->EraseRect = EraseRect;
    cso->PutC = PutC;
    cso->GetSize = GetSize;
    console->display = *display;
    console->display.frameBuffer = (void *)FRAMEBUFFER_ADDRESS;
    console->display.totalWidth = VGA_TOTALWIDTH;
    console->display.rowBytes = VGA_ROWBYTES;
    console->saveBits =
        (unsigned char *)console->display.frameBuffer +
        console->display.rowBytes * console->display.height;
    console->window_type = SCM_UNINIT;
    return cso;
}

/bsd/dev/i386/FBConsole.c modified from original.
IOConsoleInfo *FBAllocateVBEConsole(void)
{

IODisplayInfo CurrentIODisplayInfo;
    IOConsoleInfo *cso = (IOConsoleInfo *)IOMalloc(sizeof(IOConsoleInfo));

// 0x1285c is Selected Mode X Resolution.
// 0x12854 is 
  if ((_DAT_0001285c == 0) || (_DAT_00012854 == 0))
  return NIL;
  else {
    if (cso == NIL)
        return NIL;
        _VBEModeInfo2IODisplayInfo(0x12858, &CurrentIODisplayInfo);
    cso->priv = (void *)IOMalloc(sizeof(ConsoleRep));
    if (cso->priv == NIL)
    {
        IOFree(cso, sizeof(IOConsoleInfo));
return NIL;
    }
    cso->Free = Free;
    cso->Init = Init;
    cso->Restore = Restore;
    cso->DrawRect = DrawRect;
    cso->EraseRect = EraseRect;
    cso->PutC = PutC;
    cso->GetSize = GetSize;
    ((ConsolePtr)cso->priv)->display = *display;
    ((ConsolePtr)cso->priv)->window_type = SCM_UNINIT;
    }
    return cso;
}

/* Void VBEModeInfo2IODisplayInfo(ushort 0x12858, uint *param_2)
unit *param_2 is actually IODisplay *param_2 accessed as int's to copy data.
    */
void _VBEModeInfo2IODisplayInfo(ushort *VBEModeInfo,uint *display)
//driverkit/displayDefs.h for the struct of *display.

{
  byte bVar1;
  byte bVar2;
  int iVar3;
 
  *display = (uint)VBEModeInfo[2]; // display[0] = width
  display[1] = (uint)VBEModeInfo[3]; // display[1] = height
  display[2] = (uint)VBEModeInfo[2]; // display[2] = totalWidth (same as width)
  display[3] = (uint)VBEModeInfo[4]; // display[3] = rowBytes (bytes per scan line)
  display[4] = 0; // display[4] = refreshRate (unused or 0)
  display[5] = *(uint *)(VBEModeInfo + 10); // display[5] = framebuffer pointer]
  switch(*(undefined *)(VBEModeInfo + 5)) { //display[6] = bitsPerPixel
  case 2:
    display[6] = 0; // 2 bpp
    break;
  case 8:
    display[6] = 1; // 8 bpp
    break;
  case 0xc:
    display[6] = 2; // 12 bpp
    break;
  case 0xf:
  case 0x10:
    display[6] = 3; // 15/16 bpp
    break;
  case 0x18:
  case 0x20:
    display[6] = 4; // 24/32 bpp
    break;
  default:
    *(byte *)(display + 0x20) = *(byte *)(display + 0x20) | 0x10; // Set DPS flag if unrecognized
    return;
  }
  if ((*(byte *)(VBEModeInfo + 1) & 8) == 0) { // Color Space / Encoding
    display[7] = 1; // IO_OneIsWhiteColorSpace
    iVar3 = 0;
    if (*(char *)(VBEModeInfo + 5) != '\0') {
      do {
        *(undefined *)(iVar3 + 0x20 + (int)display) = 'W'; //IO_SampleTypeGray
        iVar3 = iVar3 + 1;
      } while (iVar3 < (int)(uint)*(byte *)(VBEModeInfo + 5));
    }
  }
  else {
    display[7] = 2; // IO_RGBColorSpace
    if (*(char *)((int)VBEModeInfo + 0xb) == '\x04') {
      iVar3 = 0;
      if (*(char *)(VBEModeInfo + 5) != '\0') {
        do {
          *(undefined *)(iVar3 + 0x20 + (int)display) = 'P'; // IO_SampleTypePseudoColor
          iVar3 = iVar3 + 1;
        } while (iVar3 < (int)(uint)*(byte *)(VBEModeInfo + 5));
      }
    }
    else {
      iVar3 = 0;
      if (*(char *)(VBEModeInfo + 5) != '\0') {
        do {
          *(undefined *)(iVar3 + 0x20 + (int)display) = '-'; // IO_SampleTypeSkip
          iVar3 = iVar3 + 1;
        } while (iVar3 < (int)(uint)*(byte *)(VBEModeInfo + 5));
      }
      bVar1 = *(byte *)(VBEModeInfo + 5);
      bVar2 = *(byte *)((int)VBEModeInfo + 0xd);
      iVar3 = 0;
      if (*(char *)(VBEModeInfo + 6) != '\0') {
        do {
          *(undefined *)((((uint)bVar1 - (uint)bVar2) - iVar3) + 0x1f + (int)display) = 'R';
          iVar3 = iVar3 + 1;
        } while (iVar3 < (int)(uint)*(byte *)(VBEModeInfo + 6));
      }
      bVar1 = *(byte *)(VBEModeInfo + 5);
      bVar2 = *(byte *)((int)VBEModeInfo + 0xf);
      iVar3 = 0;
      if (*(char *)(VBEModeInfo + 7) != '\0') {
        do {
          *(undefined *)((((uint)bVar1 - (uint)bVar2) - iVar3) + 0x1f + (int)display) = 'G';
          iVar3 = iVar3 + 1;
        } while (iVar3 < (int)(uint)*(byte *)(VBEModeInfo + 7));
      }
      bVar1 = *(byte *)(VBEModeInfo + 5);
      bVar2 = *(byte *)((int)VBEModeInfo + 0x11);
      iVar3 = 0;
      if (*(char *)(VBEModeInfo + 8) != '\0') {
        do {
          *(undefined *)((((uint)bVar1 - (uint)bVar2) - iVar3) + 0x1f + (int)display) = 'B';
          iVar3 = iVar3 + 1;
        } while (iVar3 < (int)(uint)*(byte *)(VBEModeInfo + 8));
      }
    }
  }
  display[24] = 2; // display flags IO_DISPLAY_NEEDS_SOFTWARE_GAMMA_CORRECTION
  display[25] = (uint)*VBEModeInfo; // display *paramaters
  display[26] = (uint)VBEModeInfo[3] * (uint)VBEModeInfo[4]; //display memorySize (bytes)
  return;
}

This is the code that creates the unsigned long at kernbootstruct+0x1854 or 0x12854
No links to @evolver56k this time. I'm getting better with pointers and casting so that's a positive.  :P

EDIT (10/May/2025): Added some more routines from the kernel that called on the way down to routine VBEModeInfo2IODisplayInfo(). In the kernel /machdep/i386/ there is some calls to BIOS by the APM. I have no idea how to call those :/
Title: Re: NeXTStep 3.3 running with VESA VBE 2.0 graphics!! (crucial)
Post by: pTeK on June 13, 2025, 03:45:58 AM
Had a quick look at the OpenStep 4.2 version of VGA.config in Ghidra because it supports SVGA 800x600. It seems to have BIOS calls in the code.

Go to top  Forum index