OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Sep 24, 2020 7:58 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: [SOLVED] Switching back to real mode from GRUB
PostPosted: Mon Jan 13, 2020 9:56 am 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 884
Hi,

There are many GRUB-experts on this forum, maybe one of you know the answer.
My boot loader is capable of booting many different ways (from ROM, disk, cdrom, as Linux kernel, etc.) All works fine, except when I boot it with recent GRUB2 versions.

Because my loader is quite complex, I've narrowed the problem down to a simple VESA call and 512 bytes of code. I've attached the source and the outputs. The problem is, when this code is booted through GRUB using Multiboot, and it switches back to real mode to continue where the other boot paths start, then some of the BIOS routines go crazy. I think the code sets up everything for real mode correctly (segments, GDT, IVT etc.). I wonder what could be missing.
Code:
            USE32
multiboot_start:
            cli
            cld
            lgdt        [GDT_value]
            mov         ax, DATA_BOOT
            mov         ds, ax
            mov         es, ax
            jmp         CODE_BOOT:.real ;load 16 bit mode segment into cs
            USE16
.real:      mov         eax, CR0
            and         eax, 07FFFFFFEh ;switching back to real mode
            mov         CR0, eax
            xor         ax, ax
            mov         ds, ax          ;load segment registers DS and CS
            jmp         0:@f
@@:         lidt        [idt16]         ;restore IDT as newer GRUBs mess it up
            ;fallthrough realmode_start

realmode_start:


The expected behaviour: this code (after realmode_start) should print strings on screen as well as on serial port, then set up 800x600x32 VESA mode. That's it. This works in both qemu and bochs if you boot it from ROM, though boot sector etc. But if you boot it through GRUB, then the screen resolution is either wrong; not set; or the BIOS code gets into an infinite loop. If it's not how I switch to real mode, then could it be that GRUB accidentally destroys some variables in BDA or EBDA? Bochs also gives me "io write to address 00000000 len 2" errors (as you can see in the attachment, there's no out instruction in stage2.asm, only BIOS int calls).

I've provided a Makefile for testing ("make all" will compile the code and create the required images):
Code:
make bochsrom
make bochsbios
make bochsgrub
make qemurom
make qemubios
make qemugrub

The question is: how can we switch back to real mode properly after booting from Multiboot so that BIOS routines work as expected?

Cheers,
bzt

ps: the attachment is a targz, but phpbb does not allow the extension tgz.


Attachments:
grubbug.tgz.txt [7.72 KiB]
Downloaded 5 times


Last edited by bzt on Mon Jan 13, 2020 1:58 pm, edited 1 time in total.
Top
 Profile  
 
 Post subject: Re: Switching back to real mode from GRUB
PostPosted: Mon Jan 13, 2020 11:35 am 
Offline
Member
Member

Joined: Sun Nov 23, 2008 5:56 am
Posts: 31
Location: Russia, Saint-Petersburg
Try adding "mov ss, ax" before jumping to CODE_BOOT:.real.
It seems that grub leaves the upper part of ESP nonzero. If the SS shadow descriptor is left with D=1, then CPU will use ESP when accessing stack. And BIOS expects that after "mov bp, sp" the BP register will point to the current stack, which is no longer true.


Top
 Profile  
 
 Post subject: Re: Switching back to real mode from GRUB
PostPosted: Mon Jan 13, 2020 2:02 pm 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 884
quirck wrote:
Try adding "mov ss, ax" before jumping to CODE_BOOT:.real.
It seems that grub leaves the upper part of ESP nonzero. If the SS shadow descriptor is left with D=1, then CPU will use ESP when accessing stack. And BIOS expects that after "mov bp, sp" the BP register will point to the current stack, which is no longer true.
Bingo! Thank you very much! It was indeed! I set up ss and sp as well in 16 bit mode, but the upper part of esp left nonzero. Reloading the ss shadow register and clearing all 32 bits of esp solved the issue! It's still not working properly, but at least the code doesn't get into an infinite loop in a BIOS routine any more!

Thanks!
bzt


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 11 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