Loading GDT causes restart loop

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
MichaelPetch
Member
Member
Posts: 772
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Loading GDT causes restart loop

Post by MichaelPetch »

Removed to avoid confusion
Last edited by MichaelPetch on Sun Apr 14, 2024 10:48 pm, edited 2 times in total.
MichaelPetch
Member
Member
Posts: 772
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Loading GDT causes restart loop

Post by MichaelPetch »

Removed to avoid confusion
Last edited by MichaelPetch on Sun Apr 14, 2024 10:47 pm, edited 1 time in total.
nullplan
Member
Member
Posts: 1760
Joined: Wed Aug 30, 2017 8:24 am

Re: Loading GDT causes restart loop

Post by nullplan »

No, it should be 0xa0 for the code segment and 0xc0 for the data segment. Indeed, I also set the limit to 0xfffff on both segments (that is, set the limit1_flags value to 0xaf/0xcf and limit0 to 0xffff). They should not matter as per CPU manual, but it also doesn't cost me anything to just set the limit to 4GB, and maybe something in the system doesn't like a limit of 0.
Carpe diem!
MichaelPetch
Member
Member
Posts: 772
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Loading GDT causes restart loop

Post by MichaelPetch »

What is being recommended is that you change your code to be:

Code: Select all

__attribute__((aligned(0x8)))
GDT default_gdt = {
    {0x0000, 0, 0, 0x00, 0x00, 0},
    {0xffff, 0, 0, 0x9a, 0xaf, 0},
    {0xffff, 0, 0, 0x92, 0xcf, 0},
    {0x0000, 0, 0, 0x00, 0x00, 0},
    {0xffff, 0, 0, 0x9a, 0xaf, 0},
    {0xffff, 0, 0, 0x92, 0xcf, 0},
};
User avatar
0xY
Posts: 13
Joined: Thu Sep 29, 2022 6:12 pm
Libera.chat IRC: 0xY

Re: Loading GDT causes restart loop

Post by 0xY »

I have updated the repository (https://github.com/crystalw1ngs/kernel) to contain all the files you need to build the project, the steps are: cd into /gnu-efi and 'make bootloader', then cd into /kernel and 'make kernel' then 'make buildimg'. This should generate the correct files in the /bin directory. I appreciate your help with this. I am still working on attaching a debugger to QEMU, it doesn't seem so straightforward, at least on Windows. I will let you know once I succeed with this.
MichaelPetch
Member
Member
Posts: 772
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Loading GDT causes restart loop

Post by MichaelPetch »

I cloned your repository. I had to rebuild gnu-efi first (the files you had didn't work on my system). I made the bootloader after that without a problem. When I went to build your kernel I got linker errors because memcpy and memzero were defined more than once. There was a reason for this since you defined them in memory.h. I modified memory.h to be:

Code: Select all

#ifndef _MEMORY_H
#define _MEMORY_H

#include "stddef.h"
#include "stdint.h"
#include "efimem.h"

#define UEFI_MMAP_SIZE 0x4000

typedef struct _mmap {
        uint64_t nbytes;
        uint8_t buffer[UEFI_MMAP_SIZE];
        uint64_t mapkey;
        uint64_t descsize;
        uint32_t desc_version;
} MEMORY_MAP;

extern uint64_t getmemsize(EFI_MEMORY_DESCRIPTOR* mmap, uint64_t mmapentries, uint64_t mmapdescsize);

extern void memzero(void* s, uint64_t n);
extern void memcpy(void *dest, void *src, size_t n);
#endif
I then moved the functions to memory.c:

Code: Select all

#include "memory.h"

uint64_t getmemsize(EFI_MEMORY_DESCRIPTOR* mmap, uint64_t mmapentries, uint64_t mmapdescsize) {
        static uint64_t memsizebytes = 0;
        if (memsizebytes > 0) return memsizebytes;

        for (int i = 0; i < mmapentries; i++) {
                EFI_MEMORY_DESCRIPTOR* desc = (EFI_MEMORY_DESCRIPTOR*)((uint64_t)mmap + (i * mmapdescsize));
                memsizebytes += desc->numpages * 4096;
        }

        return memsizebytes;
}

void memzero(void* s, uint64_t n) {
    for (int i = 0; i < n; i++) {
                 ((uint8_t*)s)[i] = 0;
        }
}

void memcpy(void *dest, void *src, size_t n) {
        uint8_t *pdest = (uint8_t*) dest;
    uint8_t *psrc = (uint8_t*) src;

        for (unsigned int i = 0; i < n; i++) {
                pdest[i] = psrc[i];
        }
}
I also had an error in the Makefile while using mformat. I had to change:

Code: Select all

mformat -i $(BUILDDIR)/$(OSNAME).img -f 1440 ::
to:

Code: Select all

mformat -i $(BUILDDIR)/$(OSNAME).img ::
Once I was able to build up everything and run it, it worked fine. In fact I went back and modified gdt.h with the 0x1000 alignment and old GDT you had and it still worked. I modified kernel.c and put an `asm("hlt")` right after the load_gdt . Ran it and went into the QEMU monitor and all the segment registers were loaded correctly (including CS).

I'm curious what environment you build all this in. Your Makefile suggest it it being done in some kind of Linux/Unix type environment but when you run QEMU you are doing it from Windows.

The build I made was on WSL2 (Windows Subsystem for Linux v2) using Ubuntu 22.04 using GCC 11.4.0 and QEMU 7.2.0. I run QEMU from inside WSL2 as well.
User avatar
0xY
Posts: 13
Joined: Thu Sep 29, 2022 6:12 pm
Libera.chat IRC: 0xY

Re: Loading GDT causes restart loop

Post by 0xY »

Thanks for your efforts, I really appreciate it. My set up is the same as yours, I am using WSL2 (Ubuntu 20.04) to build the project (GCC 9.4.0) and then running it with QEMU 7.2.0 in Windows 10. I'm not sure what the issue is then, even with the changes to the GDT entries the kernel still crashes and reboots once it loads. I have made previous attempts at making a kernel with UEFI and the GDT worked fine, the code was almost identical to the one shown here.
MichaelPetch
Member
Member
Posts: 772
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Loading GDT causes restart loop

Post by MichaelPetch »

I had a Ubuntu 20.04 system on my computer (WSL2) and I happened to clone your repository. I didn't rebuild gnu-efi (as the files are for the same version as yours). I built the bootloader and the kernel I had to fix the issue with just memcpy/memzero being duplicated and ran it in QEMU under WSL2. It worked as expected.

Do you have a link to the installer for the version of QEMU you are running under Windows? What is the command line you launch the Windows version with? Have you tried the QEMU in WSL2(Ubuntu 20.04)? Does it give the same result? Could you put a copy of your OS.img that doesn't work onto Github somewhere?

As it stands right now I begin to wonder if the QEMU you are using is an issue?
User avatar
0xY
Posts: 13
Joined: Thu Sep 29, 2022 6:12 pm
Libera.chat IRC: 0xY

Re: Loading GDT causes restart loop

Post by 0xY »

Do you have a link to the installer for the version of QEMU you are running under Windows? What is the command line you launch the Windows version with?
I got my QEMU from here, I tried with the latest version but it still didn't work: https://qemu.weilnetz.de/w64/2024/

Here are the options I used:

Code: Select all

 qemu-system-x86_64 -drive file=%BUILDDIR%/%OSNAME%.img -m 256M -cpu qemu64 -drive if=pflash,format=raw,unit=0,file="%OVMFDIR%/OVMF_CODE-pure-efi.fd",readonly=on -drive if=pflash,format=raw,unit=1,file="%OVMFDIR%/OVMF_VARS-pure-efi.fd" -net none -d int -no-reboot -no-shutdown

I ran it using QEMU from within WSL2 instead using the following options:

Code: Select all

qemu-system-x86_64 -drive file=bin/OS.img -m 256M -cpu qemu64 -bios /usr/share/OVMF/OVMF_CODE.fd -net none 
The results are a bit better now but still inconsistent. Sometimes it boots fine and other times it will do the reboot loop after reaching the kernel or sometimes even before; it will crash before the bootloader prints everything leading up to the kernel start function.

If I add the options:

Code: Select all

-d int -no-reboot -no-shutdown  
It does the same thing as before, it will reach the kernel and pause. Here is the last exception that comes up in the console:

Code: Select all

   613: v=68 e=0000 i=0 cpl=0 IP=0038:000000000e910a81 pc=000000000e910a81 SP=0030:000000000ff1bae8 env->regs[R_EAX]=00000000009bd31f
RAX=00000000009bd31f RBX=0000000000000000 RCX=00000000000f4240 RDX=00000000000000ae
RSI=000000000004baf1 RDI=0000000000000000 RBP=000000000f186400 RSP=000000000ff1bae8
R8 =00000000009bd3cd R9 =0000000000000064 R10=0000000000000000 R11=0000000000000001
R12=000000000f1c1828 R13=0000000000000000 R14=000000000f18c854 R15=0000000000000011
RIP=000000000e910a81 RFL=00000202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0030 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0038 0000000000000000 ffffffff 00af9a00 DPL=0 CS64 [-R-]
SS =0030 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0030 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0030 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0030 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT=     000000000fbeea98 00000047
IDT=     000000000f630018 00000fff
CR0=80010033 CR2=0000000000000000 CR3=000000000fc01000 CR4=00000668
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
MichaelPetch
Member
Member
Posts: 772
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Loading GDT causes restart loop

Post by MichaelPetch »

I have noticed that Tiano Core seems to get stuck before it even loads the bootloader. In the times that it reaches the boot screen (the one with the counter, press ESC etc) the bootloader and the kernel always works for me as expected. When it does work the kernel exits and the machine is rebooted.

Maybe someone knows a reason why Tiano Core might get stuck before loading any bootloader. I didn't actually try replacing the OVMF files with different ones to see what happens.
User avatar
0xY
Posts: 13
Joined: Thu Sep 29, 2022 6:12 pm
Libera.chat IRC: 0xY

Re: Loading GDT causes restart loop

Post by 0xY »

I have noticed that Tiano Core seems to get stuck before it even loads the bootloader.
That happens to me too when I use QEMU on windows, I have found that replacing the OVMF files with a fresh set seems to fix it until next time. I do not have this issue when running QEMU from WSL, but the behaviour is still inconsistent, sometimes it will run the kernel fine and other times it will restart during the bootloader stage even before reaching the kernel. Thanks for you help though hopefully this means that the issue is with QEMU rather than my code.
Octocontrabass
Member
Member
Posts: 5494
Joined: Mon Mar 25, 2013 7:01 pm

Re: Loading GDT causes restart loop

Post by Octocontrabass »

Where did you get your copy of OVMF? Perhaps your copy is just buggy.

You may have better luck if you delete startup.nsh and rename your bootloader "\efi\boot\bootx64.efi". Even if it doesn't make OVMF happy, it'll at least make your OS bootable on more hardware.
Post Reply