Page 1 of 1

How can I enter Real Mode after GRUB?

Posted: Sat Oct 24, 2015 12:37 pm
by Awe2K
Hello, I'm wondering how can I enter RM after booting with GRUB?
I want to go back to RM, then change graphics mode, and then go to PM and execute kernel.
Setting PM bit to zero and STI doesn't do.

Thanks.

Code: Select all

MBOOT_PAGE_ALIGN    equ 1<<0 
MBOOT_MEM_INFO      equ 1<<1
MBOOT_VIDINFO equ  1 << 2       ;;; DOESN'T WORK IN QEMU
MBOOT_HEADER_MAGIC  equ 0x1BADB002 ; Multiboot Magic value
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)


[BITS 32]

[GLOBAL mboot] 
[EXTERN code]                   ; Start of the '.text' section.
[EXTERN bss]                    ; Start of the .bss section.
[EXTERN end]                    ; End of the last loadable section.

mboot:
    dd  MBOOT_HEADER_MAGIC 
    dd  MBOOT_HEADER_FLAGS 
    dd  MBOOT_CHECKSUM
    
    dd  mboot                   ; Location of this descriptor
    dd  code                    ; Start of kernel '.text' (code) section.
    dd  bss                     ; End of kernel '.data' section.
    dd  end                     ; End of kernel.
    dd  start                   ; Kernel entry point (initial EIP).
;       dd 0 ; # 0 = set graphics mode
;	dd 1024
;	dd 768
;	dd 32
;    ^ ^ ^ Don't work in Qemu

[GLOBAL start]                  ; Kernel entry point.
[EXTERN main]                   ; This is the entry point of our C code

start:

	mov eax, cr0
	and eax,-0x2
	mov cr0,eax ; disable PM

	[bits 16]

       ;; Interrupts already enabled by grub?

	mov ah,0
	mov al,4 ; 320x200x(4 color)
	int 0x10  ; gets crashed

	[bits 32]
   ; push esp - stack ptr
   ; push ebx - mboot ptr



    ; Execute the kernel:
   ; cli                       
   ; call main ; not yet, still in 16 bit real mode
    jmp $



Re: How can I enter Real Mode after GRUB?

Posted: Sat Oct 24, 2015 2:03 pm
by Roman
1) Entering real mode from protected mode is more complicated than you think. You can read about it here.
2) GRUB can setup graphics for you.

Re: How can I enter Real Mode after GRUB?

Posted: Sat Oct 24, 2015 2:07 pm
by Awe2K
Roman wrote:1) Entering real mode from protected mode is more complicated than you think. You can read about it here.
2) GRUB can setup graphics for you.
1) Yes, I know. I have already read that article.
2) I know, but this doesn't work in qemu (I use qemu/KVM to boot my kernel and debug it)

Re: How can I enter Real Mode after GRUB?

Posted: Sat Oct 24, 2015 2:40 pm
by BASICFreak
The steps to enter Real Mode (if the data structures are not destroyed) [NOTE this is my way and may not be the best]

1. CLI
2. Setup GDT (with null, 32-bit code, 32-bit data, and 16-bit code)
3. LIDT (the realmode IVT is at 0x0000:0x0000) <- if you skip this step you will not have any Real Mode Ints
4. Switch to 16-bit protected mode (16-bit code segment and 32-bit (or 16) data segment) <- If you skip this step you will triple fault!
5. Switch to 16-bit real mode (set cr0 then jmp Segment:Offset)
6. Setup data segments for real mode
7. STI <- Optional (unless you need maskable ints...)
8. Do things
9. Switch back to PM <- way easier than switching to RM

Just remember all 16-bit code must be under 1MB

If you remapped the PIC then you will have to map it back (assuming reliance on it is needed)

FWIW, this is the reason I wrote my BootStrap and OSLoader - so I could do everything in RM that I wanted to do before the Kernel is executed.

EDIT: Decided to make an untested example:

Code: Select all

MBOOT_PAGE_ALIGN    equ 1<<0 
MBOOT_MEM_INFO      equ 1<<1
MBOOT_VIDINFO equ  1 << 2       ;;; DOESN'T WORK IN QEMU
MBOOT_HEADER_MAGIC  equ 0x1BADB002 ; Multiboot Magic value
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)


[BITS 32]

[GLOBAL mboot] 
[EXTERN code]                   ; Start of the '.text' section.
[EXTERN bss]                    ; Start of the .bss section.
[EXTERN end]                    ; End of the last loadable section.

mboot:
    dd  MBOOT_HEADER_MAGIC 
    dd  MBOOT_HEADER_FLAGS 
    dd  MBOOT_CHECKSUM
    
    dd  mboot                   ; Location of this descriptor
    dd  code                    ; Start of kernel '.text' (code) section.
    dd  bss                     ; End of kernel '.data' section.
    dd  end                     ; End of kernel.
    dd  start                   ; Kernel entry point (initial EIP).

[GLOBAL start]                  ; Kernel entry point.
[EXTERN main]                   ; This is the entry point of our C code

start:
   cli
   sgdt [OLDGDT]
   sidt [OLDIDT]
   
   lgdt [gdtinfo]
   lidt [idt_real]

   mov eax, cr0
   mov DWORD [OLDCR0], eax
   mov eax, cr3
   mov DWORD [OLDCR3], eax

   jmp 0x08:.protected16bit
[bits 16]
   .protected16bit:
      mov ax, 0x10
      mov ds, ax
      mov es, ax
      mov eax, cr0
      and eax, 0x7FFFFFFE
      mov cr0, eax
      jmp 0:.realmode ; Or Whatever Segment You Need

  .realmode:
    mov ax, 0 ; Or Whatever Segment You Need
    mov ds, ax
    mov es, ax

    ;Setup stack
    mov ss, ax
    mov sp, 0xFFF0

   ; sti ; If you need maskable ints uncomment this

   mov ah,0
   mov al,4 ; 320x200x(4 color)
   int 0x10

   cli
   mov eax, DWORD [OLDCR3]
   mov cr3, eax
   mov eax, DWORD [OLDCR0]
   mov cr0, eax

   ; lgdt [OLDGDT] ; If you changed your GDT reload the old one.

   jmp 18h:.protectedmode
[bits 32]
    .protectedmode:
      mov ax, 0x10
      mov dx, ax
      mov es, ax
      mov ss, ax
      mov sp, [KERNEL_STACK]
      lidt [OLDIDT]
      call main
      .halt:
        hlt
        jmp .halt


;----------------------------------------------------
;                        GDT
;----------------------------------------------------
gdtinfo:
   dw (gdt_end - gdt - 1)   ;last byte in table
   dd (gdt)                ;start of table

gdt         dd 0,0        ; entry 0 is always unused
flatcode    db 0xFF, 0xFF, 0, 0, 0, 10011010b, 10001111b, 0 ; 16-bit code
flatdata    db 0xFF, 0xFF, 0, 0, 0, 10010010b, 11001111b, 0 ; 32-bit data
pmflatcode  db 0xFF, 0xFF, 0, 0, 0, 10011010b, 11001111b, 0 ; 32-bit code
gdt_end:

OLDGDT dd 0
OLDIDT dd 0
OLDCR0 dd 0
OLDCR3 dd 0

idt_real:
  dw 0x3ff    ; 256 entries, 4b each = 1K
  dd 0      ; Real Mode IVT @ 0x0000
Now this will have to be loaded in Real Mode addressable space (below 1MB+64KB)

Re: How can I enter Real Mode after GRUB?

Posted: Sat Oct 24, 2015 11:51 pm
by Awe2K
BASICFreak wrote:The steps to enter Real Mode (if the data structures are not destroyed) [NOTE this is my way and may not be the best]

1. CLI
2. Setup GDT (with null, 32-bit code, 32-bit data, and 16-bit code)
3. LIDT (the realmode IVT is at 0x0000:0x0000) <- if you skip this step you will not have any Real Mode Ints
4. Switch to 16-bit protected mode (16-bit code segment and 32-bit (or 16) data segment) <- If you skip this step you will triple fault!
5. Switch to 16-bit real mode (set cr0 then jmp Segment:Offset)
6. Setup data segments for real mode
7. STI <- Optional (unless you need maskable ints...)
8. Do things
9. Switch back to PM <- way easier than switching to RM

Just remember all 16-bit code must be under 1MB

If you remapped the PIC then you will have to map it back (assuming reliance on it is needed)

FWIW, this is the reason I wrote my BootStrap and OSLoader - so I could do everything in RM that I wanted to do before the Kernel is executed.

EDIT: Decided to make an untested example:

Code: Select all

MBOOT_PAGE_ALIGN    equ 1<<0 
MBOOT_MEM_INFO      equ 1<<1
MBOOT_VIDINFO equ  1 << 2       ;;; DOESN'T WORK IN QEMU
MBOOT_HEADER_MAGIC  equ 0x1BADB002 ; Multiboot Magic value
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)


[BITS 32]

[GLOBAL mboot] 
[EXTERN code]                   ; Start of the '.text' section.
[EXTERN bss]                    ; Start of the .bss section.
[EXTERN end]                    ; End of the last loadable section.

mboot:
    dd  MBOOT_HEADER_MAGIC 
    dd  MBOOT_HEADER_FLAGS 
    dd  MBOOT_CHECKSUM
    
    dd  mboot                   ; Location of this descriptor
    dd  code                    ; Start of kernel '.text' (code) section.
    dd  bss                     ; End of kernel '.data' section.
    dd  end                     ; End of kernel.
    dd  start                   ; Kernel entry point (initial EIP).

[GLOBAL start]                  ; Kernel entry point.
[EXTERN main]                   ; This is the entry point of our C code

start:
   cli
   sgdt [OLDGDT]
   sidt [OLDIDT]
   
   lgdt [gdtinfo]
   lidt [idt_real]

   mov eax, cr0
   mov DWORD [OLDCR0], eax
   mov eax, cr3
   mov DWORD [OLDCR3], eax

   jmp 0x08:.protected16bit
[bits 16]
   .protected16bit:
      mov ax, 0x10
      mov ds, ax
      mov es, ax
      mov eax, cr0
      and eax, 0x7FFFFFFE
      mov cr0, eax
      jmp 0:.realmode ; Or Whatever Segment You Need

  .realmode:
    mov ax, 0 ; Or Whatever Segment You Need
    mov ds, ax
    mov es, ax

    ;Setup stack
    mov ss, ax
    mov sp, 0xFFF0

   ; sti ; If you need maskable ints uncomment this

   mov ah,0
   mov al,4 ; 320x200x(4 color)
   int 0x10

   cli
   mov eax, DWORD [OLDCR3]
   mov cr3, eax
   mov eax, DWORD [OLDCR0]
   mov cr0, eax

   ; lgdt [OLDGDT] ; If you changed your GDT reload the old one.

   jmp 18h:.protectedmode
[bits 32]
    .protectedmode:
      mov ax, 0x10
      mov dx, ax
      mov es, ax
      mov ss, ax
      mov sp, [KERNEL_STACK]
      lidt [OLDIDT]
      call main
      .halt:
        hlt
        jmp .halt


;----------------------------------------------------
;                        GDT
;----------------------------------------------------
gdtinfo:
   dw (gdt_end - gdt - 1)   ;last byte in table
   dd (gdt)                ;start of table

gdt         dd 0,0        ; entry 0 is always unused
flatcode    db 0xFF, 0xFF, 0, 0, 0, 10011010b, 10001111b, 0 ; 16-bit code
flatdata    db 0xFF, 0xFF, 0, 0, 0, 10010010b, 11001111b, 0 ; 32-bit data
pmflatcode  db 0xFF, 0xFF, 0, 0, 0, 10011010b, 11001111b, 0 ; 32-bit code
gdt_end:

OLDGDT dd 0
OLDIDT dd 0
OLDCR0 dd 0
OLDCR3 dd 0

idt_real:
  dw 0x3ff    ; 256 entries, 4b each = 1K
  dd 0      ; Real Mode IVT @ 0x0000
Now this will have to be loaded in Real Mode addressable space (below 1MB+64KB)
Thanks, I will try this code to setup proper graphics mode

Re: How can I enter Real Mode after GRUB?

Posted: Sun Oct 25, 2015 12:04 am
by Awe2K
Also, I've tried to switch to it before using Intel's developer manual.
It said I have to perform same steps as you mentioned. I think now I'm going to read more about GDT's (I suspect my bad one for triple-faulting) :)