OSDev.org

The Place to Start for Operating System Developers
It is currently Wed Apr 24, 2024 11:29 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: AMD Ryzen locks up with blank display
PostPosted: Sun Mar 17, 2019 4:16 pm 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
I'm trying to boot a laptop with an AMD Ryzen 5 2500U processor with UEFI. I get the boot menu, the boot succeeds and my OS loads. Everything seems to work fine for about 15 seconds, and then the display goes blank and everything seems to be dead. Even if I add code that hangs all cores in a loop with interrupts disabled, the same thing still happens.

Could it be some sort of firmware timeout, or possibly the CPU overheats?

Any ideas why this happens and what might possibly fix the issue?


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Sun Mar 17, 2019 4:46 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 642
Location: Ukraine, Bachmut
Quote:
Could it be some sort of firmware timeout

FW should disable watchdog at ExitBootServices(). Do you use this service? But even with WD on, it should trigger reboot, not hang.
Quote:
or possibly the CPU overheats?

<flame>Of course it could, it's AMD after all. :mrgreen: </flame>
Quote:
Everything seems to work fine for about 15 seconds

What that "everything" is? maybe that everything causes the hang even when you think, you only loop the cpus? Maybe not all cores get into the loop or maybe interrupts aren't disabled still. Apparently it's not a FW fault, I assume other OSs work ok on this machine.

_________________
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Mon Mar 18, 2019 3:15 am 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
zaval wrote:
Quote:
Could it be some sort of firmware timeout

FW should disable watchdog at ExitBootServices(). Do you use this service? But even with WD on, it should trigger reboot, not hang.


Yes, I call ExitBootServices().

zaval wrote:
Quote:
or possibly the CPU overheats?

<flame>Of course it could, it's AMD after all. :mrgreen: </flame>


:-)

zaval wrote:
Quote:
Everything seems to work fine for about 15 seconds

What that "everything" is? maybe that everything causes the hang even when you think, you only loop the cpus? Maybe not all cores get into the loop or maybe interrupts aren't disabled still. Apparently it's not a FW fault, I assume other OSs work ok on this machine.


The command prompt works, and I can type state to display running threads & services. Additionally, the same USB boot stick works on another UEFI machine (Intel based). It also worked on an AMD Athlon machine when I tested it there a while ago. The UEFI boot file is 64-bit, but switches to 32-bit protected mode. The VME bug in Ryzen should not be involved as it is an UEFI boot. Actually, this laptop doesn't seem to support legacy boot at all.

As for other OSes, Windows 10 works of course as it is shipped with it preinstalled. I don't know about Linux.


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Mon Mar 18, 2019 12:19 pm 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
Done more research on the issue.

If I create a loop in the 32-bit loader (which is reached by switching from long mode to 32-bit protected mode), then the blank display is still shown and there is a lock-up. Thus, the lockup after 15 seconds is firmware related and not related to my OS.

If I create a loop in the 64-bit loader, then there is a reboot after 15 seconds. Thus, if the system is still in long mode, then there is a reboot, but if the system is in protected mode, then the system freezes.

Here is the EFI boot code, in case somebody can spot the reason:

Code:
#include <lib.h>
#include <efi.h>
#include <efilib.h>
#include <efiprot.h>
#include <stdarg.h>

#define RDOS_LOADER 0x110000
#define RDOS_MEM  0x400
#define RDOS_BASE 0x121000

EFI_SYSTEM_TABLE         *ST;
EFI_BOOT_SERVICES        *BS;
EFI_RUNTIME_SERVICES     *RT;

EFI_LOADED_IMAGE *Image;
FILEPATH_DEVICE_PATH *LoadedPath;
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;

unsigned int VideoMode;
unsigned int Width;
unsigned int Height;
unsigned int ScanLine;
EFI_GRAPHICS_PIXEL_FORMAT PixelFormat;
EFI_PHYSICAL_ADDRESS LfbBase;
unsigned int LfbSize;

unsigned int TextMode;
unsigned int TextRows;
unsigned int TextCols;

unsigned int CurrFs;
unsigned int FsCount;
EFI_FILE_IO_INTERFACE *Fs;
EFI_FILE_HANDLE Root;
char FsInfoData[1024];
EFI_FILE_SYSTEM_INFO *FsInfo;
EFI_FILE_INFO *FileInfo;
EFI_FILE_HANDLE FileHandle;

void *Interface;
EFI_HANDLE *FsArr;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
EFI_STATUS Status;
EFI_CONFIGURATION_TABLE* ConfigTableArr;
void *AcpiTable = 0;

char nbuf[32];
char str[256];
char buf[256];
CHAR16 wstr[256];

#define MENU_WIDTH 40
#define MENU_ROWS  20

struct BootEntry
{
    EFI_FILE_IO_INTERFACE *Volume;
    CHAR16 FileName[256];
    unsigned int FileSize;
    char MenuStr[MENU_WIDTH + 1];   
};

int StartRow;
int StartCol;
int SelectedRow;
int MenuRows = 0;
EFI_FILE_IO_INTERFACE *CurrVolume;
struct BootEntry MenuArr[MENU_ROWS];

EFI_INPUT_KEY Key;

EFI_PHYSICAL_ADDRESS RdosLoaderBase = RDOS_LOADER;
unsigned int RdosLoaderPages = 16;

EFI_PHYSICAL_ADDRESS RdosImageBase = RDOS_BASE;
unsigned int RdosImagePages;

unsigned int LoaderEntry = (unsigned int)RDOS_LOADER;
void (*StartLoaderProc)();

#define PIXEL_REVERSE  1

#pragma pack( push, 1 )

struct LoaderParam
{
    EFI_PHYSICAL_ADDRESS Lfb;
    unsigned int LfbWidth;
    unsigned int LfbHeight;
    unsigned int LfbLineSize;
    unsigned int LfbFlags;
    unsigned int MemEntries;
    EFI_PHYSICAL_ADDRESS AcpiTable;
};

struct MemMapEntry
{
    unsigned int Len;
    unsigned long long Base;
    unsigned long long Size;
    unsigned int Type;
};

#pragma pack( pop )

unsigned int LoaderParamPos = (unsigned int)(RDOS_LOADER + 2);
struct LoaderParam *LoaderData;

char MemMapBuf[4096];
EFI_MEMORY_DESCRIPTOR *MemMap = (EFI_MEMORY_DESCRIPTOR *)MemMapBuf;
unsigned int MemMapSize = 4096;
unsigned int MapKey;
unsigned int MemDescrSize;
unsigned int MemDescrVersion;

unsigned int MemMapCount;
struct MemMapEntry *MemMapArr;   

//
// Root device path
//

EFI_DEVICE_PATH RootDevicePath[] = {
   {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH,0}}
};

EFI_DEVICE_PATH EndDevicePath[] = {
   {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
};

EFI_DEVICE_PATH EndInstanceDevicePath[] = {
   {END_DEVICE_PATH_TYPE, END_INSTANCE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
};


//
// EFI IDs
//

EFI_GUID EfiGlobalVariable  = EFI_GLOBAL_VARIABLE;
EFI_GUID NullGuid = { 0,0,0,{0,0,0,0,0,0,0,0} };

//
// Protocol IDs
//

EFI_GUID DevicePathProtocol       = DEVICE_PATH_PROTOCOL;
EFI_GUID LoadedImageProtocol      = LOADED_IMAGE_PROTOCOL;
EFI_GUID TextInProtocol           = SIMPLE_TEXT_INPUT_PROTOCOL;
EFI_GUID TextOutProtocol          = SIMPLE_TEXT_OUTPUT_PROTOCOL;
EFI_GUID BlockIoProtocol          = BLOCK_IO_PROTOCOL;
EFI_GUID DiskIoProtocol           = DISK_IO_PROTOCOL;
EFI_GUID FileSystemProtocol       = SIMPLE_FILE_SYSTEM_PROTOCOL;
EFI_GUID LoadFileProtocol         = LOAD_FILE_PROTOCOL;
EFI_GUID DeviceIoProtocol         = DEVICE_IO_PROTOCOL;
EFI_GUID UnicodeCollationProtocol = UNICODE_COLLATION_PROTOCOL;
EFI_GUID SerialIoProtocol         = SERIAL_IO_PROTOCOL;
EFI_GUID SimpleNetworkProtocol    = EFI_SIMPLE_NETWORK_PROTOCOL;
EFI_GUID PxeBaseCodeProtocol      = EFI_PXE_BASE_CODE_PROTOCOL;
EFI_GUID PxeCallbackProtocol      = EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL;
EFI_GUID NetworkInterfaceIdentifierProtocol = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL;
EFI_GUID UiProtocol               = EFI_UI_PROTOCOL;
EFI_GUID PciIoProtocol            = EFI_PCI_IO_PROTOCOL;
EFI_GUID GopProtocol              = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;

//
// File system information IDs
//

EFI_GUID GenericFileInfo           = EFI_FILE_INFO_ID;
EFI_GUID FileSystemInfo            = EFI_FILE_SYSTEM_INFO_ID;
EFI_GUID FileSystemVolumeLabelInfo = EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID;

//
// Reference implementation public protocol IDs
//

EFI_GUID InternalShellProtocol = INTERNAL_SHELL_GUID;
EFI_GUID VariableStoreProtocol = VARIABLE_STORE_PROTOCOL;
EFI_GUID LegacyBootProtocol = LEGACY_BOOT_PROTOCOL;
EFI_GUID VgaClassProtocol = VGA_CLASS_DRIVER_PROTOCOL;

EFI_GUID TextOutSpliterProtocol = TEXT_OUT_SPLITER_PROTOCOL;
EFI_GUID ErrorOutSpliterProtocol = ERROR_OUT_SPLITER_PROTOCOL;
EFI_GUID TextInSpliterProtocol = TEXT_IN_SPLITER_PROTOCOL;
/* Added for GOP support */
EFI_GUID GraphicsOutputProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;

EFI_GUID AdapterDebugProtocol = ADAPTER_DEBUG_PROTOCOL;

//
// Device path media protocol IDs
//
EFI_GUID PcAnsiProtocol = DEVICE_PATH_MESSAGING_PC_ANSI;
EFI_GUID Vt100Protocol  = DEVICE_PATH_MESSAGING_VT_100;

//
// EFI GPT Partition Type GUIDs
//
EFI_GUID EfiPartTypeSystemPartitionGuid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID;
EFI_GUID EfiPartTypeLegacyMbrGuid = EFI_PART_TYPE_LEGACY_MBR_GUID;


//
// Reference implementation Vendor Device Path Guids
//
EFI_GUID UnknownDevice      = UNKNOWN_DEVICE_GUID;

//
// Configuration Table GUIDs
//

EFI_GUID MpsTableGuid             = MPS_TABLE_GUID;
EFI_GUID AcpiTableGuid            = ACPI_TABLE_GUID;
EFI_GUID SMBIOSTableGuid          = SMBIOS_TABLE_GUID;
EFI_GUID SalSystemTableGuid       = SAL_SYSTEM_TABLE_GUID;

//
// Network protocol GUIDs
//
EFI_GUID Ip4ServiceBindingProtocol = EFI_IP4_SERVICE_BINDING_PROTOCOL;
EFI_GUID Ip4Protocol = EFI_IP4_PROTOCOL;
EFI_GUID Udp4ServiceBindingProtocol = EFI_UDP4_SERVICE_BINDING_PROTOCOL;
EFI_GUID Udp4Protocol = EFI_UDP4_PROTOCOL;
EFI_GUID Tcp4ServiceBindingProtocol = EFI_TCP4_SERVICE_BINDING_PROTOCOL;
EFI_GUID Tcp4Protocol = EFI_TCP4_PROTOCOL;


static void WriteChar(char ch)
{
    CHAR16 wstr[] = { 0, 0 };

    wstr[0] = (CHAR16)ch;           
    ST->ConOut->OutputString(ST->ConOut, wstr);
}


char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";

#define hex2ascii(hex)  (hex2ascii_data[hex])

static int isupper(int c)
{
    if((c >= 'A') && (c <= 'Z'))
        return 1;
    else
        return 0;
}

static int islower(int c)
{
    if((c >= 'a') && (c <= 'z'))
        return 1;
    else
        return 0;
}

static int tolower(int c)
{
    if((c >= 'A') && (c <= 'Z'))
        return c - 'A' + 'a';
    else
        return c;
}

static int toupper(int c)
{
    if((c >= 'a') && (c <= 'z'))
        return c - 'a' + 'A';
    else
        return c;
}

static int isdigit(int c)
{
    if((c >= '0') && (c <= '9'))
        return 1;
    else
        return 0;
}

static int isalpha(int c)
{
    return isupper(c) || islower(c);
}

static int isalnum(int c)
{
    return isalpha(c) || isdigit(c);
}

static int strlen(const char *s)
{
    int l = 0;
    while (*s++)
        l++;
    return l;
}

static void strupper(char *s)
{
    while (*s)
    {
        *s = (char)toupper(*s);
        s++;
    }
}

static void strlower(char *s)
{
    while (*s)
    {
        *s = (char)tolower(*s);
        s++;
    }
}

static int strcmp(const char *s1, const char *s2)
{
    for ( ; *s1 == *s2; s1++, s2++)
        if (*s1 == '\0')
            return 0;
    return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : +1);
}

static void strcpy(char *dest, const char *src)
{
    int i;

    for (i = 0; src[i] != '\0'; i++)
        dest[i] = src[i];

    dest[i] = '\0';
}

static char *strcat(char *dest, const char *src)
{
    int i,j;

    for (i = 0; dest[i] != '\0'; i++)
        ;

    for (j = 0; src[j] != '\0'; j++)
        dest[i+j] = src[j];

    dest[i+j] = '\0';
    return dest;
}

void reverse(char *s)
{
     int i, j;
     char c;

     for (i = 0, j = strlen(s)-1; i<j; i++, j--)
     {
         c = s[i];
         s[i] = s[j];
         s[j] = c;
    }
}

static void itoa(int n, char *s)
{
     int i, sign;

     if ((sign = n) < 0)  /* record sign */
         n = -n;          /* make n positive */
     i = 0;
     do {       /* generate digits in reverse order */
         s[i++] = n % 10 + '0';   /* get next digit */
     } while ((n /= 10) > 0);     /* delete it */
     if (sign < 0)
         s[i++] = '-';
     s[i] = '\0';
     reverse(s);
}

static char *strstr(char *string, char *substring)
{
    char *a, *b;

    b = substring;
    if (*b == 0)
        return string;

    for ( ; *string != 0; string += 1)
    {
        if (*string != *b)
            continue;

        a = string;
        while (1)
        {
            if (*b == 0)
                return string;

            if (*a++ != *b++)
                break;
        }
        b = substring;
    }
    return (char *) 0;
}

static void wstrcpy(CHAR16 *dest, const CHAR16 *src)
{
    int i;

    for (i = 0; src[i] != '\0'; i++)
        dest[i] = src[i];

    dest[i] = '\0';
}

static char *sprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
{
    char *p, c;

    p = nbuf;
    *p = '\0';
    do
    {
        c = hex2ascii(num % base);
        *++p = upper ? toupper(c) : c;
    }
    while (num /= base);

    if (lenp)
        *lenp = p - nbuf;
    return (p);
}

int printf(const char *fmt, ...)
{
    char *d;
    const char *p, *percent, *q;
    unsigned char *up;
    int radix = 10;
    int ch, n;
    uintmax_t num;
    int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
    int cflag, hflag, jflag, tflag, zflag;
    int dwidth, upper;
    char padc;
    int stop = 0, retval = 0;
    va_list ap;

    va_start(ap, fmt);

    num = 0;

    if (fmt == NULL)
         fmt = "(fmt null)\n";

    for (;;)
    {
        padc = ' ';
        width = 0;
        while ((ch = (unsigned char)*fmt++) != '%' || stop)
        {
            if (ch == '\0')
                return (retval);
            WriteChar(ch);
        }
        percent = fmt - 1;
        qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
        sign = 0; dot = 0; dwidth = 0; upper = 0;
        cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
reswitch:
        switch (ch = (unsigned char)*fmt++)
        {
            case '.':
                dot = 1;
                goto reswitch;

            case '#':
                sharpflag = 1;
                goto reswitch;

            case '+':
                sign = 1;
                goto reswitch;

            case '-':
                ladjust = 1;
                goto reswitch;

            case '%':
                WriteChar(ch);
                break;

            case '*':
                if (!dot)
                {
                    width = va_arg(ap, int);
                    if (width < 0)
                    {
                        ladjust = !ladjust;
                        width = -width;
                    }
                }
                else
                    dwidth = va_arg(ap, int);
                goto reswitch;

            case '0':
                if (!dot)
                {
                    padc = '0';
                    goto reswitch;
                }

            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                for (n = 0;; ++fmt)
                {
                    n = n * 10 + ch - '0';
                    ch = *fmt;
                    if (ch < '0' || ch > '9')
                        break;
                }
                if (dot)
                    dwidth = n;
                else
                    width = n;
                goto reswitch;

            case 'b':
                num = (unsigned int)va_arg(ap, int);
                p = va_arg(ap, char *);
                for (q = sprintn(nbuf, num, *p++, NULL, 0); *q;)
                    WriteChar(*q--);

                if (num == 0)
                    break;

                for (tmp = 0; *p;)
                {
                    n = *p++;
                    if (num & (1 << (n - 1)))
                    {
                        WriteChar(tmp ? ',' : '<');
                        for (; (n = *p) > ' '; ++p)
                            WriteChar(n);
                        tmp = 1;
                    }
                    else
                        for (; *p > ' '; ++p)
                            continue;
                }
                if (tmp)
                    WriteChar('>');
                break;

            case 'c':
                WriteChar(va_arg(ap, int));
                break;

            case 'D':
                up = va_arg(ap, unsigned char *);
                p = va_arg(ap, char *);
                if (!width)
                    width = 16;
                while(width--)
                {
                    WriteChar(hex2ascii(*up >> 4));
                    WriteChar(hex2ascii(*up & 0x0f));
                    up++;
                    if (width)
                        for (q=p;*q;q++)
                            WriteChar(*q);
                }
                break;

            case 'd':
            case 'i':
                base = 10;
                sign = 1;
                goto handle_sign;

            case 'h':
                if (hflag)
                {
                    hflag = 0;
                    cflag = 1;
                }
                else
                    hflag = 1;
                goto reswitch;

            case 'j':
                jflag = 1;
                goto reswitch;

            case 'l':
                if (lflag)
                {
                    lflag = 0;
                    qflag = 1;
                }
                else
                    lflag = 1;
                goto reswitch;

            case 'n':
                if (jflag)
                    *(va_arg(ap, intmax_t *)) = retval;
                else if (qflag)
                    *(va_arg(ap, long long *)) = retval;
                else if (lflag)
                    *(va_arg(ap, long *)) = retval;
                else if (zflag)
                    *(va_arg(ap, int *)) = retval;
                else if (hflag)
                    *(va_arg(ap, short *)) = retval;
                else if (cflag)
                    *(va_arg(ap, char *)) = retval;
                else
                    *(va_arg(ap, int *)) = retval;
                break;

            case 'o':
                base = 8;
                goto handle_nosign;

            case 'p':
                base = 16;
                sharpflag = (width == 0);
                sign = 0;
                num = (uintptr_t)va_arg(ap, void *);
                goto number;

            case 'q':
                qflag = 1;
                goto reswitch;

            case 'r':
                base = radix;
                if (sign)
                    goto handle_sign;
                goto handle_nosign;

            case 's':
                p = va_arg(ap, char *);
                if (p == NULL)
                    p = "(null)";
                if (!dot)
                    n = strlen (p);
                else
                    for (n = 0; n < dwidth && p[n]; n++)
                        continue;

                width -= n;

                if (!ladjust && width > 0)
                    while (width--)
                        WriteChar(padc);
                    while (n--)
                        WriteChar(*p++);
                    if (ladjust && width > 0)
                        while (width--)
                            WriteChar(padc);
                break;

            case 't':
                tflag = 1;
                goto reswitch;

            case 'u':
                base = 10;
                goto handle_nosign;

            case 'X':
                upper = 1;

            case 'x':
                base = 16;
                goto handle_nosign;

            case 'y':
                base = 16;
                sign = 1;
                goto handle_sign;

            case 'z':
                zflag = 1;
                goto reswitch;

handle_nosign:
                sign = 0;
                if (jflag)
                    num = va_arg(ap, uintmax_t);
                else if (qflag)
                    num = va_arg(ap, unsigned long long);
                else if (tflag)
                    num = va_arg(ap, void *);
                else if (lflag)
                    num = va_arg(ap, unsigned long);
                else if (zflag)
                    num = va_arg(ap, int);
                else if (hflag)
                    num = (unsigned short int)va_arg(ap, int);
                else if (cflag)
                    num = (unsigned char)va_arg(ap, int);
                else
                    num = va_arg(ap, unsigned int);
                goto number;

handle_sign:
                if (jflag)
                    num = va_arg(ap, intmax_t);
                else if (qflag)
                    num = va_arg(ap, long long);
                else if (tflag)
                    num = va_arg(ap, void *);
                else if (lflag)
                    num = va_arg(ap, long);
                else if (hflag)
                    num = (short)va_arg(ap, int);
                else if (cflag)
                    num = (char)va_arg(ap, int);
                else
                    num = va_arg(ap, int);
number:
                if (sign && (intmax_t)num < 0)
                {
                    neg = 1;
                    num = -(intmax_t)num;
                }
                p = sprintn(nbuf, num, base, &tmp, upper);
                if (sharpflag && num != 0)
                {
                    if (base == 8)
                        tmp++;
                    else if (base == 16)
                        tmp += 2;
                }
                if (neg)
                    tmp++;

                if (!ladjust && padc != '0' && width && (width -= tmp) > 0)
                    while (width--)
                        WriteChar(padc);
                if (neg)
                        WriteChar('-');
                if (sharpflag && num != 0)
                {
                    if (base == 8)
                    {
                        WriteChar('0');
                    }
                    else if (base == 16)
                    {
                        WriteChar('0');
                        WriteChar('x');
                    }
                }
                if (!ladjust && width && (width -= tmp) > 0)
                    while (width--)
                        WriteChar(padc);

                while (*p)
                    WriteChar(*p--);

                if (ladjust && width && (width -= tmp) > 0)
                    while (width--)
                        WriteChar(padc);

                break;

            default:
                while (percent < fmt)
                    WriteChar(*percent++);
                stop = 1;
                break;
        }
    }
    va_end(ap);
    return 0;
}

static void ConvertToWide(CHAR16 *dest, const char *src)
{
    int i = 0;

    while (src[i])
    {
        dest[i] = (CHAR16)src[i];
        i++;
    }
    dest[i] = 0;
}

static void ConvertFromWide(char *dest, const CHAR16 *src)
{
    int i = 0;

    while (src[i])
    {
        dest[i] = (char)src[i];
        i++;
    }
    dest[i] = 0;
}


static int ShowMode(int Mode)
{
    unsigned int Size;

    if (Gop->QueryMode(Gop, Mode, &Size, &Info) == EFI_SUCCESS)
    {
        printf("Mode %d: %dx%d, ", Mode, Info->HorizontalResolution, Info->VerticalResolution);
       
        switch (Info->PixelFormat)
        {
            case PixelRedGreenBlueReserved8BitPerColor:
                printf("8-bit RGB\n\r");
                break;

            case PixelBlueGreenRedReserved8BitPerColor:
                printf("8-bit BGR\n\r");
                break;

            case PixelBitMask:
                printf("Bit mask\n\r");
                break;

            case PixelBltOnly:
                printf("Blit only\n\r");
                break;
        }
        return 1;
    }
    return 0;
}

static void ShowUsedMode()
{       
    printf("GOP: %dx%d, ", Width, Height);
       
    switch (PixelFormat)
    {
        case PixelRedGreenBlueReserved8BitPerColor:
            printf("8-bit RGB, ");
            break;

        case PixelBlueGreenRedReserved8BitPerColor:
            printf("8-bit BGR, ");
            break;

        case PixelBitMask:
            printf("Bit mask, ");
            break;

        case PixelBltOnly:
            printf("Blit only, ");
            break;
    }

    printf("Base: %08lX, Size: %08lX\n\r", LfbBase, LfbSize);
}

static void ShowAvailableModes()
{
    ShowMode(0);
    ShowMode(1);
    ShowMode(2);
    ShowMode(3);
    ShowMode(4);
    ShowMode(5);
    ShowMode(6);
    ShowMode(7);
    ShowMode(8);
    ShowMode(9);
}

static void InitGop()
{
    Status = BS->LocateProtocol(&GopProtocol, 0, &Interface);

    if (EFI_ERROR(Status))
    {
        printf("GOP Not found\n\r");
        return Status;
    }

    Gop = (EFI_GRAPHICS_OUTPUT_PROTOCOL *)Interface;

    Info = Gop->Mode->Info;
    Width = Info->HorizontalResolution;
    Height = Info->VerticalResolution;
    ScanLine = Info->PixelsPerScanLine;
    PixelFormat = Info->PixelFormat;

    LfbBase = Gop->Mode->FrameBufferBase;
    LfbSize = Gop->Mode->FrameBufferSize;

    ShowAvailableModes();
    ShowUsedMode();
}

static void GetFileInfo(EFI_FILE_HANDLE DirHandle)
{
    unsigned int Size = 1024;
    FileInfo = (EFI_FILE_INFO *)FsInfoData;

    if (DirHandle->GetInfo(DirHandle, &GenericFileInfo, &Size, FsInfoData) == EFI_SUCCESS)
    {
        printf("Path: <");

        ST->ConOut->OutputString(ST->ConOut, FileInfo->FileName);

        printf(">\n\r");
    }
}

static void GetFileSystemInfo(EFI_FILE_HANDLE DirHandle)
{
    unsigned int Size = 1024;
    FsInfo = (EFI_FILE_SYSTEM_INFO *)FsInfoData;

    if (DirHandle->GetInfo(DirHandle, &FileSystemInfo, &Size, FsInfoData) == EFI_SUCCESS)
    {
        printf("Volume label: <");

        ST->ConOut->OutputString(ST->ConOut, FsInfo->VolumeLabel);

        printf(">\n\r");
    }
}

static void AddMenuRow(const char *str, const CHAR16 *FileName, UINT64 FileSize)
{
    int i;
    char *ptr = MenuArr[MenuRows].MenuStr;

    wstrcpy(MenuArr[MenuRows].FileName, FileName);
    MenuArr[MenuRows].Volume = CurrVolume;
    MenuArr[MenuRows].FileSize = (unsigned int)FileSize;

    MenuRows++;

    *ptr = ' ';
    ptr++;

    for (i = 1; i < MENU_WIDTH; i++)
    {
        if (*str)
        {
            *ptr = *str;
            str++;
        }
        else
            *ptr = ' ';
        ptr++;
    }
    *ptr = 0;
}

static void GetNormalFile(EFI_FILE_HANDLE DirHandle)
{
    unsigned int Size = 1024;
    FileInfo = (EFI_FILE_INFO *)FsInfoData;
    char *substr;

    DirHandle->SetPosition(DirHandle, 0);

    while (Size)
    {
        Size = 1024;
       
        if (DirHandle->Read(DirHandle, &Size, FsInfoData) == EFI_SUCCESS)
        {
            if (Size)
            {
                if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0)
                {
                    ConvertFromWide(str, FileInfo->FileName);
                    strlower(str);

                    if (!strcmp(str, "rdos.bin"))
                    {
                        strcpy(str, "RDOS - normal boot");
                        if (CurrFs)
                        {
                            strcat(str, " (part");
                            itoa(CurrFs, buf);
                            strcat(str, buf);
                            strcat(str, ")");
                        }
                        AddMenuRow(str, FileInfo->FileName, FileInfo->FileSize);
                    }
                }
            }
        }
    }
}

static void GetSafeFile(EFI_FILE_HANDLE DirHandle)
{
    unsigned int Size = 1024;
    FileInfo = (EFI_FILE_INFO *)FsInfoData;
    char *substr;

    DirHandle->SetPosition(DirHandle, 0);

    while (Size)
    {
        Size = 1024;
       
        if (DirHandle->Read(DirHandle, &Size, FsInfoData) == EFI_SUCCESS)
        {
            if (Size)
            {
                if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0)
                {
                    ConvertFromWide(str, FileInfo->FileName);
                    strlower(str);

                    if (!strcmp(str, "safe.bin"))
                    {
                        strcpy(str, "RDOS - safe mode boot");
                        if (CurrFs)
                        {
                            strcat(str, " (part");
                            itoa(CurrFs, buf);
                            strcat(str, buf);
                            strcat(str, ")");
                        }
                        AddMenuRow(str, FileInfo->FileName, FileInfo->FileSize);
                    }
                }
            }
        }
    }
}

static void GetOtherFiles(EFI_FILE_HANDLE DirHandle)
{
    unsigned int Size = 1024;
    FileInfo = (EFI_FILE_INFO *)FsInfoData;
    char *substr;
    int isrdos;

    DirHandle->SetPosition(DirHandle, 0);

    while (Size)
    {
        Size = 1024;
       
        if (DirHandle->Read(DirHandle, &Size, FsInfoData) == EFI_SUCCESS)
        {
            if (Size)
            {
                isrdos = 0;

                if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0)
                {
                    ConvertFromWide(str, FileInfo->FileName);
                    strlower(str);

                    if (!strcmp(str, "rdos.bin"))
                        isrdos = 1;

                    if (!isrdos && !strcmp(str, "safe.bin"))
                        isrdos = 1;

                    if (!isrdos)
                    {
                        substr = strstr(str, ".bin");
                        if (substr)
                        {
                            strcpy(buf, str);
                            strcpy(str, "RDOS - ");
                            strcat(str, buf);
                            strcat(str, " boot");

                            if (CurrFs)
                            {
                                strcat(str, " (part");
                                itoa(CurrFs, buf);
                                strcat(str, buf);
                                strcat(str, ")");
                            }
                            AddMenuRow(str, FileInfo->FileName, FileInfo->FileSize);
                        }
                    }
                }
            }
        }
    }
}

static void CheckFs(EFI_HANDLE handle)
{
    if (BS->HandleProtocol(handle, &FileSystemProtocol, &Interface) == EFI_SUCCESS)
    {
        Fs = (EFI_FILE_IO_INTERFACE*)Interface;

        if (Fs->OpenVolume(Fs, &Root) == EFI_SUCCESS)
        {
            CurrVolume = Fs;

            GetFileSystemInfo(Root);
            GetNormalFile(Root);
            GetSafeFile(Root);
            GetOtherFiles(Root);
            Root->Close(Root);
        }
    }
}

static void InitFs()
{
    CurrFs = 0;
    CheckFs(Image->DeviceHandle);

    FsCount = 0;
    BS->LocateHandleBuffer(ByProtocol, &FileSystemProtocol, 0, &FsCount, &FsArr);

    for (CurrFs = 1; CurrFs <= FsCount; CurrFs++)
        if (FsArr[CurrFs - 1] != Image->DeviceHandle)
            CheckFs(FsArr[CurrFs - 1]);
}

static void DrawBox(int StartRow, int StartCol, int InnerRows, int InnerCols)
{
    int i;

    ConvertToWide(wstr, "          RDOS UEFI boot-loader");
    ST->ConOut->SetCursorPosition(ST->ConOut, StartCol + 2, StartRow - 1);
    ST->ConOut->OutputString(ST->ConOut, wstr);

    for (i = 0; i < InnerCols; i++)
        wstr[i] = BOXDRAW_DOUBLE_HORIZONTAL;
    wstr[InnerCols] = 0;

    ST->ConOut->SetCursorPosition(ST->ConOut, StartCol + 1, StartRow);
    ST->ConOut->OutputString(ST->ConOut, wstr);

    ST->ConOut->SetCursorPosition(ST->ConOut, StartCol + 1, StartRow + InnerRows + 1);
    ST->ConOut->OutputString(ST->ConOut, wstr);

    wstr[0] = BOXDRAW_DOUBLE_DOWN_RIGHT;
    wstr[1] = 0;
    ST->ConOut->SetCursorPosition(ST->ConOut, StartCol, StartRow);
    ST->ConOut->OutputString(ST->ConOut, wstr);

    wstr[0] = BOXDRAW_DOUBLE_DOWN_LEFT;
    wstr[1] = 0;
    ST->ConOut->SetCursorPosition(ST->ConOut, StartCol + InnerCols + 1, StartRow);
    ST->ConOut->OutputString(ST->ConOut, wstr);

    wstr[0] = BOXDRAW_DOUBLE_UP_RIGHT;
    wstr[1] = 0;
    ST->ConOut->SetCursorPosition(ST->ConOut, StartCol, StartRow + InnerRows + 1);
    ST->ConOut->OutputString(ST->ConOut, wstr);

    wstr[0] = BOXDRAW_DOUBLE_UP_LEFT;
    wstr[1] = 0;
    ST->ConOut->SetCursorPosition(ST->ConOut, StartCol + InnerCols + 1, StartRow + InnerRows + 1);
    ST->ConOut->OutputString(ST->ConOut, wstr);

    wstr[0] = BOXDRAW_DOUBLE_VERTICAL;
    wstr[1] = 0;

    for (i = 0; i < InnerRows; i++)
    {
        ST->ConOut->SetCursorPosition(ST->ConOut, StartCol, StartRow + i + 1);
        ST->ConOut->OutputString(ST->ConOut, wstr);

        ST->ConOut->SetCursorPosition(ST->ConOut, StartCol + InnerCols + 1, StartRow + i + 1);
        ST->ConOut->OutputString(ST->ConOut, wstr);
    }

}

static void DrawRow(int Row)
{
    ConvertToWide(wstr, MenuArr[Row].MenuStr);

    if (SelectedRow == Row)
        ST->ConOut->SetAttribute(ST->ConOut, EFI_BLACK | EFI_BACKGROUND_LIGHTGRAY);
    else
        ST->ConOut->SetAttribute(ST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK);

    ST->ConOut->SetCursorPosition(ST->ConOut, StartCol + 2, StartRow + 1 + Row);
    ST->ConOut->OutputString(ST->ConOut, wstr);
}

static void SetupMenu()
{
    int i;

    TextMode = ST->ConOut->Mode->Mode;

    if (ST->ConOut->QueryMode(ST->ConOut, TextMode, &TextCols, &TextRows) != EFI_SUCCESS)
    {
        TextCols = 80;
        TextRows = 25;
    }

    printf("Mode: %d, %dx%d\n\r", TextMode, TextRows, TextCols);

    ST->ConOut->ClearScreen(ST->ConOut);

    StartRow = 1;
    StartCol = TextCols / 2 - MENU_WIDTH / 2;
    SelectedRow = 0;

    DrawBox(StartRow, StartCol, MenuRows, MENU_WIDTH + 2);

    for (i = 0; i < MenuRows; i++)
        DrawRow(i);

    ST->ConOut->SetAttribute(ST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK);
}

static void HandleMenu()
{
    for (;;)
    {
        while ((Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key)) == EFI_NOT_READY)
            ;

        switch (Key.ScanCode)
        {
            case SCAN_UP:
                if (SelectedRow > 0)
                {
                    SelectedRow--;
                    DrawRow(SelectedRow);
                    DrawRow(SelectedRow + 1);
                }
                break;

            case SCAN_DOWN:
                if (SelectedRow < MenuRows - 1)
                {
                    SelectedRow++;
                    DrawRow(SelectedRow);
                    DrawRow(SelectedRow - 1);
                }
                break;
 
            default:
                break;
        }

        if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)
            break;
    }
}

static int LoadRdosBinary()
{
    unsigned int FileSize = MenuArr[SelectedRow].FileSize;
    RdosImagePages = FileSize / 0x1000 + 1;
    int ok = 0;
    int i;

    printf("Booting: <");
    ST->ConOut->OutputString(ST->ConOut, MenuArr[SelectedRow].FileName);
    printf(">, %d bytes\n\r", FileSize);

    Fs = MenuArr[SelectedRow].Volume;

    if (Fs->OpenVolume(Fs, &Root) == EFI_SUCCESS)
    {
        if (Root->Open(Root, &FileHandle, MenuArr[SelectedRow].FileName, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM) == EFI_SUCCESS)
        {
            if (BS->AllocatePages(AllocateAddress, EfiRuntimeServicesData, RdosImagePages, &RdosImageBase) == EFI_SUCCESS)
            {
                printf("Image base: %08lX\n\r", RdosImageBase);

                FileHandle->SetPosition(FileHandle, 0);
                FileHandle->Read(FileHandle, &FileSize, RdosImageBase);
               
//                for (i = 0; i < RdosImagePages; i++)
//                {
//                    FileHandle->Read(FileHandle, 0x1000, RdosImageBase);
//                    RdosImageBase += 0x1000;
//                }

                ok = 1;
            }
            else
                printf("Failed to allocate fixed memory for RDOS boot\n\r");

            FileHandle->Close(FileHandle);
        }
        else
            printf("Cannot open file\n\r");
           
        Root->Close(Root);
    }
    else
        printf("Cannot open volume\n\r");

    return ok;
}

static int LoadBootLoader()
{
    int ok = 0;
    int size = RdosLoaderPages * 0x1000;

    if (sizeof(void *) == 4)
        strcpy(str, "efi\\rdos\\boot32.bin");
    else
        strcpy(str, "efi\\rdos\\boot64.bin");

    printf("Loading: ");
    printf(str);
    printf("\n\r");

    ConvertToWide(wstr, str);

    Fs = MenuArr[SelectedRow].Volume;

    if (Fs->OpenVolume(Fs, &Root) == EFI_SUCCESS)
    {
        if (Root->Open(Root, &FileHandle, wstr, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM) == EFI_SUCCESS)
        {
            if (BS->AllocatePages(AllocateAddress, EfiBootServicesData, RdosLoaderPages, &RdosLoaderBase) == EFI_SUCCESS)
            {
                printf("Loader base: %08lX\n\r", RdosLoaderBase);

                if (FileHandle->Read(FileHandle, &size, RdosLoaderBase) == EFI_SUCCESS)
                {
                    ok = 1;

                    short int us = *(short int *)RdosLoaderBase;
                    printf("Loader start: %04hX\n\r", us);
                }
                else
                {
                    BS->FreePages(RdosLoaderBase, RdosLoaderPages);
                    printf("Failed to read RDOS loader\n\r");
                }
            }
            else
                printf("Failed to allocate fixed memory for RDOS loader\n\r");

            FileHandle->Close(FileHandle);
        }
        else
            printf("Cannot open loader file\n\r");
           
        Root->Close(Root);
    }
    else
        printf("Cannot open volume\n\r");

    return ok;
}

static void ShowMem(unsigned long long Base, unsigned long long Size)
{
    unsigned int lsb, msb;

    lsb = (unsigned int)Base;
    msb = (unsigned int)(Base >> 32);
    printf("%08lX_%08lX-", msb, lsb);

    Base += Size;
    Base--;
    lsb = (unsigned int)Base;
    msb = (unsigned int)(Base >> 32);
    printf("%08lX_%08lX\n\r", msb, lsb);
}

static void DumpMem()
{
    int i;

    printf("ACPI: %08lX\n\r", AcpiTable);
    printf("LFB: %08lX\n\r", LfbBase);

    for (i = 0; i < MemMapCount; i++)
        ShowMem(MemMapArr[i].Base, MemMapArr[i].Size);
}

static void AddMem(unsigned long long Base, unsigned long long Size)
{
    MemMapArr[MemMapCount].Len = 0x14;
    MemMapArr[MemMapCount].Base = Base;
    MemMapArr[MemMapCount].Size = Size;
    MemMapArr[MemMapCount].Type = 1;
    MemMapCount++;
}

static int ConvertMemoryMap()
{
    int i;
    int count;
    char *ptr;
    EFI_MEMORY_DESCRIPTOR *memptr;
    unsigned long long Base;
    unsigned long long Size;
    int has_entry = 0;
    EFI_PHYSICAL_ADDRESS RdosMemBase = RDOS_MEM;

    MemMapCount = 0;
    MemMapArr = (struct MemMapEntry *)RdosMemBase;   
   
    if (BS->GetMemoryMap(&MemMapSize, MemMap, &MapKey, &MemDescrSize, &MemDescrVersion) == EFI_SUCCESS)
    {
        ptr = (char *)MemMap;
        count = MemMapSize / MemDescrSize;

        AddMem(0, 0x90000);

        for (i = 0; i < count; i++)
        {
            memptr = (EFI_MEMORY_DESCRIPTOR *)ptr;
           
            switch (memptr->Type)
            {
                case EfiLoaderCode:
                case EfiLoaderData:
                case EfiBootServicesCode:
                case EfiBootServicesData:
                case EfiConventionalMemory:
                    if (has_entry)
                    {
                        if (Base + Size == memptr->PhysicalStart)
                            Size += memptr->NumberOfPages << 12;
                        else
                        {
                            if (Base >= 0x90000)
                                AddMem(Base, Size);
                            Base = memptr->PhysicalStart;
                            Size = memptr->NumberOfPages << 12;
                        }
                    }
                    else
                    {
                        Base = memptr->PhysicalStart;
                        Size = memptr->NumberOfPages << 12;
                        has_entry = 1;
                    }
                    break;

                default:
                    if (has_entry)
                    {
                        if (Base >= 0x90000)
                            AddMem(Base, Size);
                        has_entry = 0;
                    }
                    break;
            }
            ptr += MemDescrSize;
        }

        if (has_entry)
            AddMem(Base, Size);

//        DumpMem();

        return 1;
    }
                       
    return 0;
}

int CompareGUIDs( EFI_GUID left, EFI_GUID right )
{
    return left.Data1 == right.Data1 &&
           left.Data2 == right.Data2 &&
           left.Data3 == right.Data3 &&
           left.Data4[0] == right.Data4[0] &&
           left.Data4[1] == right.Data4[1] &&
           left.Data4[2] == right.Data4[2] &&
           left.Data4[3] == right.Data4[3] &&
           left.Data4[4] == right.Data4[4] &&
           left.Data4[5] == right.Data4[5] &&
           left.Data4[6] == right.Data4[6] &&
           left.Data4[7] == right.Data4[7];
}


static void GetAcpiTable()
{
    int i;
    unsigned int ConfigTableCount = ST->NumberOfTableEntries;
    ConfigTableArr = ST->ConfigurationTable;
    EFI_GUID AcpiTableGuid = ACPI_20_TABLE_GUID;

    AcpiTable = 0;

    for (i = 0; i < ConfigTableCount; i++)
        if (CompareGUIDs(ConfigTableArr[i].VendorGuid, AcpiTableGuid))
            AcpiTable = ConfigTableArr[i].VendorTable;

}                       

static void StartLoader()
{
    StartLoaderProc = (void *)LoaderEntry;
    LoaderData = (struct LoaderParam *)LoaderParamPos;

    LoaderData->Lfb = LfbBase;
    LoaderData->LfbWidth = Width;
    LoaderData->LfbHeight = Height;
    if (ScanLine)
        LoaderData->LfbLineSize = 4 * ScanLine;
    else
        LoaderData->LfbLineSize = 4 * Width;
    LoaderData->LfbFlags = 0;
    LoaderData->AcpiTable = (long long)AcpiTable;

    switch (PixelFormat)
    {
        case PixelRedGreenBlueReserved8BitPerColor:
            break;

        case PixelBlueGreenRedReserved8BitPerColor:
            LoaderData->LfbFlags | PIXEL_REVERSE;
            break;
    };

    LoaderData->MemEntries = MemMapCount;

    (*StartLoaderProc)();
}
           
EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
    /* Store the system table for future use in other functions */
    ST = SystemTable;
    BS = SystemTable->BootServices;

    InitGop();

    if (EFI_ERROR(Status))
        return Status;

    Status = BS->HandleProtocol(ImageHandle, &LoadedImageProtocol, &Interface);
    if (EFI_ERROR(Status))
        return Status;

    Image = (EFI_LOADED_IMAGE *)Interface;

    if (Image->FilePath->Type == MEDIA_DEVICE_PATH && Image->FilePath->SubType == MEDIA_FILEPATH_DP)
    {
        LoadedPath = (FILEPATH_DEVICE_PATH *)Image->FilePath;

        printf("Loaded image :<");
        ST->ConOut->OutputString(ST->ConOut, LoadedPath->PathName);
        printf(">\n\r");

    }
    else
        return -1;

    InitFs();

    if (MenuRows)
    {
        SetupMenu();
        HandleMenu();
        ST->ConOut->ClearScreen(ST->ConOut);

        if (LoadRdosBinary())
        {
            if (LoadBootLoader())
            {
                GetAcpiTable();

                if (ConvertMemoryMap())
                {
                    BS->SetWatchdogTimer(0, 0, 0, NULL);
                    if (BS->ExitBootServices(ImageHandle, MapKey) == EFI_SUCCESS)
                        StartLoader();
                    else
                        printf("Exit boot services failed\n\r");
                }
                else
                    printf("Get memory map failed\n\r");

                BS->FreePages(RdosLoaderBase, RdosLoaderPages);
            }

            BS->FreePages(RdosImageBase, RdosImagePages);
        }
    }

    printf("Failed to load, press any key to continue\n\r");   
 
    /* Now wait for a keystroke before continuing, otherwise your
       message will flash off the screen before you see it.

       First, we need to empty the console input buffer to flush
       out any keystrokes entered before this point */
    Status = ST->ConIn->Reset(ST->ConIn, FALSE);
    if (EFI_ERROR(Status))
        return Status;


    /* Now wait until a key becomes available.  This is a simple
       polling implementation.  You could try and use the WaitForKey
       event instead if you like */
    while ((Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key)) == EFI_NOT_READY) ;

    return Status;
}


Here is the makefile (built with cygwin64):

Code:
OUTPUT = bootx64.efi

EFI_CC ?= gcc

CFLAGS = -I../efi -I../efi/inc -I../efi/inc/x86_64 -I../efi/inc/protocol -Wall -Wextra -Wno-long-long -g -ffreestanding

OBJS = ../efimain.o

all: $(OUTPUT)

%.o: %.c Makefile
   $(EFI_CC) -c -o $@ $< $(CFLAGS)
   
$(OUTPUT): $(OBJS)
   $(EFI_CC) -nostdlib -Wl,-dll -shared -Wl,--subsystem,10 -e efi_main -o $(OUTPUT) $(OBJS) -lgcc

.PHONY: clean

clean:
   rm -f *.o $(OUTPUT)



Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Mon Mar 18, 2019 1:46 pm 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
Same Acer laptop, and it seems like Linux "freezes" too:

https://community.amd.com/thread/234045


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Mon Mar 18, 2019 2:23 pm 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
Updating to a newer BIOS version (1.13) doesn't help either.


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Mon Mar 18, 2019 3:55 pm 
Offline
Member
Member
User avatar

Joined: Wed Oct 27, 2004 11:00 pm
Posts: 874
Location: WA
rdos wrote:
If I create a loop in the 32-bit loader (which is reached by switching from long mode to 32-bit protected mode), then the blank display is still shown and there is a lock-up. Thus, the lockup after 15 seconds is firmware related and not related to my OS.

If I create a loop in the 64-bit loader, then there is a reboot after 15 seconds. Thus, if the system is still in long mode, then there is a reboot, but if the system is in protected mode, then the system freezes.

my first instinct is that this sounds to me, like that particular firmware isn't disabling the watchdog timer (or you aren't calling ExitBootServices properly)

this would result in the watchdog timer going off after a period of time... if you are still in LMode, then the firmware's IDT intercepts the interrupt and restarts the boot process -- but if you have switched to PMode, the LMode IDT is invalid and this results in a triple-fault

_________________
## ---- ----- ------ Intel Manuals
OSdev wiki


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Mon Mar 18, 2019 4:39 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
One thing I thought of too, is that you might be trashing the AML code/data area. The ACPI Reserved area, which includes the AML code, should still be intact even after ExitBootServices. You can trash the ACPI Reclaim area but not the ACPI NVS memory.

Just a thought I had.

Ben
- http://www.fysnet.net/osdesign_book_series.htm


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Tue Mar 19, 2019 1:43 am 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
BenLunt wrote:
One thing I thought of too, is that you might be trashing the AML code/data area. The ACPI Reserved area, which includes the AML code, should still be intact even after ExitBootServices. You can trash the ACPI Reclaim area but not the ACPI NVS memory.

Just a thought I had.

Ben
- http://www.fysnet.net/osdesign_book_series.htm


I checked the memory used by EFI, and they have something around 0x09000000, but that is still far beyond any area that I use in the load process. I load the OS loader at 0x110000 (just above the HMA area), and the OS image at 0x121000. The OS image is 3-4MB.


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Tue Mar 19, 2019 1:52 am 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
JAAman wrote:
rdos wrote:
If I create a loop in the 32-bit loader (which is reached by switching from long mode to 32-bit protected mode), then the blank display is still shown and there is a lock-up. Thus, the lockup after 15 seconds is firmware related and not related to my OS.

If I create a loop in the 64-bit loader, then there is a reboot after 15 seconds. Thus, if the system is still in long mode, then there is a reboot, but if the system is in protected mode, then the system freezes.

my first instinct is that this sounds to me, like that particular firmware isn't disabling the watchdog timer (or you aren't calling ExitBootServices properly)

this would result in the watchdog timer going off after a period of time... if you are still in LMode, then the firmware's IDT intercepts the interrupt and restarts the boot process -- but if you have switched to PMode, the LMode IDT is invalid and this results in a triple-fault


Yes, that's my impression too. Except when I did the PMode stop, interrupts were disabled, so that leaves only NMI or SMI as methods the BIOS can interfere. My guess is that it is an SMI that assume the core is still executing in LMode and tries to switch to long mode code and then faults. Although, tripple-faults usually reboot the PC and so shouldn't leave it hanging unless they have failed to implement the tripple-fault RESET logic properly,


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Tue Mar 19, 2019 5:37 am 
Offline
Member
Member

Joined: Tue May 13, 2014 3:02 am
Posts: 280
Location: Private, UK
rdos wrote:
Although, tripple-faults usually reboot the PC and so shouldn't leave it hanging unless they have failed to implement the tripple-fault RESET logic properly,


I wouldn't be surprised if modern systems have dropped the triple-fault reset logic. A triple fault almost always means the OS is beyond hope (and might well be displaying evidence of this already; such as an error message); nobody's running OS/2 1.x anymore!

_________________
Image


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Tue Mar 19, 2019 6:16 am 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
mallard wrote:
rdos wrote:
Although, tripple-faults usually reboot the PC and so shouldn't leave it hanging unless they have failed to implement the tripple-fault RESET logic properly,


I wouldn't be surprised if modern systems have dropped the triple-fault reset logic. A triple fault almost always means the OS is beyond hope (and might well be displaying evidence of this already; such as an error message); nobody's running OS/2 1.x anymore!


I only know of one specific embedded board where the tripple fault logic was missing, and it had an external watchdog to bring the system to a RESET.

I suppose, in general, ACPIs RESET method would be preferred, but I know cases when that doesn't work. In those cases, tripple fault is the only other method I know which does a real RESET.

I've looked at AMDs manual for Zen (17th generation), and it seems like it has a watchdog timer as an MSR, and if it is set up to the maximum interval, it would fire after about 20 seconds. It can be disabled, but if it turns out the tripple-fault logic is faulty, then I might want to continue to kick the watchdog somewhere in the scheduler. I might even use it in more sophisticated ways. While the documentation is poor, I suspect the watchdog triggers NMI, and the hangup in RDOS could be caused by failures in the NMI handler.


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Tue Mar 19, 2019 10:01 am 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
zaval wrote:
Quote:
or possibly the CPU overheats?

<flame>Of course it could, it's AMD after all. :mrgreen: </flame>


Actually, to the shock and amazement of nearly everyone :lol: , the Zen arch chips appear to lack that 'halt and catch fire' instruction which played such a large role in previous AMD chips. Which isn't to say that overheating isn't still a possibility.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Tue Mar 19, 2019 3:09 pm 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
The processor watchdog is active, but turning it off doesn't help.

I've also added code that sends an NMI, and then I do cli / hlt in a loop in the NMI handler. The OS becomes completely unresponsive, but the BIOS still manages to lock up the processor and turn off the display. I know the processor is locked up because I need to hold down the power button several seconds to turn it off before I can boot again.

I think I'm back to the BIOS having some kind of SMM code that does all of this. Cannot think of any other way it can gain control while the core is running with interrupts disabled in a halted state.

I've also verified that the tripple fault logic appears to cause a system RESET. Which means that the lockup caused by BIOS is not a tripple fault.


Top
 Profile  
 
 Post subject: Re: AMD Ryzen locks up with blank display
PostPosted: Wed Mar 20, 2019 4:19 pm 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 3193
I now have a method to make it work. If I start Windows 10, log in, restart and reboot with RDOS, it seems to work. From this state, I can reboot RDOS and boot again, and it still seems to work. If I turn off the computer, it goes into the hangup after 15-20s again, and then I have to boot Windows again.

Very strange.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next

All times are UTC - 6 hours


Who is online

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