1

I'm slowly but surely working on a small operating system and I finally think I have some code in place that should (in theory) output to VESA VBE. I am, however, getting a slew of errors when trying to compile. I'm sure there's something wrong with my code, though I have no clue what. I see the errors, but I don't know how to fix them. For more relevant information, you can check out a few sources for my mess of code:

  1. I got the VBE_modeInfo struct from here
  2. I got the u32 modeInfoPointer = asm volatile ("eax");, u32 physical_address = modeInfo.PhysBasePtr + y * modeInfo.LinBytesPerScanLine + x * bytesPerPixel;, and a lot of my assembly code from a previous question

Here is my long list of errors, if anyone is curious. I don't think boot.asm is the issue, considering I got no errors mentioning it. Here I'll leave kernel.cpp and my GitHub for the rest of the code:

kernel.cpp:

typedef unsigned char uint8_t;
typedef unsigned char u8;
typedef unsigned short uint16_t;
typedef unsigned int u32;
typedef u32 size_t;
typedef unsigned long phys_bytes;
#define SCREEN_WIDTH (int)(modeInfo.XResolution)
#define SCREEN_HEIGHT (int)(modeInfo.YResolution)
#define BPP 32
#define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
#define FPS 30
#define PIT_HERTZ 1193131.666
#define CLOCK_HIT (int)(PIT_HERTZ/FPS)
#define KEY_LEFT 0x4B
#define KEY_UP 0x48
#define KEY_RIGHT 0x4D
#define KEY_DOWN 0x50

typedef struct VBE_modeInfo{
/*  Mandatory information for all VBE revisions */
uint16_t ModeAttributes;   
uint8_t WinAAttributes;    
uint8_t WinBAttributes;    
uint16_t WinGranularity;   
uint16_t WinSize;          
uint16_t WinASegment;      
uint16_t WinBSegment;      
phys_bytes WinFuncPtr;     
uint16_t BytesPerScanLine; 
/* Mandatory information for VBE 1.2 and above */

uint16_t XResolution;       
uint16_t YResolution;       
uint8_t XCharSize;          
uint8_t YCharSize;          
uint8_t NumberOfPlanes;     
uint8_t BitsPerPixel;       
uint8_t NumberOfBanks;      
uint8_t MemoryModel;        
uint8_t BankSize;           
uint8_t NumberOfImagePages; 
uint8_t Reserved1;          
/* Direct Color fields (required for direct/6 and YUV/7 memory models) */

uint8_t RedMaskSize;         /* size of direct color red mask in bits */
uint8_t RedFieldPosition;    /* bit position of lsb of red mask */
uint8_t GreenMaskSize;       /* size of direct color green mask in bits */
uint8_t GreenFieldPosition;  /* bit position of lsb of green mask */
uint8_t BlueMaskSize;        /* size of direct color blue mask in bits */
uint8_t BlueFieldPosition;   /* bit position of lsb of blue mask */
uint8_t RsvdMaskSize;        /* size of direct color reserved mask in bits */
uint8_t RsvdFieldPosition;   /* bit position of lsb of reserved mask */
uint8_t DirectColorModeInfo; /* direct color mode attributes */

/* Mandatory information for VBE 2.0 and above */
phys_bytes PhysBasePtr; 
uint8_t Reserved2[4];   
uint8_t Reserved3[2];   
/* Mandatory information for VBE 3.0 and above */
uint16_t LinBytesPerScanLine;  /* bytes per scan line for linear modes */
uint8_t BnkNumberOfImagePages; /* number of images for banked modes */
uint8_t LinNumberOfImagePages; /* number of images for linear modes */
uint8_t LinRedMaskSize;        /* size of direct color red mask (linear modes) */
uint8_t LinRedFieldPosition;   /* bit position of lsb of red mask (linear modes) */
uint8_t LinGreenMaskSize;      /* size of direct color green mask (linear modes) */
uint8_t LinGreenFieldPosition; /* bit position of lsb of green mask (linear  modes) */
uint8_t LinBlueMaskSize;       /* size of direct color blue mask (linear modes) */
uint8_t LinBlueFieldPosition;  /* bit position of lsb of blue mask (linear modes ) */
uint8_t LinRsvdMaskSize;       /* size of direct color reserved mask (linear modes) */
uint8_t LinRsvdFieldPosition;  /* bit position of lsb of reserved mask (linear modes) */
u32 MaxPixelClock;        /* maximum pixel clock (in Hz) for graphics mode */
uint8_t Reserved4[190];        /* remainder of ModeInfoBlock */
} VBE_modeInfo;

u32 modeInfoPointer = asm volatile ("eax");
#define modeInfo (struct VBE_modeInfo *)modeInfoPointer

static u32 *BUFFER = (u32 *) modeInfo.PhysBasePtr;

// double buffers
u32 _sbuffers[2][SCREEN_SIZE];
u32 _sback = 0;

#define CURRENT (_sbuffers[_sback])
#define SWAP() (_sback = 1 - _sback)

#define screen_buffer() (_sbuffers[_sback])

static inline void outb(uint16_t port, uint8_t val)
{
    asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
}

#define bytesPerPixel ((modeInfo->BitsPerPixel + 7) / 8)

void screen_set(u32 color,int x,int y) {
    u32 physical_address = modeInfo.PhysBasePtr + y * modeInfo.LinBytesPerScanLine + x * bytesPerPixel;
    _sbuffers[_sback][physical_address]=color;
}

static inline uint8_t inb(uint16_t port)
{
    uint8_t ret;
    asm volatile ( "inb %1, %0"
                   : "=a"(ret)
                   : "Nd"(port) );
    return ret;
}

const unsigned char font[128-32][8] = {
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0020 (space)
         /*deleted to help with length of code...*/
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}    // U+007F
};

static inline void *memcpy(void *dst, const void *src, size_t n)
{
    u8 *d = (u8*)dst;
    const u8 *s = (const u8*)src;

    while (n-- > 0) {
        *d++ = *s++;
    }

    return d;
}

void screen_swap() {
    memcpy(BUFFER, CURRENT, SCREEN_SIZE);
    SWAP();
}

unsigned read_pit(void) {
    unsigned count = 0;
 
    // al = channel in bits 6 and 7, remaining bits clear
    outb(0x43,0b0000000);
 
    count = inb(0x40);          // Low byte
    count |= inb(0x40)<<8;      // High byte
 
    return count;
}
 
void draw_char(char c, int x, int y, u32 color)
{
    const unsigned char *glyph = font[(int)c-32];
 
    for(int cy=0;cy<8;cy++){
        for(int cx=0;cx<8;cx++){
            if(((int)glyph[cy]&(1<<cx))==(1<<cx)){
                screen_set(color,x+cx,y+cy);
            }
        } 
    }
}

void draw_string(const char * s, int x, int y, u32 color) {
    int i = 0;
    while(s[i] != false) {
        draw_char(s[i],x+(i*8),y,color);
        i++;
    }
}

void draw_rect(int pos_x, int pos_y, int w, int h, u32 color) {
    for(int y = 0; y<h; y++) {
        for(int x = 0; x<w; x++) {
            screen_set(color,x+pos_x,y+pos_y);
        }
    }
}

static void render(int c0, int c1) {
    //draw_rect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,0);
    //draw_string("Hello, reader. This is written text.", 100, 180, 16777215);
    //draw_string("If this is displayed, my code works.", 100+c0, 100+c1, 16777215);
}

extern "C" void main(){
    
    int clock = 0;
    int incC1 = 0;
    int incC0 = 0;
    while(true) {
        uint16_t scancode = (uint16_t) inb(0x60);
        clock++;
        if(read_pit()!= 0 && clock == CLOCK_HIT) {
            if(scancode == KEY_LEFT) {
                incC0--;
            }else if(scancode == KEY_RIGHT) {
                incC0++;
            }
            if(scancode == KEY_DOWN) {
                incC1++;
            }else if(scancode == KEY_UP) {
                incC1--;
            }
            clock = 0;
            render(incC0,incC1);
            screen_swap();
        }
    }

    return;
}

EDIT: I'll add the rest of the relevant code here. Shell file and full src on my GitHub:

errors:

kernel.cpp:85:23: error: expected primary-expression before 'asm'
   85 | u32 modeInfoPointer = asm volatile ("eax");
      |                       ^~~
kernel.cpp:88:39: error: request for member 'PhysBasePtr' in 'modeInfoPointer', which is of non-class type 'u32' {aka 'unsigned int'}
   88 | static u32 *BUFFER = (u32 *) modeInfo.PhysBasePtr;
      |                                       ^~~~~~~~~~~
kernel.cpp:17:37: error: request for member 'XResolution' in 'modeInfoPointer', which is of non-class type 'u32' {aka 'unsigned int'}
   17 | #define SCREEN_WIDTH (int)(modeInfo.XResolution)
      |                                     ^~~~~~~~~~~
kernel.cpp:20:22: note: in expansion of macro 'SCREEN_WIDTH'
   20 | #define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
      |                      ^~~~~~~~~~~~
kernel.cpp:91:18: note: in expansion of macro 'SCREEN_SIZE'
   91 | u32 _sbuffers[2][SCREEN_SIZE];
      |                  ^~~~~~~~~~~
kernel.cpp:18:38: error: request for member 'YResolution' in 'modeInfoPointer', which is of non-class type 'u32' {aka 'unsigned int'}
   18 | #define SCREEN_HEIGHT (int)(modeInfo.YResolution)
      |                                      ^~~~~~~~~~~
kernel.cpp:20:37: note: in expansion of macro 'SCREEN_HEIGHT'
   20 | #define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
      |                                     ^~~~~~~~~~~~~
kernel.cpp:91:18: note: in expansion of macro 'SCREEN_SIZE'
   91 | u32 _sbuffers[2][SCREEN_SIZE];
      |                  ^~~~~~~~~~~
kernel.cpp: In function 'void screen_set(u32, int, int)':
kernel.cpp:107:37: error: request for member 'PhysBasePtr' in 'modeInfoPointer', which is of non-class type 'u32' {aka
unsigned int'}
  107 |     u32 physical_address = modeInfo.PhysBasePtr + y * modeInfo.LinBytesPerScanLine + x * bytesPerPixel;
      |                                     ^~~~~~~~~~~
kernel.cpp:107:64: error: request for member 'LinBytesPerScanLine' in 'modeInfoPointer', which is of non-class type 'u3
' {aka 'unsigned int'}
  107 |     u32 physical_address = modeInfo.PhysBasePtr + y * modeInfo.LinBytesPerScanLine + x * bytesPerPixel;
      |                                                                ^~~~~~~~~~~~~~~~~~~
kernel.cpp:104:33: error: base operand of '->' is not a pointer
  104 | #define bytesPerPixel ((modeInfo->BitsPerPixel + 7) / 8)
      |                                 ^~
kernel.cpp:107:90: note: in expansion of macro 'bytesPerPixel'
  107 |     u32 physical_address = modeInfo.PhysBasePtr + y * modeInfo.LinBytesPerScanLine + x * bytesPerPixel;
      |                                                                                          ^~~~~~~~~~~~~
kernel.cpp:108:5: error: '_sbuffers' was not declared in this scope
  108 |     _sbuffers[_sback][physical_address]=color;
      |     ^~~~~~~~~
kernel.cpp: In function 'void screen_swap()':
kernel.cpp:94:18: error: '_sbuffers' was not declared in this scope
   94 | #define CURRENT (_sbuffers[_sback])
      |                  ^~~~~~~~~
kernel.cpp:232:20: note: in expansion of macro 'CURRENT'
  232 |     memcpy(BUFFER, CURRENT, SCREEN_SIZE);
      |                    ^~~~~~~
kernel.cpp:17:37: error: request for member 'XResolution' in 'modeInfoPointer', which is of non-class type 'u32' {aka 'unsigned int'}
   17 | #define SCREEN_WIDTH (int)(modeInfo.XResolution)
      |                                     ^~~~~~~~~~~
kernel.cpp:20:22: note: in expansion of macro 'SCREEN_WIDTH'
   20 | #define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
      |                      ^~~~~~~~~~~~
kernel.cpp:232:29: note: in expansion of macro 'SCREEN_SIZE'
  232 |     memcpy(BUFFER, CURRENT, SCREEN_SIZE);
      |                             ^~~~~~~~~~~
kernel.cpp:18:38: error: request for member 'YResolution' in 'modeInfoPointer', which is of non-class type 'u32' {aka 'unsigned int'}
   18 | #define SCREEN_HEIGHT (int)(modeInfo.YResolution)
      |                                      ^~~~~~~~~~~
kernel.cpp:20:37: note: in expansion of macro 'SCREEN_HEIGHT'
   20 | #define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
      |                                     ^~~~~~~~~~~~~
kernel.cpp:232:29: note: in expansion of macro 'SCREEN_SIZE'
  232 |     memcpy(BUFFER, CURRENT, SCREEN_SIZE);
      |                             ^~~~~~~~~~~

boot.asm:

[org 0x7c00]                        
KERNEL_LOCATION equ 0x1000
                                    
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x8000
mov [BOOT_DISK], dl

;Get video mode info
mov ax, 4f01h
mov cx, 105h
mov di, modeInfo 
int 10h

mov eax, modeInfo
mov bx, KERNEL_LOCATION
mov dh, 32

mov ah, 0x02
mov al, dh 
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
mov dl, [BOOT_DISK]
int 0x13

                                    
mov ax, 0x4F02   ; set VBE mode
mov bx, 0x4118   ; VBE mode number
int 0x10         ; call VBE BIOS
cmp ax, 0x004F   ; test for error
jne error

CODE_SEG equ GDT_code - GDT_start
DATA_SEG equ GDT_data - GDT_start

cli
lgdt [GDT_descriptor]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp CODE_SEG:start_protected_mode

jmp $

modeInfo    TIMES 256 db 0

error:
   stc
   ret

BOOT_DISK: db 0

GDT_start:
    GDT_null:
        dd 0x0
        dd 0x0

    GDT_code:
        dw 0xffff
        dw 0x0
        db 0x0
        db 0b10011010
        db 0b11001111
        db 0x0

    GDT_data:
        dw 0xffff
        dw 0x0
        db 0x0
        db 0b10010010
        db 0b11001111
        db 0x0

GDT_end:

GDT_descriptor:
    dw GDT_end - GDT_start - 1
    dd GDT_start


[bits 32]
start_protected_mode:
    mov ax, DATA_SEG
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x00090000     ; 32 bit stack base pointer
    mov ebp, esp            ; Only if you need this!

    jmp KERNEL_LOCATION

                                     
 
times 510-($-$$) db 0              
dw 0xaa55
  • 1
    Please post all code and errors into the question and not as a an external link. External links can go away or become inaccessible which will make the question useless for future readers. Also, please ensure the code is a [mre]. – kaylum Jul 24 '22 at 20:15
  • Read up on how inline assembly syntax work. Don't just guess. – fuz Jul 24 '22 at 20:22
  • Also, I can't find `asm volatile ("eax")` anywhere in your previous question (or this one for that matter). Why do you omit code that you know causes problems from your question? – fuz Jul 24 '22 at 20:23
  • @fuz It's on line 85 of `kernel.cpp`. I added a whole bunch of code since my last question, including the line containing that. I don't think I've omitted any erroneous code... –  Jul 24 '22 at 20:28
  • @Kai How do you expect `modeInfoPointer = asm volatile ("eax")` to work? – fuz Jul 24 '22 at 20:32
  • @fuz Well, I thought It would put what's stored at `eax` into `modeInfoPointer`, though I'm guessing it's very wrong. –  Jul 24 '22 at 20:35
  • 2
    @Kai Don't guess, read the documentation! `asm (...)` is a statement. It does not have a value and cannot be assigned to a variable. Additionally, static variables can only have constant initialisers and the contents of `eax` are not a constant. You'll have to (as the answer you refer to says) write actual code to set up the variable with the pointer. – fuz Jul 24 '22 at 20:50
  • See: https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables you want: `register u32 *ptr asm("rax");` But what you really want is a full asm block with constraints – Craig Estey Jul 24 '22 at 20:52
  • @CraigEstey I'm sorry, I don't quite understand. Is that to replace `u32 modeInfoPointer = asm volatile ("eax");`? Why is it accessing `rax`? –  Jul 24 '22 at 21:03
  • @fuz Sorry for my incompetency, I try to read the documentation but it can get confusing. –  Jul 24 '22 at 21:15
  • @Kai There's no need to be sorry. Inline assembly is known to be difficult. – fuz Jul 24 '22 at 21:17
  • @CraigEstey That will not work either; the only supported use of this syntax is forcing an operand to an `asm` statement to live in a particular register when the statement is executed. It does not reserve a register for the whole execution of the program or during initialisation. OP will have to figure out a way to do the handover (e.g. by having the boot loader pass the pointer as an argument to the kernel's main function). – fuz Jul 24 '22 at 21:19
  • 1
    Why are you retrieving video mode information for mode **105h** and then later setup the video mode **0x4118**. That's gonna give a whole lot of problems! Don't just copy snippets of code from everywhere. *You must understand what the code does before you incorporate it into your program*. – Sep Roland Jul 24 '22 at 21:24
  • @fuz yes that's why I said OP needed a full asm block with constraints. In conjunction with an "r" constraint it will use rax – Craig Estey Jul 24 '22 at 21:37
  • @CraigEstey What exactly does that mean? Why will it use rax and what for? What do you mean by "a full asm block"? –  Jul 24 '22 at 21:39
  • 1
    @CraigEstey The objective with that `asm` block was to obtain the contents of `eax` before the `main` function of the kernel is called. It cannot be achieved with `asm` blocks; you have to either change how the pointer is passed to `main` (e.g. by obeying the calling convention) or write `main` itself in assembly to have full control over what is in which register. – fuz Jul 24 '22 at 21:53
  • @fuz Yes, _I_ get it [and did before]. OP wanted to have `modeInfoPointer` in a _specific_ register. The syntax/method was wrong--corrected in the link. And, BTW, the duration is the full block scope (unlike just an inline asm block). `asm(rxx)` on a `register` [or global] variable is completely different--it is _not_ an asm "block". Using `rax` for `rxx` is a bad choice because it gets clobbered (`r12` is better as it's callee preserved). Whether that did anything useful was the second issue and I [again] said OP needed a full inline asm block to do anything useful. – Craig Estey Jul 24 '22 at 22:27
  • 1
    @CraigEstey No, he did not. He wanted (as was recommended to him in the previous question) to have that variable be initialised with the contents of `eax` at kernel start. This is not supported by C. After the kernel starts, I don't think he cares if the variable is still held in `eax`. – fuz Jul 24 '22 at 22:44

1 Answers1

1

Okay, based on all the top comments ...

We want modeInfoPointer to be set from eax because that holds the VBE pointer.

In boot.asm, it gets this from int 0x10. But, we have to move this somewhere. It gets clobbered when we jump to start_protected_mode and do:

mov ax, DATA_SEG

So, we need (as the first instruction of that):

mov edi, eax ; save VBE pointer

Then, just before jmp KERNEL_LOCATION, we need:

push edi ; save as first argument to main

Also, we want call instead of jmp

Then, in kernel.cpp, we want:

struct VBE_modeInfo *modeInfoPointer;
extern "C" void main(struct VBE_modeInfo *vbe)
{
    modeInfoPointer = vbe;

There are other adjustments. Use of modeInfo is inconsistent with modeInfo. and modeInfo->

I've corrected the compilation errors as best I can. It is almost certainly still broken but should get you a bit farther.

It should fix the issue that we want modeInfoPointer to point to the VBE block [AFAICT].


In the code below, I've used cpp conditionals to denote old vs. new code:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

Note: this can be cleaned up by running the file through unifdef -k


Here is a patch against the github repo:

diff --git a/src/OS.bin b/src/OS.bin
deleted file mode 100644
index 2957814..0000000
Binary files a/src/OS.bin and /dev/null differ
diff --git a/src/boot.asm b/src/boot.asm
index 0ee58af..a41730a 100644
--- a/src/boot.asm
+++ b/src/boot.asm
@@ -83,6 +83,7 @@ GDT_descriptor:

 [bits 32]
 start_protected_mode:
+   mov edi, eax    ; save VBE pointer
     mov ax, DATA_SEG
     mov ds, ax
     mov es, ax
@@ -92,9 +93,8 @@ start_protected_mode:
     mov esp, 0x00090000     ; 32 bit stack base pointer
     mov ebp, esp            ; Only if you need this!

-    jmp KERNEL_LOCATION
-
-
+   push edi                ; save as first argument to main
+    call KERNEL_LOCATION

 times 510-($-$$) db 0
 dw 0xaa55
diff --git a/src/kernel.cpp b/src/kernel.cpp
index 79ef409..49282bb 100644
--- a/src/kernel.cpp
+++ b/src/kernel.cpp
@@ -14,8 +14,13 @@ typedef unsigned short uint16_t;
 typedef unsigned int u32;
 typedef u32 size_t;
 typedef unsigned long phys_bytes;
+#if 0
 #define SCREEN_WIDTH (int)(modeInfo.XResolution)
 #define SCREEN_HEIGHT (int)(modeInfo.YResolution)
+#else
+#define SCREEN_WIDTH (int)(modeInfo->XResolution)
+#define SCREEN_HEIGHT (int)(modeInfo->YResolution)
+#endif
 #define BPP 32
 #define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
 #define FPS 30
@@ -82,16 +87,28 @@ u32 MaxPixelClock;        /* maximum pixel clock (in Hz) for graphics mode */
 uint8_t Reserved4[190];        /* remainder of ModeInfoBlock */
 } VBE_modeInfo;

+#if 0
 u32 modeInfoPointer = asm volatile ("eax");
 #define modeInfo (struct VBE_modeInfo *)modeInfoPointer
+#else
+struct VBE_modeInfo *modeInfoPointer;
+#define modeInfo modeInfoPointer
+#endif

-static u32 *BUFFER = (u32 *) modeInfo.PhysBasePtr;
+static u32 *BUFFER = (u32 *) modeInfo->PhysBasePtr;

 // double buffers
+#if 0
 u32 _sbuffers[2][SCREEN_SIZE];
+#else
+u32 *_sbuffers;
+#endif
 u32 _sback = 0;

-#define CURRENT (_sbuffers[_sback])
+#define SBUF(_y,_x) \
+   _sbuffers[((_y) * SCREEN_SIZE) + _x]
+
+#define CURRENT &SBUF(0,0)
 #define SWAP() (_sback = 1 - _sback)

 #define screen_buffer() (_sbuffers[_sback])
@@ -103,9 +120,26 @@ static inline void outb(uint16_t port, uint8_t val)

 #define bytesPerPixel ((modeInfo->BitsPerPixel + 7) / 8)

+#ifndef NULL
+//#define NULL nullptr
+#include <cstddef>
+#include <cstdlib>
+#endif
+
 void screen_set(u32 color,int x,int y) {
+#if 0
     u32 physical_address = modeInfo.PhysBasePtr + y * modeInfo.LinBytesPerScanLine + x * bytesPerPixel;
+#else
+    u32 physical_address = modeInfo->PhysBasePtr + y * modeInfo->LinBytesPerScanLine + x * bytesPerPixel;
+#endif
+#if 0
     _sbuffers[_sback][physical_address]=color;
+#else
+   if (_sbuffers == NULL)
+       _sbuffers = (u32 *) malloc(sizeof(u32) * 2 * SCREEN_SIZE);
+
+    SBUF(_sback,physical_address)=color;
+#endif
 }

 static inline uint8_t inb(uint16_t port)
@@ -280,8 +314,13 @@ static void render(int c0, int c1) {
     //draw_string("If this is displayed, my code works.", 100+c0, 100+c1, 16777215);
 }

+#if 0
 extern "C" void main(){
-
+#else
+extern "C" void main(struct VBE_modeInfo *vbe) {
+   modeInfoPointer = vbe;
+#endif
+
     int clock = 0;
     int incC1 = 0;
     int incC0 = 0;
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • unfortunately your edits wouldn't compile because it doesn't recognize ``. I think this has to do with not having access to external libraries. Please let me know if there is a way to fix this. –  Jul 25 '22 at 23:25
  • @Kai `cstddef` is the C++ wrapper for the C include `stddef.h`. So, you could try that. Your extension is `.cpp` so it should default to C++ but it might be compiling as C. Since this code executes early, I'd do it in pure C (i.e. rename to `kernel.c`). Your `fix.patch` has CRLF line terminators instead of just LF, so that might be another issue. The fix for your initial issue is just a few lines, so you could edit it in manually. The `_sbuffers` patch is because it must be a pointer because you can't declare a static array that has variable dimensions. Do you have a `malloc` impl yet? – Craig Estey Jul 25 '22 at 23:55
  • Nope, so that was another thing I was iffy about. I think it should be easy enough to implement, though. –  Jul 25 '22 at 23:57
  • Okay, so I looked around, and it seems malloc has a lot that goes into it. Do you know if there is any inline asm thing I can do to make it simpler? –  Jul 26 '22 at 00:06
  • To get you going, you could just have a _huge_ static buffer and just linearly alloc from it (vs. a full blown `malloc` impl). Where the `malloc` call was, you could do: `static char hidden[2 * 1920 * 1024]; if (_sbuffers == NULL) _sbuffers = hidden;` Access through `_sbuffers` is still required to get the buffer flip and _actual_ geometry – Craig Estey Jul 26 '22 at 00:07
  • 1
    Here's a cheap `malloc`. There is _no_ `free`. `void * malloc(size_t len) { static size_t curoff = 0; static char space[1 * 1024 * 1024 * 1024]; void *ptr = NULL; if ((curoff + len) < sizeof(space)) { ptr = &space[curoff]; curoff += len; } return ptr; }` – Craig Estey Jul 26 '22 at 00:10
  • Thanks, this is super helpful! Sadly, I got another compilation error :( . Now it's mad about `` (I converted it to this because I assumed it would like this better than ``) –  Jul 26 '22 at 00:15
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/246755/discussion-between-craig-estey-and-kai). – Craig Estey Jul 26 '22 at 00:15