assembly 如何修复操作系统的VBE实现?

zzoitvuj  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(115)

我正在缓慢但稳定地开发一个小型操作系统,我终于认为我有了一些代码(理论上)输出到VESA VBE。然而,我在尝试编译时遇到了一系列错误。我确信我的代码有问题,尽管我不知道是什么问题。我看到了错误,但我不知道如何修复它们。有关更多相关信息,您可以查看一些源代码以了解我的混乱代码:
1.我从here得到了VBE_modeInfo结构体
1.我从previous question中得到了u32 modeInfoPointer = asm volatile ("eax");u32 physical_address = modeInfo.PhysBasePtr + y * modeInfo.LinBytesPerScanLine + x * bytesPerPixel;和很多汇编代码。
Here是我的一长串错误,如果有人好奇的话。我不认为boot.asm是问题所在,因为我没有提到它。在这里,我将kernel.cpp和我的GitHub留给其余的代码:
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;
}

编辑:我将在这里添加其余的相关代码。Shell文件和完整的src在我的GitHub
错误数:

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
zte4gxcn

zte4gxcn1#

好吧,根据所有的热门评论...
我们希望从eax设置modeInfoPointer,因为它保存了VBE指针。
boot.asm中,它从int 0x10得到这个。但是,我们必须把它移到某个地方。当我们跳到start_protected_mode并执行以下操作时,它会被重写:

mov ax, DATA_SEG

所以,我们需要(作为第一个指令的那一点):

mov edi, eax ; save VBE pointer

然后,在jmp KERNEL_LOCATION之前,我们需要:

push edi ; save as first argument to main

此外,我们需要call而不是jmp
然后,在kernel.cpp中,我们需要:

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

还有其他调整。modeInfo的使用与modeInfo.modeInfo-> * 不一致 *
我已经尽我所能纠正了编译错误。几乎可以肯定它仍然是坏的,但应该会让你更进一步。
它应该解决了我们希望modeInfoPointer指向VBE块[AFAICT]的问题。
在下面的代码中,我使用了cpp条件语句来表示旧代码和新代码:

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

#if 1
// new code
#endif

注意:可以通过unifdef -k运行文件来清除此问题
下面是一个针对github回购协议的补丁:

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;

相关问题