OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 12:50 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 12 posts ] 
Author Message
 Post subject: Switching VGA mode with GRUB
PostPosted: Tue Apr 11, 2017 11:31 am 
Offline

Joined: Mon Apr 10, 2017 10:25 am
Posts: 10
hi everyone
I want to switch to the VGA graphic mode. For this I will use GRUB.I switch back to Real Mode for setting the graphic video mode, but I meet a few problems,it just reboots back to GRUB in qemu
i use the code from http://www.rohitab.com/discuss/topic/35 ... -mode/,but seems it dosen't work well.
here is my code:
Code:
MBOOT_HEADER_MAGIC  equ 0x1BADB002
MBOOT_PAGE_ALIGN    equ 1 << 0
MBOOT_MEM_INFO      equ 1 << 1
;MBOOT_GRAPH_MODE    equ 1 << 2
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO ;| MBOOT_GRAPH_MODE
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)

;magic flags checksum (magic + flags + checksum = 0)

[BITS 32]
section .text

dd MBOOT_HEADER_MAGIC
dd MBOOT_HEADER_FLAGS
dd MBOOT_CHECKSUM

;dd 0
;dd 0
;dd 0
;dd 0
;dd 0

;dd 0
;dd 640
;dd 480
;dd 16

[GLOBAL start]
[GLOBAL glb_mboot_ptr]
[EXTERN kern_entry]

start:
    cli

    mov esp, STACK_TOP
    mov ebp, 0
    and esp, 0FFFFFFF0H
    mov [glb_mboot_ptr] , ebx
    call kern_entry

stop:
    hlt
    jmp stop

section .bss
stack:
    resb 32768
glb_mboot_ptr:
    resb 4

STACK_TOP equ $ - stack - 1


Code:
// define our structure
typedef struct __attribute__ ((packed)) {
   unsigned short di, si, bp, sp, bx, dx, cx, ax;
   unsigned short gs, fs, es, ds, eflags;
} regs16_t;

// tell compiler our int32 function is external
extern void int32(unsigned char intnum, regs16_t *regs);

// int32 test
void int32_test()
{
   int y;
   regs16_t regs;
   
   // switch to 320x200x256 graphics mode
   regs.ax = 0x0013;
   int32(0x10, &regs);

   // full screen with blue color (1)
   //memset((char *)0xA0000, 0xff, (320*200));
   
   // draw horizontal line from 100,80 to 100,240 in multiple colors
   //for(y = 0; y < 200; y++)
   //   memset((char *)0xA0000 + (y*320+80), y, 160);
   
   // wait for key
   /*regs.ax = 0x0000;
   int32(0x16, &regs);*/
   
   // switch to 80x25x16 text mode
   //regs.ax = 0x0003;
   //int32(0x10, &regs);
}

int kern_entry()
{
      
   //regs16_t regs;   
   //regs.ax = 0x0013;
   //int32(0x10, &regs);
   int32_test();   
   char* p;   
   int i;
   for(i = 0xA0000; i < 0xAFFFF; i++) {
      p = (char*)i;
      *p = 0xff;   
   }
   return 0;
}


Code:
;
; Protected Mode BIOS Call Functionailty v2.0 - by Napalm
; -------------------------------------------------------
;
; This is code shows how its POSSIBLE to execute BIOS interrupts
; by switch out to real-mode and then back into protected mode.
;
; If you wish to use all or part of this code you must agree
; to the license at the following URL.
;
; License: http://creativecommons.org/licenses/by-sa/2.0/uk/
;         
; Notes: This file is in NASM syntax.
;        Turn off paging before calling these functions.
;        int32() resets all selectors.
;
; C Prototype:
;   void _cdelc int32(unsigned char intnum, regs16_t *regs);
;
; Example of usage:
;   regs.ax = 0x0013;
;   int32(0x10, &regs);
;   memset((char *)0xA0000, 1, (320*200));
;   memset((char *)0xA0000 + (100*320+80), 14, 80);
;   regs.ax = 0x0000;
;   int32(0x16, &regs);
;   regs.ax = 0x0003;
;   int32(0x10, &regs);
;
;
[bits 32]

global int32, _int32

struc regs16_t
   .di   resw 1
   .si   resw 1
   .bp   resw 1
   .sp resw 1
   .bx   resw 1
   .dx   resw 1
   .cx   resw 1
   .ax   resw 1
   .gs   resw 1
   .fs   resw 1
   .es   resw 1
   .ds   resw 1
   .ef resw 1
endstruc

%define INT32_BASE                             0x7C00
%define REBASE(x)                              (((x) - reloc) + INT32_BASE)
%define GDTENTRY(x)                            ((x) << 3)
%define CODE32                                 GDTENTRY(1)   ; 0x08
%define DATA32                                 GDTENTRY(2)   ; 0x10
%define CODE16                                 GDTENTRY(3)   ; 0x18
%define DATA16                                 GDTENTRY(4)   ; 0x20
%define STACK16                                (INT32_BASE - regs16_t_size)


section .text
   int32: use32                               ; by Napalm
   _int32:
      cli                                    ; disable interrupts
      pusha                                  ; save register state to 32bit stack
      mov  esi, reloc                        ; set source to code below
      mov  edi, INT32_BASE                   ; set destination to new base address
      mov  ecx, (int32_end - reloc)          ; set copy size to our codes size
      cld                                    ; clear direction flag (so we copy forward)
      rep  movsb                             ; do the actual copy (relocate code to low 16bit space)
      jmp INT32_BASE                         ; jump to new code location
   reloc: use32                               ; by Napalm
      mov  [REBASE(stack32_ptr)], esp        ; save 32bit stack pointer
      sidt [REBASE(idt32_ptr)]               ; save 32bit idt pointer
      sgdt [REBASE(gdt32_ptr)]               ; save 32bit gdt pointer
      lgdt [REBASE(gdt16_ptr)]               ; load 16bit gdt pointer
      lea  esi, [esp+0x24]                   ; set position of intnum on 32bit stack
      lodsd                                  ; read intnum into eax
      mov  [REBASE(ib)], al                  ; set intrrupt immediate byte from our arguments
      mov  esi, [esi]                        ; read regs pointer in esi as source
      mov  edi, STACK16                      ; set destination to 16bit stack
      mov  ecx, regs16_t_size                ; set copy size to our struct size
      mov  esp, edi                          ; save destination to as 16bit stack offset
      rep  movsb                             ; do the actual copy (32bit stack to 16bit stack)
      jmp  word CODE16:REBASE(p_mode16)      ; switch to 16bit selector (16bit protected mode)
   p_mode16: use16
      mov  ax, DATA16                        ; get our 16bit data selector
      mov  ds, ax                            ; set ds to 16bit selector
      mov  es, ax                            ; set es to 16bit selector
      mov  fs, ax                            ; set fs to 16bit selector
      mov  gs, ax                            ; set gs to 16bit selector
      mov  ss, ax                            ; set ss to 16bit selector
      mov  eax, cr0                          ; get cr0 so we can modify it
      and  al,  ~0x01                        ; mask off PE bit to turn off protected mode
      mov  cr0, eax                          ; set cr0 to result
      jmp  word 0x0000:REBASE(r_mode16)      ; finally set cs:ip to enter real-mode
   r_mode16: use16
      xor  ax, ax                            ; set ax to zero
      mov  ds, ax                            ; set ds so we can access idt16
      mov  ss, ax                            ; set ss so they the stack is valid
      lidt [REBASE(idt16_ptr)]               ; load 16bit idt
      mov  bx, 0x0870                        ; master 8 and slave 112
      call resetpic                          ; set pic's the to real-mode settings
      popa                                   ; load general purpose registers from 16bit stack
      pop  gs                                ; load gs from 16bit stack
      pop  fs                                ; load fs from 16bit stack
      pop  es                                ; load es from 16bit stack
      pop  ds                                ; load ds from 16bit stack
      sti                                    ; enable interrupts
      db 0xCD                                ; opcode of INT instruction with immediate byte
   ib: db 0x00
      cli                                    ; disable interrupts
      xor  sp, sp                            ; zero sp so we can reuse it
      mov  ss, sp                            ; set ss so the stack is valid
      mov  sp, INT32_BASE                    ; set correct stack position so we can copy back
      pushf                                  ; save eflags to 16bit stack
      push ds                                ; save ds to 16bit stack
      push es                                ; save es to 16bit stack
      push fs                                ; save fs to 16bit stack
      push gs                                ; save gs to 16bit stack
      pusha                                  ; save general purpose registers to 16bit stack
      mov  bx, 0x2028                        ; master 32 and slave 40
      call resetpic                          ; restore the pic's to protected mode settings
      mov  eax, cr0                          ; get cr0 so we can modify it
      inc  eax                               ; set PE bit to turn on protected mode
      mov  cr0, eax                          ; set cr0 to result
      jmp  dword CODE32:REBASE(p_mode32)     ; switch to 32bit selector (32bit protected mode)
   p_mode32: use32
      mov  ax, DATA32                        ; get our 32bit data selector
      mov  ds, ax                            ; reset ds selector
      mov  es, ax                            ; reset es selector
      mov  fs, ax                            ; reset fs selector
      mov  gs, ax                            ; reset gs selector
      mov  ss, ax                            ; reset ss selector
      lgdt [REBASE(gdt32_ptr)]               ; restore 32bit gdt pointer
      lidt [REBASE(idt32_ptr)]               ; restore 32bit idt pointer
      mov  esp, [REBASE(stack32_ptr)]        ; restore 32bit stack pointer
      mov  esi, STACK16                      ; set copy source to 16bit stack
      lea  edi, [esp+0x28]                   ; set position of regs pointer on 32bit stack
      mov  edi, [edi]                        ; use regs pointer in edi as copy destination
      mov  ecx, regs16_t_size                ; set copy size to our struct size
      cld                                    ; clear direction flag (so we copy forward)
      rep  movsb                             ; do the actual copy (16bit stack to 32bit stack)
      popa                                   ; restore registers
      sti                                    ; enable interrupts
      ret                                    ; return to caller
      
   resetpic:                                  ; reset's 8259 master and slave pic vectors
      push ax                                ; expects bh = master vector, bl = slave vector
      mov  al, 0x11                          ; 0x11 = ICW1_INIT | ICW1_ICW4
      out  0x20, al                          ; send ICW1 to master pic
      out  0xA0, al                          ; send ICW1 to slave pic
      mov  al, bh                            ; get master pic vector param
      out  0x21, al                          ; send ICW2 aka vector to master pic
      mov  al, bl                            ; get slave pic vector param
      out  0xA1, al                          ; send ICW2 aka vector to slave pic
      mov  al, 0x04                          ; 0x04 = set slave to IRQ2
      out  0x21, al                          ; send ICW3 to master pic
      shr  al, 1                             ; 0x02 = tell slave its on IRQ2 of master
      out  0xA1, al                          ; send ICW3 to slave pic
      shr  al, 1                             ; 0x01 = ICW4_8086
      out  0x21, al                          ; send ICW4 to master pic
      out  0xA1, al                          ; send ICW4 to slave pic
      pop  ax                                ; restore ax from stack
      ret                                    ; return to caller
      
   stack32_ptr:                               ; address in 32bit stack after we
      dd 0x00000000                          ;   save all general purpose registers
      
   idt32_ptr:                                 ; IDT table pointer for 32bit access
      dw 0x0000                              ; table limit (size)
      dd 0x00000000                          ; table base address
      
   gdt32_ptr:                                 ; GDT table pointer for 32bit access
      dw 0x0000                              ; table limit (size)
      dd 0x00000000                          ; table base address
      
   idt16_ptr:                                 ; IDT table pointer for 16bit access
      dw 0x03FF                              ; table limit (size)
      dd 0x00000000                          ; table base address
      
   gdt16_base:                                ; GDT descriptor table
      .null:                                 ; 0x00 - null segment descriptor
         dd 0x00000000                      ; must be left zero'd
         dd 0x00000000                      ; must be left zero'd
         
      .code32:                               ; 0x01 - 32bit code segment descriptor 0xFFFFFFFF
         dw 0xFFFF                          ; limit  0:15
         dw 0x0000                          ; base   0:15
         db 0x00                            ; base  16:23
         db 0x9A                            ; present, iopl/0, code, execute/read
         db 0xCF                            ; 4Kbyte granularity, 32bit selector; limit 16:19
         db 0x00                            ; base  24:31
         
      .data32:                               ; 0x02 - 32bit data segment descriptor 0xFFFFFFFF
         dw 0xFFFF                          ; limit  0:15
         dw 0x0000                          ; base   0:15
         db 0x00                            ; base  16:23
         db 0x92                            ; present, iopl/0, data, read/write
         db 0xCF                            ; 4Kbyte granularity, 32bit selector; limit 16:19
         db 0x00                            ; base  24:31
         
      .code16:                               ; 0x03 - 16bit code segment descriptor 0x000FFFFF
         dw 0xFFFF                          ; limit  0:15
         dw 0x0000                          ; base   0:15
         db 0x00                            ; base  16:23
         db 0x9A                            ; present, iopl/0, code, execute/read
         db 0x0F                            ; 1Byte granularity, 16bit selector; limit 16:19
         db 0x00                            ; base  24:31
         
      .data16:                               ; 0x04 - 16bit data segment descriptor 0x000FFFFF
         dw 0xFFFF                          ; limit  0:15
         dw 0x0000                          ; base   0:15
         db 0x00                            ; base  16:23
         db 0x92                            ; present, iopl/0, data, read/write
         db 0x0F                            ; 1Byte granularity, 16bit selector; limit 16:19
         db 0x00                            ; base  24:31
         
   gdt16_ptr:                                 ; GDT table pointer for 16bit access
      dw gdt16_ptr - gdt16_base - 1          ; table limit (size)
      dd gdt16_base                          ; table base address
      
   int32_end:                                 ; end marker (so we can copy the code)
   
   


can somenoe give me some advice?
Sorry for my poor English


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Tue Apr 11, 2017 1:08 pm 
Offline
Member
Member
User avatar

Joined: Fri Jan 27, 2017 12:15 pm
Posts: 149
Location: Belgium
First off, uncomment all the
Code:
dd
lines at the beginning. These are the flags that pass the graphics mode information to grub, so that it can set your graphics mode before putting you into protected mode (more info: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html). Then, just before
Code:
call kern_entry
, push ebx to the stack with
Code:
push ebx
. You don't need to switch back to real mode. Then, to draw on the screen, you need to get the framebuffer pointer (in the grub command line, type the
Code:
lspci -i
, and under VGA, get the last eight digits of the hex string), and you can start modifying the screen straight away!

Example:

Code:
MBOOT_HEADER_MAGIC  equ 0x1BADB002
MBOOT_PAGE_ALIGN    equ 1 << 0
MBOOT_MEM_INFO      equ 1 << 1
;MBOOT_GRAPH_MODE    equ 1 << 2
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO ;| MBOOT_GRAPH_MODE
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)

;magic flags checksum (magic + flags + checksum = 0)

[BITS 32]
section .text

dd MBOOT_HEADER_MAGIC
dd MBOOT_HEADER_FLAGS
dd MBOOT_CHECKSUM

dd 0
dd 0
dd 0
dd 0
dd 0

dd 0
dd 800 ; width
dd 600 ; height
dd 32 ; bpp

[GLOBAL start]
[GLOBAL glb_mboot_ptr]
[EXTERN kern_entry]

start:
    cli

    mov esp, STACK_TOP
    mov ebp, 0
    and esp, 0FFFFFFF0H
    mov [glb_mboot_ptr] , ebx

    push ebx
    call kern_entry

stop:
    hlt
    jmp stop

section .bss
stack:
    resb 32768
glb_mboot_ptr:
    resb 4

STACK_TOP equ $ - stack - 1

Code:
extern void int32(unsigned char intnum, regs16_t *regs);

void kern_entry()
{   
   unsigned int* buffer = (unsigned int*) 0xE0000000;
   for (int i = 0; i < 800 * 600; i++)
      buffer[i] = 0x00FF00FF;
   while (1) {}
}


You won't need the other code anymore. Also, further down the line, you won't want to hard code the framebuffer pointer, as it varies from device to device, but grub gives you a vbe information structure, with the pointer for you to use. But that's for another topic.
Ask if you need more help, or if it doesn't work.

_________________
AQUA OS: https://obiwac.wordpress.com/aqua-os/


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Tue Apr 11, 2017 8:44 pm 
Offline

Joined: Mon Apr 10, 2017 10:25 am
Posts: 10
obiwac wrote:
First off, uncomment all the
Code:
dd
lines at the beginning. These are the flags that pass the graphics mode information to grub, so that it can set your graphics mode before putting you into protected mode (more info: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html). Then, just before
Code:
call kern_entry
, push ebx to the stack with
Code:
push ebx
. You don't need to switch back to real mode. Then, to draw on the screen, you need to get the framebuffer pointer (in the grub command line, type the
Code:
lspci -i
, and under VGA, get the last eight digits of the hex string), and you can start modifying the screen straight away!

thank you very much,but it still dosen't work. I'm wanting just a simple 320 x 200 8bit screen.I don't know what's wrong with it


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Wed Apr 12, 2017 2:15 am 
Offline
Member
Member
User avatar

Joined: Sun Sep 19, 2010 10:05 pm
Posts: 1074
8-bits may not be an option. Try something a little more common, like 640x480x32 bits.

_________________
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Wed Apr 12, 2017 11:21 am 
Offline
Member
Member
User avatar

Joined: Fri Jan 27, 2017 12:15 pm
Posts: 149
Location: Belgium
If you're just wanting 320x200x8, then you can write a pure protected mode driver, that'll work for all graphics cards.


It's in C++, but if you want, I think I have the same code lying around in C, and I could post it here.

_________________
AQUA OS: https://obiwac.wordpress.com/aqua-os/


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Wed Apr 12, 2017 7:10 pm 
Offline

Joined: Mon Apr 10, 2017 10:25 am
Posts: 10
obiwac wrote:
If you're just wanting 320x200x8, then you can write a pure protected mode driver, that'll work for all graphics cards.


It's in C++, but if you want, I think I have the same code lying around in C, and I could post it here.

thank you very much


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Thu Apr 13, 2017 6:52 am 
Offline
Member
Member
User avatar

Joined: Mon Feb 22, 2016 4:40 am
Posts: 59
Location: United Kingdom
I might be talking through my arse here, but I had similar problems a few months back. Turns out you need to actually specify what mode you want in your grub.cfg before it'll actually be nice enough to change things.

Something like this, I believe:

Code:
menuentry "MyOS" {
   multiboot /boot/myos.bin
   set gfxpayload=1024x768x32

   boot
}


Hopefully that'll get you what you want :-)

_________________
Current developing Tupai, a monolithic x86 operating system
http://zesterer.homenet.org/projects.shtml


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Thu Apr 13, 2017 8:49 am 
Offline
Member
Member
User avatar

Joined: Fri Jan 27, 2017 12:15 pm
Posts: 149
Location: Belgium
zesterer wrote:
I might be talking through my arse here, but I had similar problems a few months back. Turns out you need to actually specify what mode you want in your grub.cfg before it'll actually be nice enough to change things.

Something like this, I believe:

Code:
menuentry "MyOS" {
   multiboot /boot/myos.bin
   set gfxpayload=1024x768x32

   boot
}


Hopefully that'll get you what you want :-)


Actually, that just changes the graphics mode for grub. But before switching to pmode, grub changes to 80x25 text mode. So, you have to tell it what mode you want with the multiboot flags.

_________________
AQUA OS: https://obiwac.wordpress.com/aqua-os/


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Thu Apr 13, 2017 9:39 am 
Offline
Member
Member
User avatar

Joined: Mon Feb 22, 2016 4:40 am
Posts: 59
Location: United Kingdom
obiwac wrote:
zesterer wrote:
I might be talking through my arse here, but I had similar problems a few months back. Turns out you need to actually specify what mode you want in your grub.cfg before it'll actually be nice enough to change things.

Something like this, I believe:

Code:
menuentry "MyOS" {
   multiboot /boot/myos.bin
   set gfxpayload=1024x768x32

   boot
}


Hopefully that'll get you what you want :-)


Actually, that just changes the graphics mode for grub. But before switching to pmode, grub changes to 80x25 text mode. So, you have to tell it what mode you want with the multiboot flags.


That's not the case. If you wish to change GRUB's graphics mode, you use "gfxmode". However, "gfxpayload" defines the graphics mode that is passed on to the OS before booting.

_________________
Current developing Tupai, a monolithic x86 operating system
http://zesterer.homenet.org/projects.shtml


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Thu Apr 13, 2017 9:50 am 
Offline
Member
Member
User avatar

Joined: Fri Jan 27, 2017 12:15 pm
Posts: 149
Location: Belgium
Hmm... what version of grub are you using?

_________________
AQUA OS: https://obiwac.wordpress.com/aqua-os/


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Fri Apr 14, 2017 11:23 am 
Offline
Member
Member
User avatar

Joined: Mon Feb 22, 2016 4:40 am
Posts: 59
Location: United Kingdom
obiwac wrote:
Hmm... what version of grub are you using?


GRUB 2.02~rc1. This was the primary problem I had when requesting graphics modes, and gfxpayload changes this.

_________________
Current developing Tupai, a monolithic x86 operating system
http://zesterer.homenet.org/projects.shtml


Top
 Profile  
 
 Post subject: Re: Switching VGA mode with GRUB
PostPosted: Sun Apr 16, 2017 11:33 pm 
Offline

Joined: Mon Apr 10, 2017 10:25 am
Posts: 10
Thank you all for your attention, i have sloved the problem as i do this viewtopic.php?f=1&t=31524


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 43 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group