Accessing ACPI MSDM From UEFI Shell

This post is an update on my February 2015 post on how to retrieve your Microsoft Windows 8 or later product key from your firmware via the ACPI MSDM (Microsoft Data Management) table and the UEFI Shell. You should read that post if you are unfamiliar with the ACPI MSDM table. Of note is the fact that the ACPI specification is now managed by the UEFI Forum.

The original version of this utility was named ListMSDM.efi and used Nigel Croxon’s excellent GNI-EFI library. This version is named ShowMSDM.efi and is based on the UDK2017 snapshot of the TianoCore EDK2 (EFI Development Kit, Version 2.)

Here is the current source code for ShowMSDM.efi:

//  Copyright (c) 2014-2018  Finnbarr P. Murphy.  All rights reserved.
//  Display ACPI MSDM and/or Microsoft Windows License Key
//  License: BSD License

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/ShellLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/PrintLib.h>

#include <Protocol/EfiShell.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/AcpiSystemDescriptionTable.h>

#include <Guid/Acpi.h>

#define UTILITY_VERSION L"20180221"
#undef DEBUG

#pragma pack(1)
typedef struct {
    UINT32   Version;
    UINT32   Reserved;
    UINT32   DataType;
    UINT32   DataReserved;
    UINT32   DataLength;
    CHAR8    Data[30];

// Microsoft Data Management table structure
typedef struct {
#pragma pack()

static VOID AsciiToUnicodeSize(CHAR8 *, UINT8, CHAR16 *, BOOLEAN);

static VOID
AsciiToUnicodeSize( CHAR8 *String,
                    UINT8 length,
                    CHAR16 *UniString,
                    BOOLEAN Quote )
    int len = length;

    if (Quote)
        *(UniString++) = L'"';
    while (*String != '\0' && len > 0) {
        *(UniString++) = (CHAR16) *(String++);
    if (Quote)
        *(UniString++) = L'"';
    *UniString = '\0';

static VOID
PrintHexTable( UINT8 *ptr,
               int Count )
    int i = 0;

    Print(L"  ");
    for (i = 0; i < Count; i++ ) {
        if ( i > 0 && i%16 == 0)
            Print(L"\n  ");
        Print(L"0x%02x ", 0xff & *ptr++);

static VOID
PrintAcpiHeader( EFI_ACPI_SDT_HEADER *Ptr )
    CHAR16 Buffer[50];

    Print(L"ACPI Standard Header\n");
    AsciiToUnicodeSize((CHAR8 *)&(Ptr->Signature), 4, Buffer, TRUE);
    Print(L"  Signature         : %s\n", Buffer);
    Print(L"  Length            : 0x%08x (%d)\n", Ptr->Length, Ptr->Length);
    Print(L"  Revision          : 0x%02x (%d)\n", Ptr->Revision, Ptr->Revision);
    Print(L"  Checksum          : 0x%02x (%d)\n", Ptr->Checksum, Ptr->Checksum);
    AsciiToUnicodeSize((CHAR8 *)&(Ptr->OemId), 6, Buffer, TRUE);
    Print(L"  OEM ID            : %s\n", Buffer);
    AsciiToUnicodeSize((CHAR8 *)&(Ptr->OemTableId), 8, Buffer, TRUE);
    Print(L"  OEM Table ID      : %s\n", Buffer);
    Print(L"  OEM Revision      : 0x%08x (%d)\n", Ptr->OemRevision, Ptr->OemRevision);
    AsciiToUnicodeSize((CHAR8 *)&(Ptr->CreatorId), 4, Buffer, TRUE);
    Print(L"  Creator ID        : %s\n", Buffer);
    Print(L"  Creator Revision  : 0x%08x (%d)\n", Ptr->CreatorRevision, Ptr->CreatorRevision);

static VOID
PrintSoftwareLicensing( SOFTWARE_LICENSING *Ptr,
                        BOOLEAN Verbose )
    CHAR16 Buffer[50];

    if (Verbose) {
        Print(L"Software Licensing\n");
        Print(L"  Version       : 0x%08x (%d)\n", Ptr->Version, Ptr->Version);
        Print(L"  Reserved      : 0x%08x (%d)\n", Ptr->Reserved, Ptr->Reserved);
        Print(L"  Data Type     : 0x%08x (%d)\n", Ptr->DataType, Ptr->DataType);
        Print(L"  Data Reserved : 0x%08x (%d)\n", Ptr->DataReserved, Ptr->DataReserved);
        Print(L"  Data Length   : 0x%08x (%d)\n", Ptr->DataLength, Ptr->DataLength);
        AsciiToUnicodeSize((CHAR8 *)(Ptr->Data), 30, Buffer, TRUE);
        Print(L"  Data          : %s\n", Buffer);
    } else {
        AsciiToUnicodeSize((CHAR8 *)(Ptr->Data), 30, Buffer, FALSE);
        Print(L"  %s\n", Buffer);

static VOID 
           BOOLEAN Verbose,
           BOOLEAN Hexdump )
    if (Hexdump) {
        PrintHexTable( (UINT8 *)Msdm, (int)(Msdm->Header.Length) );
    } else {
        if (Verbose) {
            PrintAcpiHeader( (EFI_ACPI_SDT_HEADER *)&(Msdm->Header) );
        PrintSoftwareLicensing( (SOFTWARE_LICENSING *)&(Msdm->SoftLic), Verbose);

static int
           CHAR16* GuidStr, 
           BOOLEAN Verbose,
           BOOLEAN Hexdump )
    EFI_ACPI_SDT_HEADER *Xsdt, *Entry;
#ifdef DEBUG 
    CHAR16 OemStr[20];
    UINT32 EntryCount;
    UINT64 *EntryPtr;

#ifdef DEBUG 
    Print(L"\n\nACPI GUID: %s\n", GuidStr);

    AsciiToUnicodeSize((CHAR8 *)(Rsdp->OemId), 6, OemStr, FALSE`);
    Print(L"\nFound RSDP. Version: %d  OEM ID: %s\n", (int)(Rsdp->Revision), OemStr);
        Xsdt = (EFI_ACPI_SDT_HEADER *)(Rsdp->XsdtAddress);
    } else {
#ifdef DEBUG 
        Print(L"ERROR: No ACPI XSDT table found.\n");
        return 1;

    if (Xsdt->Signature != SIGNATURE_32 ('X', 'S', 'D', 'T')) {
#ifdef DEBUG 
        Print(L"ERROR: Invalid ACPI XSDT table found.\n");
        return 1;

    EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_SDT_HEADER)) / sizeof(UINT64);
#ifdef DEBUG 
    AsciiToUnicodeSize((CHAR8 *)(Xsdt->OemId), 6, OemStr, FALSE);
    Print(L"Found XSDT. OEM ID: %s  Entry Count: %d\n\n", OemStr, EntryCount);

    EntryPtr = (UINT64 *)(Xsdt + 1);
    for (int Index = 0; Index < EntryCount; Index++, EntryPtr++) {
        Entry = (EFI_ACPI_SDT_HEADER *)((UINTN)(*EntryPtr));
        if (Entry->Signature == SIGNATURE_32 ('M', 'S', 'D', 'M')) {
            PrintMSDM((EFI_ACPI_MSDM *)((UINTN)(*EntryPtr)), Verbose, Hexdump);

    return 0;

static void
Usage( void )
    Print(L"Usage: ShowMSDM [-v | --verbose]\n");
    Print(L"       ShowMSDM [-V | --version]\n");
    Print(L"       ShowMSDM [-d | --dump]\n");

ShellAppMain( UINTN Argc, 
              CHAR16 **Argv )
    EFI_CONFIGURATION_TABLE *ect = gST->ConfigurationTable;
    EFI_GUID gAcpi20TableGuid = EFI_ACPI_20_TABLE_GUID;
    EFI_GUID gAcpi10TableGuid = ACPI_10_TABLE_GUID;
    CHAR16 GuidStr[100];
    BOOLEAN Verbose = FALSE;
    BOOLEAN Hexdump = FALSE;

    if (Argc == 2) {
        if (!StrCmp(Argv[1], L"--verbose") ||
            !StrCmp(Argv[1], L"-v")) {
            Verbose = TRUE;
        } else if (!StrCmp(Argv[1], L"--dump") ||
            !StrCmp(Argv[1], L"-d")) {
            Hexdump = TRUE;
        } else if (!StrCmp(Argv[1], L"--version") ||
            !StrCmp(Argv[1], L"-V")) {
            Print(L"Version: %s\n", UTILITY_VERSION);
            return Status;
        } else if (!StrCmp(Argv[1], L"--help") ||
            !StrCmp(Argv[1], L"-h")) {
            return Status;
        } else {
            return Status;
    if (Argc > 2) {
        return Status;

    // locate RSDP (Root System Description Pointer) 
    for (int i = 0; i < gST->NumberOfTableEntries; i++) {
        if ((CompareGuid (&(gST->ConfigurationTable[i].VendorGuid), &gAcpi20TableGuid)) ||
            (CompareGuid (&(gST->ConfigurationTable[i].VendorGuid), &gAcpi10TableGuid))) {
            if (!AsciiStrnCmp("RSD PTR ", (CHAR8 *)(ect->VendorTable), 8)) {
                UnicodeSPrint(GuidStr, sizeof(GuidStr), L"%g", &(gST->ConfigurationTable[i].VendorGuid));
                Rsdp = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)ect->VendorTable;
                ParseRSDP(Rsdp, GuidStr, Verbose, Hexdump); 

    if (Rsdp == NULL) {
        if (Verbose) {
            Print(L"ERROR: Could not find an ACPI RSDP table.\n");
        Status = EFI_NOT_FOUND;

    return Status;

I assume you are familiar with ACPI tables, EDK2 and UEFI APIs if you are reading this post and thus make no attempt to explain the relatively simple source code.

Here is a suitable .INF build file for this utility:

  INF_VERSION                    = 1.25
  BASE_NAME                      = ShowMSDM 
  FILE_GUID                      = 4ea87c51-7395-4dcd-0055-747010f3ce51
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = ShellCEntryLib
  VALID_ARCHITECTURES            = X64







Here is sample output from this utility:

fs1:> ShowMSDM.efi -h
Usage: ShowMSDM [-v | --verbose]
       ShowMSDM [-V | --version]
       ShowMSDM [-d | --dump]

fs1:> ShowMSDM.efi


fs1:> ShowMSDM.efi -v

ACPI Standard Header
  Signature         : "MSDM"
  Length            : 0x00000055 (85)
  Revision          : 0x03 (3)
  Checksum          : 0xBF (191)
  OEM ID            : "LENOVO"
  OEM Table ID      : "TP-JB   "
  OEM Revision      : 0x00001300 (4864)
  Creator ID        : "PTEC"
  Creator Revision  : 0x00000002 (2)

Software Licensing
  Version       : 0x00000001 (1)
  Reserved      : 0x00000000 (0)
  Data Type     : 0x00000001 (1)
  Data Reserved : 0x00000000 (0)
  Data Length   : 0x0000001D (29)
  Data          : "NJCD6-T6TDQ-WRYF7-GY44B-VQVQ2 "

fs1:> ShowMSDM.efi -d

  0x4D 0x53 0x44 0x4D 0x55 0x00 0x00 0x00 0x03 0xBF 0x4C 0x45 0x4E 0x4F 0x56 0x4F 
  0x54 0x50 0x2D 0x4A 0x42 0x20 0x20 0x20 0x00 0x13 0x00 0x00 0x50 0x54 0x45 0x43 
  0x02 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 
  0x00 0x00 0x00 0x00 0x1D 0x00 0x00 0x00 0x4E 0x4A 0x43 0x46 0x37 0x2D 0x54 0x36 
  0x54 0x44 0x51 0x2D 0x57 0x52 0x59 0x46 0x37 0x2D 0x47 0x59 0x34 0x34 0x42 0x2D 
  0x56 0x51 0x56 0x51 0x32 

fs1:> ShowMSDM.efi -V
Version: 20180221


Note that the displayed product key is a made-up (fake) product key – so do not bother trying to use it.


1 comment to Accessing ACPI MSDM From UEFI Shell

  • ly

    Well, now understand why after buying a refurbished Thinkpad x260 laptop, noticed reinstalled windows 10 home version was setup with BIOS in legacy boot mode (because I was setting a Linux double boot, otherwise I would not have noticed not being in UEFI mode)… so decided to reinstall from USB media…

    With a surprise in the end:
    Reinstalled win10 (with BIOS now in UEFI mode) was no more a home version, but a pro one!

    As Thinkpads are sold with a OEM pro licence, I suppose this license was still present in UEFI but no more used in legacy mode (probable reason why reseller switched to legacy mode: Being able to install it’s home refurbished PC licence… and charge you 50 bucks more if you want pro version!).

    I didn’t really needed a pro version, only interesting feature is being able to tune some automatic upgrade delays, thus not getting in bugs triggered by the new “rolling-release” nature of win10: They’ll hit others, beings removed & reworked, before me.