Step to UEFI (108)引用Protocol GUID的方法

每一个 Protocol 都有一个GUID,这是Protocol 正式的名称。编写一个Application,标准的做法是:

1. 在Application 的inf 文件, [Packages] 节中引用 MdePkg.dec , 实际上你用到的UEFI 标准的 Protocol GUID 在这个文件中都有定义;[Protocols] 节中定义你用到的 ProtocolGuid;

2.在Application的 c 文件中 extern 一下代码中用到的 GUID;

当然,这样的做法看起来不如直接在代码中使用 EFI_GUID 定义直接易懂,之前我写的很多代码为了省事采用的就是在 Application中重新定义的方法。

下面列出常用的 Protocol 的定义:

EFI_GUID gEfiLoadedImageProtocolGuid = {0x5B1B31A1, 0x9562,0x11D2,
        { 0x8E, 0x3F,0x0, 0xA0, 0xC9, 0x69,0x72, 0x3B } };
EFI_GUID gEfiLoadedImageDevicePathProtocolGuid = {0xBC62157E, 0x3E33,0x4FEC,
        { 0x99, 0x20,0x2D, 0x3B, 0x36, 0xD7,0x50, 0xDF } };
EFI_GUID gEfiSimpleTextOutProtocolGuid = {0x387477C2, 0x69C7,0x11D2,
        { 0x8E, 0x39,0x0, 0xA0, 0xC9, 0x69,0x72, 0x3B } };
EFI_GUID gEfiDevicePathProtocolGuid = {0x9576E91, 0x6D3F,0x11D2,
        { 0x8E, 0x39,0x0, 0xA0, 0xC9, 0x69,0x72, 0x3B } };
EFI_GUID gEfiSimplePointerProtocolGuid = {0x31878C87, 0xB75,0x11D5,
        { 0x9A, 0x4F,0x0, 0x90, 0x27, 0x3F,0xC1, 0x4D } };
EFI_GUID gEfiAbsolutePointerProtocolGuid = {0x8D59D32B, 0xC655,0x4AE9,
        { 0x9B, 0x15,0xF2, 0x59, 0x4, 0x99,0x2A, 0x43 } };
EFI_GUID gEfiSerialIoProtocolGuid = {0xBB25CF6F, 0xF1D4,0x11D2,
        { 0x9A, 0xC,0x0, 0x90, 0x27, 0x3F,0xC1, 0xFD } };
EFI_GUID gEfiEdidDiscoveredProtocolGuid = {0x1C0C34F6, 0xD380,0x41FA,
        { 0xA0, 0x49,0x8A, 0xD0, 0x6C, 0x1A,0x66, 0xAA } };
EFI_GUID gEfiEdidActiveProtocolGuid = {0xBD8C1056, 0x9F36,0x44EC,
        { 0x92, 0xA8,0xA6, 0x33, 0x7F, 0x81,0x79, 0x86 } };
EFI_GUID gEfiEdidOverrideProtocolGuid = {0x48ECB431, 0xFB72,0x45C0,
        { 0xA9, 0x22,0xF4, 0x58, 0xFE, 0x4,0xB, 0xD5 } };
EFI_GUID gEfiLoadFileProtocolGuid = {0x56EC3091, 0x954C,0x11D2,
        { 0x8E, 0x3F,0x0, 0xA0, 0xC9, 0x69,0x72, 0x3B } };
EFI_GUID gEfiLoadFile2ProtocolGuid = {0x4006C0C1, 0xFCB3,0x403E,
        { 0x99, 0x6D,0x4A, 0x6C, 0x87, 0x24,0xE0, 0x6D } };
EFI_GUID gEfiTapeIoProtocolGuid = {0x1E93E633, 0xD65A,0x459E,
        { 0xAB, 0x84,0x93, 0xD9, 0xEC, 0x26,0x6D, 0x18 } };
EFI_GUID gEfiDiskIoProtocolGuid = {0xCE345171, 0xBA0B,0x11D2,
        { 0x8E, 0x4F,0x0, 0xA0, 0xC9, 0x69,0x72, 0x3B } };
EFI_GUID gEfiBlockIoProtocolGuid = {0x964E5B21, 0x6459,0x11D2,
        { 0x8E, 0x39,0x0, 0xA0, 0xC9, 0x69,0x72, 0x3B } };
EFI_GUID gEfiUnicodeCollationProtocolGuid = {0x1D85CD7F, 0xF43D,0x11D2,
        { 0x9A, 0xC,0x0, 0x90, 0x27, 0x3F,0xC1, 0x4D } };
EFI_GUID gEfiPciRootBridgeIoProtocolGuid = {0x2F707EBB, 0x4A1A,0x11D4,
        { 0x9A, 0x38,0x0, 0x90, 0x27, 0x3F,0xC1, 0x4D } };
EFI_GUID gEfiPciIoProtocolGuid = {0x4CF5B200, 0x68B8,0x4CA5,
        { 0x9E, 0xEC,0xB2, 0x3E, 0x3F, 0x50,0x2, 0x9A } };
EFI_GUID gEfiScsiPassThruProtocolGuid = {0xA59E8FCF, 0xBDA0,0x43BB,
        { 0x90, 0xB1,0xD3, 0x73, 0x2E, 0xCA,0xA8, 0x77 } };
EFI_GUID gEfiScsiIoProtocolGuid = {0x932F47E6, 0x2362,0x4002,
        { 0x80, 0x3E,0x3C, 0xD5, 0x4B, 0x13,0x8F, 0x85 } };
EFI_GUID gEfiExtScsiPassThruProtocolGuid = {0x143B7632, 0xB81B,0x4CB7,
        { 0xAB, 0xD3,0xB6, 0x25, 0xA5, 0xB9,0xBF, 0xFE } };
EFI_GUID gEfiIScsiInitiatorNameProtocolGuid = {0x59324945, 0xEC44,0x4C0D,
        { 0xB1, 0xCD,0x9D, 0xB1, 0x39, 0xDF,0x7, 0xC } };
EFI_GUID gEfiUsbIoProtocolGuid = {0x2B2F68D6, 0xCD2,0x44CF,
        { 0x8E, 0x8B,0xBB, 0xA2, 0xB, 0x1B,0x5B, 0x75 } };
EFI_GUID gEfiUsbHcProtocolGuid = {0xF5089266, 0x1AA0,0x4953,
        { 0x97, 0xD8,0x56, 0x2F, 0x8A, 0x73,0xB5, 0x19 } };
EFI_GUID gEfiUsb2HcProtocolGuid = {0x3E745226, 0x9818,0x45B6,
        { 0xA2, 0xAC,0xD7, 0xCD, 0xE, 0x8B,0xA2, 0xBC } };
EFI_GUID gEfiDebugSupportProtocolGuid = {0x2755590C, 0x6F3C,0x42FA,
        { 0x9E, 0xA4,0xA3, 0xBA, 0x54, 0x3C,0xDA, 0x25 } };
EFI_GUID gEfiDebugPortProtocolGuid = {0xEBA4E8D2, 0x3858,0x41EC,
        { 0xA2, 0x81,0x26, 0x47, 0xBA, 0x96,0x60, 0xD0 } };
EFI_GUID gEfiDecompressProtocolGuid = {0xD8117CFE, 0x94A6,0x11D4,
        { 0x9A, 0x3A,0x0, 0x90, 0x27, 0x3F,0xC1, 0x4D } };
EFI_GUID gEfiAcpiTableProtocolGuid = {0xFFE06BDD, 0x6107,0x46A6,
        { 0x7B, 0xB2,0x5A, 0x9C, 0x7E, 0xC5,0x27, 0x5C } };
EFI_GUID gEfiEbcProtocolGuid = {0x13AC6DD1, 0x73D0,0x11D4,
        { 0xB0, 0x6B,0x0, 0xAA, 0x0, 0xBD,0x6D, 0xE7 } };
EFI_GUID gEfiSimpleNetworkProtocolGuid = {0xA19832B9, 0xAC25,0x11D3,
        { 0x9A, 0x2D,0x0, 0x90, 0x27, 0x3F,0xC1, 0x4D } };
EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid = {0xE18541CD, 0xF755,0x4F73,
        { 0x92, 0x8D,0x64, 0x3C, 0x8A, 0x79,0xB2, 0x29 } };
EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid_31 = {0x1ACED566, 0x76ED,0x4218,
        { 0xBC, 0x81,0x76, 0x7F, 0x1F, 0x97,0x7A, 0x89 } };
EFI_GUID gEfiPxeBaseCodeProtocolGuid = {0x3C4E603, 0xAC28,0x11D3,
        { 0x9A, 0x2D,0x0, 0x90, 0x27, 0x3F,0xC1, 0x4D } };
EFI_GUID gEfiPxeBaseCodeCallbackProtocolGuid = {0x245DCA21, 0xFB7B,0x11D3,
        { 0x8F, 0x1,0x0, 0xA0, 0xC9, 0x69,0x72, 0x3B } };
EFI_GUID gEfiBisProtocolGuid = {0xB64AAB0, 0x5429,0x11D4,
        { 0x98, 0x16,0x0, 0xA0, 0xC9, 0x1F,0xAD, 0xCF } };
EFI_GUID gEfiManagedNetworkServiceBindingProtocolGuid = {0xF36FF770, 0xA7E1,0x42CF,
        { 0x9E, 0xD2,0x56, 0xF0, 0xF2, 0x71,0xF4, 0x4C } };
EFI_GUID gEfiManagedNetworkProtocolGuid = {0x7AB33A91, 0xACE5,0x4326,
        { 0xB5, 0x72,0xE7, 0xEE, 0x33, 0xD3,0x9F, 0x16 } };
EFI_GUID gEfiArpServiceBindingProtocolGuid = {0xF44C00EE, 0x1F2C,0x4A00,
        { 0xAA, 0x9,0x1C, 0x9F, 0x3E, 0x8,0x0, 0xA3 } };
EFI_GUID gEfiArpProtocolGuid = {0xF4B427BB, 0xBA21,0x4F16,
        { 0xBC, 0x4E,0x43, 0xE4, 0x16, 0xAB,0x61, 0x9C } };
EFI_GUID gEfiDhcp4ServiceBindingProtocolGuid = {0x9D9A39D8, 0xBD42,0x4A73,
        { 0xA4, 0xD5,0x8E, 0xE9, 0x4B, 0xE1,0x13, 0x80 } };
EFI_GUID gEfiDhcp4ProtocolGuid = {0x8A219718, 0x4EF5,0x4761,
        { 0x91, 0xC8,0xC0, 0xF0, 0x4B, 0xDA,0x9E, 0x56 } };
EFI_GUID gEfiTcp4ServiceBindingProtocolGuid = {0x720665, 0x67EB,0x4A99,
        { 0xBA, 0xF7,0xD3, 0xC3, 0x3A, 0x1C,0x7C, 0xC9 } };
EFI_GUID gEfiTcp4ProtocolGuid = {0x65530BC7, 0xA359,0x410F,
        { 0xB0, 0x10,0x5A, 0xAD, 0xC7, 0xEC,0x2B, 0x62 } };
EFI_GUID gEfiIp4ServiceBindingProtocolGuid = {0xC51711E7, 0xB4BF,0x404A,
        { 0xBF, 0xB8,0xA, 0x4, 0x8E, 0xF1,0xFF, 0xE4 } };
EFI_GUID gEfiIp4ProtocolGuid = {0x41D94CD2, 0x35B6,0x455A,
        { 0x82, 0x58,0xD4, 0xE5, 0x13, 0x34,0xAA, 0xDD } };
EFI_GUID gEfiIp4ConfigProtocolGuid = {0x3B95AA31, 0x3793,0x434B,
        { 0x86, 0x67,0xC8, 0x7, 0x8, 0x92,0xE0, 0x5E } };
EFI_GUID gEfiIp4Config2ProtocolGuid = {0x5B446ED1, 0xE30B,0x4FAA,
        { 0x87, 0x1A,0x36, 0x54, 0xEC, 0xA3,0x60, 0x80 } };
EFI_GUID gEfiUdp4ServiceBindingProtocolGuid = {0x83F01464, 0x99BD,0x45E5,
        { 0xB3, 0x83,0xAF, 0x63, 0x5, 0xD8,0xE9, 0xE6 } };
EFI_GUID gEfiUdp4ProtocolGuid = {0x3AD9DF29, 0x4501,0x478D,
        { 0xB1, 0xF8,0x7F, 0x7F, 0xE7, 0xE,0x50, 0xF3 } };
EFI_GUID gEfiMtftp4ServiceBindingProtocolGuid = {0x2FE800BE, 0x8F01,0x4AA6,
        { 0x94, 0x6B,0xD7, 0x13, 0x88, 0xE1,0x83, 0x3F } };
EFI_GUID gEfiMtftp4ProtocolGuid = {0x78247C57, 0x63DB,0x4708,
        { 0x99, 0xC2,0xA8, 0xB4, 0xA9, 0xA6,0x1F, 0x6B } };
EFI_GUID gEfiAuthenticationInfoProtocolGuid = {0x7671D9D0, 0x53DB,0x4173,
        { 0xAA, 0x69,0x23, 0x27, 0xF2, 0x1F,0xB, 0xC7 } };
EFI_GUID gEfiHashServiceBindingProtocolGuid = {0x42881C98, 0xA4F3,0x44B0,
        { 0xA3, 0x9D,0xDF, 0xA1, 0x86, 0x67,0xD8, 0xCD } };
EFI_GUID gEfiHashProtocolGuid = {0xC5184932, 0xDBA5,0x46DB,
        { 0xA5, 0xBA,0xCC, 0xB, 0xDA, 0x9C,0x14, 0x35 } };
EFI_GUID gEfiHiiFontProtocolGuid = {0xE9CA4775, 0x8657,0x47FC,
        { 0x97, 0xE7,0x7E, 0xD6, 0x5A, 0x8,0x43, 0x24 } };
EFI_GUID gEfiHiiStringProtocolGuid = {0xFD96974, 0x23AA,0x4CDC,
        { 0xB9, 0xCB,0x98, 0xD1, 0x77, 0x50,0x32, 0x2A } };
EFI_GUID gEfiHiiImageProtocolGuid = {0x31A6406A, 0x6BDF,0x4E46,
        { 0xB2, 0xA2,0xEB, 0xAA, 0x89, 0xC4,0x9, 0x20 } };
EFI_GUID gEfiHiiConfigRoutingProtocolGuid = {0x587E72D7, 0xCC50,0x4F79,
        { 0x82, 0x9,0xCA, 0x29, 0x1F, 0xC1,0xA1, 0xF } };
EFI_GUID gEfiHiiConfigAccessProtocolGuid = {0x330D4706, 0xF2A0,0x4E4F,
        { 0xA3, 0x69,0xB6, 0x6F, 0xA8, 0xD5,0x43, 0x85 } };
EFI_GUID gEfiFormBrowser2ProtocolGuid = {0xB9D4C360, 0xBCFB,0x4F9B,
        { 0x92, 0x98,0x53, 0xC1, 0x36, 0x98,0x22, 0x58 } };
EFI_GUID gEfiDeviceIoProtocolGuid = {0xAF6AC311, 0x84C3,0x11D2,
        { 0x8E, 0x3C,0x0, 0xA0, 0xC9, 0x69,0x72, 0x3B } };
EFI_GUID gEfiUgaDrawProtocolGuid = {0x982C298B, 0xF4FA,0x41CB,
        { 0xB8, 0x38,0x77, 0xAA, 0x68, 0x8F,0xB8, 0x39 } };
EFI_GUID gEfiUgaIoProtocolGuid = {0x61A4D49E, 0x6F68,0x4F1B,
        { 0xB9, 0x22,0xA8, 0x6E, 0xED, 0xB,0x7, 0xA2 } };
EFI_GUID gEfiDriverConfigurationProtocolGuid = {0x107A772B, 0xD5E1,0x11D4,
        { 0x9A, 0x46,0x0, 0x90, 0x27, 0x3F,0xC1, 0x4D } };
EFI_GUID gEfiDriverConfiguration2ProtocolGuid = {0xBFD7DC1D, 0x24F1,0x40D9,
        { 0x82, 0xE7,0x2E, 0x9, 0xBB, 0x6B,0x4E, 0xBE } };
EFI_GUID gEfiSimpleTextInputExProtocolGuid = {0xDD9E7534, 0x7762,0x4698,
        { 0x8C, 0x14,0xF5, 0x85, 0x17, 0xA6,0x25, 0xAA } };
EFI_GUID gEfiIp6ServiceBindingProtocolGuid = {0xEC835DD3, 0xFE0F,0x617B,
        { 0xA6, 0x21,0xB3, 0x50, 0xC3, 0xE1,0x33, 0x88 } };
EFI_GUID gEfiIp6ProtocolGuid = {0x2C8759D5, 0x5C2D,0x66EF,
        { 0x92, 0x5F,0xB6, 0x6C, 0x10, 0x19,0x57, 0xE2 } };
EFI_GUID gEfiIp6ConfigProtocolGuid = {0x937FE521, 0x95AE,0x4D1A,
        { 0x89, 0x29,0x48, 0xBC, 0xD9, 0xA,0xD3, 0x1A } };
EFI_GUID gEfiMtftp6ServiceBindingProtocolGuid = {0xD9760FF3, 0x3CCA,0x4267,
        { 0x80, 0xF9,0x75, 0x27, 0xFA, 0xFA,0x42, 0x23 } };
EFI_GUID gEfiMtftp6ProtocolGuid = {0xBF0A78BA, 0xEC29,0x49CF,
        { 0xA1, 0xC9,0x7A, 0xE5, 0x4E, 0xAB,0x6A, 0x51 } };
EFI_GUID gEfiDhcp6ServiceBindingProtocolGuid = {0x9FB9A8A1, 0x2F4A,0x43A6,
        { 0x88, 0x9C,0xD0, 0xF7, 0xB6, 0xC4,0x7A, 0xD5 } };
EFI_GUID gEfiDhcp6ProtocolGuid = {0x87C8BAD7, 0x595,0x4053,
        { 0x82, 0x97,0xDE, 0xDE, 0x39, 0x5F,0x5D, 0x5B } };
EFI_GUID gEfiUdp6ServiceBindingProtocolGuid = {0x66ED4721, 0x3C98,0x4D3E,
        { 0x81, 0xE3,0xD0, 0x3D, 0xD3, 0x9A,0x72, 0x54 } };
EFI_GUID gEfiUdp6ProtocolGuid = {0x4F948815, 0xB4B9,0x43CB,
        { 0x8A, 0x33,0x90, 0xE0, 0x60, 0xB3,0x49, 0x55 } };
EFI_GUID gEfiTcp6ServiceBindingProtocolGuid = {0xEC20EB79, 0x6C1A,0x4664,
        { 0x9A, 0xD,0xD2, 0xE4, 0xCC, 0x16,0xD6, 0x64 } };
EFI_GUID gEfiTcp6ProtocolGuid = {0x46E44855, 0xBD60,0x4AB7,
        { 0xAB, 0xD,0xA6, 0x79, 0xB9, 0x44,0x7D, 0x77 } };
EFI_GUID gEfiVlanConfigProtocolGuid = {0x9E23D768, 0xD2F3,0x4366,
        { 0x9F, 0xC3,0x3A, 0x7A, 0xBA, 0x86,0x43, 0x74 } };
EFI_GUID gEfiEapProtocolGuid = {0x5D9F96DB, 0xE731,0x4CAA,
        { 0xA0, 0xD,0x72, 0xE1, 0x87, 0xCD,0x77, 0x62 } };
EFI_GUID gEfiEapManagementProtocolGuid = {0xBB62E663, 0x625D,0x40B2,
        { 0xA0, 0x88,0xBB, 0xE8, 0x36, 0x23,0xA2, 0x45 } };
EFI_GUID gEfiFtp4ServiceBindingProtocolGuid = {0xFAAECB1, 0x226E,0x4782,
        { 0xAA, 0xCE,0x7D, 0xB9, 0xBC, 0xBF,0x4D, 0xAF } };
EFI_GUID gEfiFtp4ProtocolGuid = {0xEB338826, 0x681B,0x4295,
        { 0xB3, 0x56,0x2B, 0x36, 0x4C, 0x75,0x7B, 0x9 } };
EFI_GUID gEfiIpSecConfigProtocolGuid = {0xCE5E5929, 0xC7A3,0x4602,
        { 0xAD, 0x9E,0xC9, 0xDA, 0xF9, 0x4E,0xBF, 0xCF } };
EFI_GUID gEfiDriverHealthProtocolGuid = {0x2A534210, 0x9280,0x41D8,
        { 0xAE, 0x79,0xCA, 0xDA, 0x1, 0xA2,0xB1, 0x27 } };
EFI_GUID gEfiDeferredImageLoadProtocolGuid = {0x15853D7C, 0x3DDF,0x43E0,
        { 0xA1, 0xCB,0xEB, 0xF8, 0x5B, 0x8F,0x87, 0x2C } };
EFI_GUID gEfiUserCredentialProtocolGuid = {0x71EE5E94, 0x65B9,0x45D5,
        { 0x82, 0x1A,0x3A, 0x4D, 0x86, 0xCF,0xE6, 0xBE } };
EFI_GUID gEfiUserManagerProtocolGuid = {0x6FD5B00C, 0xD426,0x4283,
        { 0x98, 0x87,0x6C, 0xF5, 0xCF, 0x1C,0xB1, 0xFE } };
EFI_GUID gEfiAtaPassThruProtocolGuid = {0x1D3DE7F0, 0x807,0x424F,
        { 0xAA, 0x69,0x11, 0xA5, 0x4E, 0x19,0xA4, 0x6F } };
EFI_GUID gEfiFirmwareManagementProtocolGuid = {0x86C77A67, 0xB97,0x4633,
        { 0xA1, 0x87,0x49, 0x10, 0x4D, 0x6,0x85, 0xC7 } };
EFI_GUID gEfiIpSecProtocolGuid = {0xDFB386F7, 0xE100,0x43AD,
        { 0x9C, 0x9A,0xED, 0x90, 0xD0, 0x8A,0x5E, 0x12 } };
EFI_GUID gEfiIpSec2ProtocolGuid = {0xA3979E64, 0xACE8,0x4DDC,
        { 0xBC, 0x7,0x4D, 0x66, 0xB8, 0xFD,0x9, 0x77 } };
EFI_GUID gEfiKmsProtocolGuid = {0xEC3A978D, 0x7C4E,0x48FA,
        { 0x9A, 0xBE,0x6A, 0xD9, 0x1C, 0xC8,0xF8, 0x11 } };
EFI_GUID gEfiBlockIo2ProtocolGuid = {0xA77B2472, 0xE282,0x4E9F,
        { 0xA2, 0x45,0xC2, 0xC0, 0xE2, 0x7B,0xBC, 0xC1 } };
EFI_GUID gEfiStorageSecurityCommandProtocolGuid = {0xC88B0B6D, 0xDFC,0x49A7,
        { 0x9C, 0xB4,0x49, 0x7, 0x4B, 0x4C,0x3A, 0x78 } };
EFI_GUID gEfiUserCredential2ProtocolGuid = {0xE98ADB03, 0xB8B9,0x4AF8,
        { 0xBA, 0x20,0x26, 0xE9, 0x11, 0x4C,0xBC, 0xE5 } };
EFI_GUID gPcdProtocolGuid = {0x11B34006, 0xD85B,0x4D0A,
        { 0xA2, 0x90,0xD5, 0xA5, 0x71, 0x31,0xE, 0xF7 } };
EFI_GUID gEfiTcgProtocolGuid = {0xF541796D, 0xA62E,0x4954,
        { 0xA7, 0x75,0x95, 0x84, 0xF6, 0x1B,0x9C, 0xDD } };
EFI_GUID gEfiHiiPackageListProtocolGuid = {0x6A1EE763, 0xD47A,0x43B4,
        { 0xAA, 0xBE,0xEF, 0x1D, 0xE2, 0xAB,0x56, 0xFC } };
EFI_GUID gEfiDriverFamilyOverrideProtocolGuid = {0xB1EE129E, 0xDA36,0x4181,
        { 0x91, 0xF8,0x4, 0xA4, 0x92, 0x37,0x66, 0xA7 } };
EFI_GUID gEfiIdeControllerInitProtocolGuid = {0xA1E37052, 0x80D9,0x4E65,
        { 0xA3, 0x17,0x3E, 0x9A, 0x55, 0xC4,0x3E, 0xC9 } };
EFI_GUID gEfiDiskIo2ProtocolGuid = {0x151C8EAE, 0x7F2C,0x472C,
        { 0x9E, 0x54,0x98, 0x28, 0x19, 0x4F,0x6A, 0x88 } };
EFI_GUID gEfiAdapterInformationProtocolGuid = {0xE5DD1403, 0xD622,0xC24E,
        { 0x84, 0x88,0xC7, 0x1B, 0x17, 0xF5,0xE8, 0x2 } };
EFI_GUID gEfiShellDynamicCommandProtocolGuid = {0x3C7200E9, 0x5F,0x4EA4,
        { 0x87, 0xDE,0xA3, 0xDF, 0xAC, 0x8A,0x27, 0xC3 } };
EFI_GUID gEfiDiskInfoProtocolGuid = {0xD432A67F, 0x14DC,0x484B,
        { 0xB3, 0xBB,0x3F, 0x2, 0x91, 0x84,0x93, 0x27 } };

 

Step to UEFI (107)取得USB DISK 的序列号

继续前面的话题,这次研究如何取得一个USB DISK的信息。最先想到的还是使用 DISK INFO PROTOCOL,不过到了实际编写代码的时候发现:我根本不知道返回值是什么格式。在代码中搜索了几次 gEfiDiskInfoUsbInterfaceGuid 发现无人使用。之后为了弄清楚格式,直接创建了一个256bytes大小的内存,还是用 identify 来获得返回值,最后发现:返回值是空的。因此,也就是说虽然 USB DISK上有安装这个 protocol,但是根本就是一个空的而已。
再调整思路,首先用 DISK INFO PROTOCOL取得USB DISK 的 Handle ,然后,在这个Handle上打开 USBIO,EFI_USB_IO_PROTOCOL.UsbGetStringDescriptor 可以用来取得描述符中相关的字符串【参考1】,具体结构可以在 \EdkCompatibilityPkg\Foundation\Include\IndustryStandard\usb.h 找到:

typedef struct {
  UINT8           Length;
  UINT8           DescriptorType;
  UINT16          BcdUSB;
  UINT8           DeviceClass;
  UINT8           DeviceSubClass;
  UINT8           DeviceProtocol;
  UINT8           MaxPacketSize0;
  UINT16          IdVendor;
  UINT16          IdProduct;
  UINT16          BcdDevice;
  UINT8           StrManufacturer;
  UINT8           StrProduct;
  UINT8           StrSerialNumber;
  UINT8           NumConfigurations;
} EFI_USB_DEVICE_DESCRIPTOR;

 

最后,用这个 函数来取得需要的字符串。

完整的代码:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Protocol/DiskInfo.h>
#include  <Library/BaseMemoryLib.h>
#include  <Protocol/IdeControllerInit.h>
#include <Library/MemoryAllocationLib.h>
#include  <Protocol/UsbIo.h>

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_HANDLE				 gImageHandle;

EFI_GUID gEfiDiskInfoProtocolGuid = { 0xD432A67F, 0x14DC, 0x484B, 
					{ 0xB3, 0xBB, 0x3F, 0x02, 0x91, 0x84, 0x93, 0x27 }};
EFI_GUID gEfiDiskInfoUsbInterfaceGuid   = { 0xCB871572, 0xC11A, 0x47B5, 
					{ 0xB4, 0x92, 0x67, 0x5E, 0xAF, 0xA7, 0x77, 0x27 }};

EFI_GUID  gEfiUsbIoProtocolGuid   = { 0x2B2F68D6, 0x0CD2, 0x44CF, 
					{ 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75 }};					

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
    EFI_STATUS 	Status;
    UINTN 		HandleIndex, NumHandles;
    EFI_HANDLE 	*ControllerHandle = NULL;
	EFI_DISK_INFO_PROTOCOL	*DiskInfoProtocol;	
	EFI_USB_IO_PROTOCOL 			*USBIO;
	EFI_USB_DEVICE_DESCRIPTOR     DeviceDescriptor;
	CHAR16                       *Manufacturer;
	CHAR16                       *Product;
	CHAR16                       *SerialNumber;
	
    Status = gBS->LocateHandleBuffer(
            ByProtocol,
            &gEfiDiskInfoProtocolGuid,
            NULL,
            &NumHandles,
            &ControllerHandle);
	
    for (HandleIndex = 0; HandleIndex < NumHandles; HandleIndex++) {
        Status = gBS->OpenProtocol(
                ControllerHandle[HandleIndex],
                &gEfiDiskInfoProtocolGuid, 
                (VOID**)&DiskInfoProtocol,
                gImageHandle,
                NULL,
                EFI_OPEN_PROTOCOL_GET_PROTOCOL
                );		
        if (EFI_ERROR(Status)) {
            continue;
        } 

		//We only deal with USB
		if (!(CompareGuid (
				&DiskInfoProtocol->Interface, 
				&gEfiDiskInfoUsbInterfaceGuid))) {	
				continue;
			}	
			
        Status = gBS->OpenProtocol(
                ControllerHandle[HandleIndex],
                &gEfiUsbIoProtocolGuid, 
                (VOID**)&USBIO,
                gImageHandle,
                NULL,
                EFI_OPEN_PROTOCOL_GET_PROTOCOL
                );		
        if (EFI_ERROR(Status)) {
			Print(L"ERROR : Open USBIO fail.\n");
            continue;
        } 
		
		Status = USBIO->UsbGetDeviceDescriptor
							(USBIO, &DeviceDescriptor);     
		if (EFI_ERROR(Status))
		{
			Print(L"ERROR : Get Device Descriptor fail.\n");
			return 0;
		}		
		
		Print(L"VendorID = %04X\nProductID = %04X\n", 
                              DeviceDescriptor.IdVendor, 
                              DeviceDescriptor.IdProduct);  

		Status = USBIO->UsbGetStringDescriptor (
                    USBIO,
                    0x0409, 			// English
                    DeviceDescriptor.StrManufacturer,
                    &Manufacturer
                    );
		if (EFI_ERROR (Status)) {
				Manufacturer = L"";
		}

		Status = USBIO->UsbGetStringDescriptor (
                    USBIO,
                    0x0409, 			// English
                    DeviceDescriptor.StrProduct,
                    &Product
                    );
		if (EFI_ERROR (Status)) {
				Product = L"";	}
				
				
		Status = USBIO->UsbGetStringDescriptor (
                    USBIO,
                    0x0409, 			// English
                    DeviceDescriptor.StrSerialNumber,
                    &SerialNumber
                    );
		if (EFI_ERROR (Status)) {
				SerialNumber = L"";}
		
		Print(L"     Manufacturer :  %s\n",Manufacturer);
		Print(L"     Product      :  %s\n",Product);
		Print(L"     Serial Number:  %s\n",SerialNumber);		
						  
							  
	}
  return EFI_SUCCESS;
}

 

运行结果:
ditu1

完整的代码和程序下载:
diskinfousb

另外,还可以直接枚举 USBIO 然后检查对应的 Class发现是USB MASS Storage 即是U盘,然后再重复上面取得字符串信息的动作。

参考:
1. UEFI Spec 2.4 P835 EFI_USB_IO_PROTOCOL.UsbGetStringDescriptor()

DFRobot SIM808 模块评测 GPS

人类对于世界的了解的越多,能够掌握的工具和方法就越多。

曾经读过方舟子写的《相对论有没有用?》【参考1】,让我大吃一惊的是日常用到的GPS就是相对论使用的典型:

“GPS是靠美国空军发射的24颗GPS卫星来定位的(此外还有几颗备用卫星),每颗卫星上都携带着原子钟,它们计时极为准确,误差不超过十万亿分之一,即每天的误差不超过10纳秒(1纳秒等于10亿分之一秒),并不停地发射无线电信号报告时间和轨道位置。这些GPS卫星在空中的位置是精心安排好的,任何时候在地球上的任何地点至少都能见到其中的4颗。GPS导航仪通过比较从4颗GPS卫星发射来的时间信号的差异,计算出所在的位置。

GPS卫星以每小时14000千米的速度绕地球飞行。根据狭义相对论,当物体运动时,时间会变慢,运动速度越快,时间就越慢。因此在地球上看GPS卫星,它们携带的时钟要走得比较慢,用狭义相对论的公式可以计算出,每天慢大约7微秒。

GPS卫星位于距离地面大约2万千米的太空中。根据广义相对论,物质质量的存在会造成时空的弯曲,质量越大,距离越近,就弯曲得越厉害,时间则会越慢。受地球质量的影响,在地球表面的时空要比GPS卫星所在的时空更加弯曲,这样,从地球上看,GPS卫星上的时钟就要走得比较快,用广义相对论的公式可以计算出,每天快大约45微秒。

在同时考虑了狭义相对论和广义相对论后,GPS卫星时钟每天还要快上大约38微秒,这似乎微不足道,但是如果我们考虑到GPS系统必须达到的时间精度是纳秒级的,这个误差就非常可观了(38微秒等于38000纳秒)。如果不校正的话,GPS系统每天将会累积大约10千米的定位误差,是没有用的。为此,在GPS卫星发射前,要先把其时钟的走动频率调慢100亿分之4.465,把10.23兆赫调为10.22999999543兆赫。此外,GPS卫星的运行轨道并非完美的圆形,与地面的距离和运行速度会有所变化,如果轨道偏心率为0.02,时间就会有46纳秒的误差。由于地球的自转,GPS导航仪在地球表面上的位移也会产生误差,例如当GPS导航仪在赤道上,而GPS卫星在地平线上时,由于位移产生的误差将会达到133纳秒。GPS导航仪在定位时还必须根据相对论进行计算纠正这些误差。

我手中的 DFRobot的SIM808 Shield支持GPS功能,这次我们就实验一下这个功能,GPS取得当前的时间和经纬度之后,结果显示在1602液晶上。使用到的硬件包括:

1. Arduino Uno 1块

2. DFRobot 的SIM808 Shield 1块

3. 18650 电池组 2块

4. 1602 LCD 一块

5. 亚克力切割的外壳 一对

特别注意的是,必须使用外接电源,USB端口供电不足以驱动模块,特别注意:一定要接上 GPS 天线,否则无法收到信号。

硬件准备妥当之后,先实验直接发送 AT 命令,这个实验不需要SIM卡:

1. 板上开关放置于3号位置

2. 下载 blink 程序(需要不占用 的程序)

3. 外接电源(我用的是2节18650,目前有7.5v左右)

4. 板上开关放置于2号位置

5. 用IDE自带的串口工具,输入 AT 可以看到自动回复 OK,这说明模块本身是正常的

6. 输入AT+CGNSPWR=1命令(打开GPS电源)AT+CGNSTST=1命令(开始从串口接收GPS数据)

7. 下面就可以看到获得的GPS数据了
image001

8. 结束的时候,使用AT+CGNSPWR=0命令关断GPS电源。

image002

我们在地图上看一下这个位置,很准

image003
软件方面需要下载DFRobot_SIM808的库,在https://github.com/DFRobot/DFRobot_SIM808。本文末尾提供了打包好的库文件。可以使用 Sketch->Include library->Add .zip library直接添加。

代码如下:

#include <LiquidCrystal_I2C.h>

#include <DFRobot_sim808.h>

 

DFRobot_SIM808 sim808(&Serial);

 

// Set the LCD address to 0x3F for a 16 chars and 2 line display

LiquidCrystal_I2C lcd(0x3f, 16, 2);

 

void setup() {

    Serial.begin(9600);

 

    // initialize the LCD

    lcd.begin();

 

    // Turn on the blacklight and print a message.

    lcd.backlight();

  

    //************* Turn on the GPS power************

    if( sim808.attachGPS())

      {

        Serial.println("Open the GPS power success");

        lcd.print("power success");

      }

    else

      {    

        Serial.println("Open the GPS power failure");

        lcd.print("power failure");        

      }

}

 

void loop() {

     char s[20];    

     //************** Get GPS data *******************

     if (sim808.getGPS()) {

      Serial.print(sim808.GPSdata.hour);

      Serial.print(":");

      Serial.print(sim808.GPSdata.minute);

      Serial.print(":");

      Serial.println(sim808.GPSdata.second);

      Serial.print("latitude :");

      Serial.println(sim808.GPSdata.lat);

      Serial.print("longitude :");

      Serial.println(sim808.GPSdata.lon);

 

      lcd.clear(); 

      lcd.print("GPS     bbdebbbbbbbhhh             b        "); 

      lcd.print(sim808.GPSdata.hour);  

      lcd.print(":"); 

      lcd.print(sim808.GPSdata.minute);  

      lcd.print(":"); 

      lcd.print(sim808.GPSdata.second);

      

 

      lcd.setCursor(0,1);

      lcd.print("(");

      dtostrf(sim808.GPSdata.lat,3,2,s);

      lcd.print(s);

      lcd.print(",");

      dtostrf(sim808.GPSdata.lon,3,2,s);

      lcd.print(s);

      lcd.print(")");

 

      //************* Turn off the GPS power ************

      sim808.detachGPS();

    }

 

  }

 

最终运行结果:

image004

image005

最后说点关于GPS 好玩的事情:

第一件事情:我在昆山打工的时候,有一天瞎溜达,走到一座大桥下,看到上面铭牌上刻着经纬度。那是很久以前的事情,久远到 google还没有被封,手机还没有 GPS 功能。我很好奇的记下了经纬度。回去宿舍在google map上查找这个经纬度,非常疑惑的看着坐标飞到了太平洋中。朱多年来心中疑惑一直没有解开:这样的标注是为了“乱了敌人锻炼了群众”吗?

第二件事情: 1983年9月1日清晨(UTC时间为8月31日傍晚),大韩航空007号班机进入苏联领空,遭苏联空军Su-15拦截机击落于库页岛西南方的公海。误入的原因是机长操作失误,没有切换到正确的导航模式【参考2】。这件事情之后美国宣布开放部份的GPS功能给民间使用。

参考:

1. http://view.news.qq.com/a/20090422/000029.htm 方舟子:相对论有没有用?

借用臧克家的一句话来描述方舟子“有的人死了,他还活着;有的人或者,他已经敏感字了”。

2. http://baike.baidu.com/item/%E5%A4%A7%E9%9F%A9%E8%88%AA%E7%A9%BA007%E5%8F%B7%E7%8F%AD%E6%9C%BA%E7%A9%BA%E9%9A%BE 大韩航空007号班机空难

如果非说苏联伟大的话,那么伟大的原因一定是它一次次将人类从自己的魔爪下解救出来。

Step to UEFI (106)取得AHCI SATA 的序列号

继续前面的话题,现在尝试直接输出AHCI HDD 的信息。资料上标明AHCI和IDE HDD输出的信息格式是相同的,所以这里会一同处理。

原理上:找到 DISK INFO PROTOCOL 后,判断 GUID 是否为 IDE和 AHCI 的,如果是,那么用Identify 来取得型号信息。返回构体EFI_ATAPI_IDENTIFY_DATA,具体定义在下面这个文件中:

\EdkCompatibilityPkg\Foundation\Framework\Protocol\IdeControllerInit\IdeControllerInit.h 中。

typedef struct {
    UINT16  config;             // General Configuration
    UINT16  obsolete_1;
    UINT16  specific_config;
    UINT16  obsolete_3;   
    UINT16  retired_4_5[2];
    UINT16  obsolete_6;   
    UINT16  cfa_reserved_7_8[2];
    UINT16  retired_9;
    CHAR8   SerialNo[20];       // ASCII 
    UINT16  retired_20_21[2];
    UINT16  obsolete_22;
    CHAR8   FirmwareVer[8];     // ASCII 
    CHAR8   ModelName[40];      // ASCII 
    UINT16  multi_sector_cmd_max_sct_cnt;
    UINT16  reserved_48;
    UINT16  capabilities_49;
    UINT16  capabilities_50;
    UINT16  obsolete_51_52[2];   
    UINT16  field_validity;
    UINT16  obsolete_54_58[5];
    UINT16  mutil_sector_setting;
    UINT16  user_addressable_sectors_lo;
    UINT16  user_addressable_sectors_hi;
    UINT16  obsolete_62;
    UINT16  multi_word_dma_mode;
    UINT16  advanced_pio_modes;
    UINT16  min_multi_word_dma_cycle_time;
    UINT16  rec_multi_word_dma_cycle_time;
    UINT16  min_pio_cycle_time_without_flow_control;
    UINT16  min_pio_cycle_time_with_flow_control;
    UINT16  reserved_69_74[6];
    UINT16  queue_depth;
    UINT16  reserved_76_79[4];
    UINT16  major_version_no;
    UINT16  minor_version_no;
    UINT16  cmd_set_support_82;
    UINT16  cmd_set_support_83;
    UINT16  cmd_feature_support;
    UINT16  cmd_feature_enable_85;
    UINT16  cmd_feature_enable_86;
    UINT16  cmd_feature_default;
    UINT16  ultra_dma_select;
    UINT16  time_required_for_sec_erase;
    UINT16  time_required_for_enhanced_sec_erase;
    UINT16  current_advanced_power_mgmt_value;
    UINT16  master_pwd_revison_code;
    UINT16  hardware_reset_result;
    UINT16  current_auto_acoustic_mgmt_value;
    UINT16  reserved_95_99[5];
    UINT16  max_user_lba_for_48bit_addr[4];
    UINT16  reserved_104_126[23];
    UINT16  removable_media_status_notification_support;
    UINT16  security_status;
    UINT16  vendor_data_129_159[31];
    UINT16  cfa_power_mode;
    UINT16  cfa_reserved_161_175[15];
    UINT16  current_media_serial_no[30];
    UINT16  reserved_206_254[49];
    UINT16  integrity_word;
} EFI_ATAPI_IDENTIFY_DATA;

 

代码如下:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Protocol/DiskInfo.h>
#include  <Library/BaseMemoryLib.h>
#include  <Protocol/IdeControllerInit.h>

extern EFI_BOOT_SERVICES         *gBS;

extern EFI_HANDLE				 gImageHandle;

EFI_GUID gEfiDiskInfoProtocolGuid = { 0xD432A67F, 0x14DC, 0x484B, 
					{ 0xB3, 0xBB, 0x3F, 0x02, 0x91, 0x84, 0x93, 0x27 }};
EFI_GUID gEfiDiskInfoAhciInterfaceGuid  = { 0x9e498932, 0x4abc, 0x45af, 
					{ 0xa3, 0x4d, 0x02, 0x47, 0x78, 0x7b, 0xe7, 0xc6 }};
EFI_GUID gEfiDiskInfoIdeInterfaceGuid   = { 0x5E948FE3, 0x26D3, 0x42B5, 
					{ 0xAF, 0x17, 0x61, 0x02, 0x87, 0x18, 0x8D, 0xEC }};

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
    EFI_STATUS Status;
    UINTN HandleIndex, NumHandles;
    EFI_HANDLE *ControllerHandle = NULL;
	EFI_DISK_INFO_PROTOCOL	*DiskInfoProtocol;
	UINT32                       BufferSize;	
    EFI_ATAPI_IDENTIFY_DATA      IdentifyData;	
	UINT32				i;
	
    Status = gBS->LocateHandleBuffer(
            ByProtocol,
            &gEfiDiskInfoProtocolGuid,
            NULL,
            &NumHandles,
            &ControllerHandle);
	
    for (HandleIndex = 0; HandleIndex < NumHandles; HandleIndex++) {
        Status = gBS->OpenProtocol(
                ControllerHandle[HandleIndex],
                &gEfiDiskInfoProtocolGuid, 
                (VOID**)&DiskInfoProtocol,
                gImageHandle,
                NULL,
                EFI_OPEN_PROTOCOL_GET_PROTOCOL
                );		
        if (EFI_ERROR(Status)) {
            continue;
        } 

		//We only deal with AHCI and IDE
		if (!(CompareGuid (
				&DiskInfoProtocol->Interface, 
				&gEfiDiskInfoAhciInterfaceGuid)||
			(CompareGuid (
				&DiskInfoProtocol->Interface,
			    &gEfiDiskInfoIdeInterfaceGuid)
			))) {	
				continue;
			}	

		BufferSize   = sizeof (EFI_ATAPI_IDENTIFY_DATA);
		Status = DiskInfoProtocol->Identify (
                         DiskInfoProtocol,
                         &IdentifyData,
                         &BufferSize
                         );			
		
		Print(L"Model Name :");
		for (i=0;i<40;i=i+2) {
			Print(L"%c%c",
				IdentifyData.ModelName[i+1],
				IdentifyData.ModelName[i]);
		}
		Print(L"\n");
	}

  return EFI_SUCCESS;
}

 

在 KabyLake HDK 板子上运行上述代码,结果如下:
ahci1

细心的朋友可能注意到,输出并不是直接输出序列号,而是有一个顺序上的调整:
Print(L”%c%c”, IdentifyData.ModelName[i+1], IdentifyData.ModelName[i]);
原因是,刚开始我试验的是直接顺序输出,但是发现结果是下面这样的:
ahci2

开始以为是 CHAR 对 CHAR16转换上的问题,后来查阅资料【参考1】,发现这里的行医比较特别。排列是 2/1/4/3/6/5……. 这样的:
ahci3

所以,修改代码手工做一次反转就可以了。
完整的代码下载:
diskinfoahci

参考:
1. http://www.t13.org/Documents/UploadedDocuments/docs2013/d2161r5-ATAATAPI_Command_Set_-_3.pdf

Windows常见开发包

https://msdn.microsoft.com/windows/hardware/commercialize/kits-and-tools-overview

Windows SDK for Windows 10 用来编写 Application的头文件库文件和工具 Windows SDK for Windows 10 contains headers, libraries, and tools you can use when you create apps that run on Windows operating systems.

WDK 10 用来编写Driver的头文件库文件和工具 WDK 10 contains the tools to build, test, debug, and deploy drivers for Windows 10.

Enterprise WDK (EWDK) 将上面2个放在一起的 The Enterprise WDK (EWDK) is a kit that large organizations can use as an alternative to downloading and installing the SDK and WDK individually on each computer.

Windows symbols 符号文件,用来调试 Windows的 Symbol files make it easier to debug your code.

Windows Hardware Lab Kit (HLK) for Windows 10 用来测试运行 Windows 设备的工具 Windows Hardware Lab Kit (HLK) for Windows 10

HLK supplemental test content 测试多媒体时可能需要的音频视频文件 Some tests, like graphics and multimedia tests, require additional files for testing.

ADK for Windows 10 (Windows Assessment and Deployment Kit) OEM和OEM用来制作安装镜像的工具
Download the Windows ADK to install tools and documentation for OEMs and ODMs to customize Windows 10 images, assess the quality and performance of systems or components, and to deploy Windows operating systems to new computers.

A device for UEFI Application testing

In the last posts, as the NT32 environment has too much limitations. We have to test my applications on the real system. I use a USB disk for these kinds of thing. After compiling, I have to copy my application to this disk. Then unplug and plug again to the testing system (I use Kabylake HDK now). After that I can test my application on the real system. If some bugs are found, I have to repeat this action. As you can see it’s really inconvenience.
For this purpose, I begin to study the “matrix switch IC” carefully. After all, I find that the common switching IC in the market could only support 300Mhz. While the USB 2.0 device requires 480Mhz. No one know what will happen if I make one. It’s not a good idea for me to DIY. At last, I begin to search the solution on Taobao.com. Soon, I find this one:

su

It has a mechanical switcher inside. And the most important thing: it’s very cheap. Only 7.8 Yuan (less than $2).
I buy one USB switcher and 2 USB cables (1.5m for 3Yuan).
The usage is that:
1st plug a USB disk in this switcher.
2nd Every time the complication is completed, copy the application to this USB Disk.
3rd Switch to the working PC and make your experiment in real system.

I have used this device for a period, it works well.

Step to UEFI (109)显示Shell 下面的历史信息

之前有网友询问过一个问题:他的程序调用了另外一个 Application,希望能够获得另外那个 Application的运行结果。最近,偶然看到了 Shell 下记录历史信息的功能,具体头文件在\ShellPkg\Application\Shell\ConsoleLogger.h 中有定义。

typedef struct _CONSOLE_LOGGER_PRIVATE_DATA{
  UINTN                             Signature;
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   OurConOut;        ///< the protocol we installed onto the system table
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *OldConOut;       ///< old protocol to reinstall upon exiting
  EFI_HANDLE                        OldConHandle;     ///< old protocol handle
  UINTN                             ScreenCount;      ///< How many screens worth of data to save
  CHAR16                            *Buffer;          ///< Buffer to save data
  UINTN                             BufferSize;       ///< size of buffer in bytes

                                                      //  start row is the top of the screen
  UINTN                             OriginalStartRow; ///< What the originally visible start row was
  UINTN                             CurrentStartRow;  ///< what the currently visible start row is

  UINTN                             RowsPerScreen;    ///< how many rows the screen can display
  UINTN                             ColsPerScreen;    ///< how many columns the screen can display

  INT32                             *Attributes;      ///< Buffer for Attribute to be saved for each character
  UINTN                             AttribSize;       ///< Size of Attributes in bytes

  EFI_SIMPLE_TEXT_OUTPUT_MODE       HistoryMode;      ///< mode of the history log
  BOOLEAN                           Enabled;          ///< Set to FALSE when a break is requested.
  UINTN                             RowCounter;       ///< Initial row of each print job.
} CONSOLE_LOGGER_PRIVATE_DATA;

 

这个功能实现的方法是,在 Shell 启动的时,将系统中的EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL 题材换成重新定义的,这样每次Application的输出都会被Shell截获存放在一个Buffer中,有需要的时候,再从 Buffer中取出(例如:使用 PageUp/PageDown 查看)。
对于我们来说,首先找到 Shell 的 Handle,之后枚举这个 Handle 上的全部protocol,找到SimpleTextOutProtocol,再根据找到的这个Protocol的偏移,反推算出CONSOLE_LOGGER_PRIVATE_DATA,最后就能访问到我们需要的CONSOLE_LOGGER_PRIVATE_DATA->buffer了。
代码如下,为了简单明了,我只显示Buffer最前面4行

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

extern EFI_HANDLE				 gImageHandle;

#define CR(Record, TYPE, Field, TestSignature)                                              \
    BASE_CR (Record, TYPE, Field)
	
typedef struct _CONSOLE_LOGGER_PRIVATE_DATA{
  UINTN                             Signature;
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   OurConOut;        ///< the protocol we installed onto the system table
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *OldConOut;       ///< old protocol to reinstall upon exiting
  EFI_HANDLE                        OldConHandle;     ///< old protocol handle
  UINTN                             ScreenCount;      ///< How many screens worth of data to save
  CHAR16                            *Buffer;          ///< Buffer to save data
  UINTN                             BufferSize;       ///< size of buffer in bytes

                                                      //  start row is the top of the screen
  UINTN                             OriginalStartRow; ///< What the originally visible start row was
  UINTN                             CurrentStartRow;  ///< what the currently visible start row is

  UINTN                             RowsPerScreen;    ///< how many rows the screen can display
  UINTN                             ColsPerScreen;    ///< how many columns the screen can display

  INT32                             *Attributes;      ///< Buffer for Attribute to be saved for each character
  UINTN                             AttribSize;       ///< Size of Attributes in bytes

  EFI_SIMPLE_TEXT_OUTPUT_MODE       HistoryMode;      ///< mode of the history log
  BOOLEAN                           Enabled;          ///< Set to FALSE when a break is requested.
  UINTN                             RowCounter;       ///< Initial row of each print job.
} CONSOLE_LOGGER_PRIVATE_DATA;

#define CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(a) CR (a, CONSOLE_LOGGER_PRIVATE_DATA, OurConOut, CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE)


int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
	EFI_STATUS	Status;

	EFI_HANDLE	*HandleBuffer=NULL;
	UINTN		BufferSize=0,i;
  
	EFI_HANDLE	TheHandle;
	EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Dev;
	
	CONSOLE_LOGGER_PRIVATE_DATA       *ConsoleInfo;
	
	// Look up all gEfiShellProtocolGuid in the platform
	Status = gBS->LocateHandle(
		ByProtocol,
		&gEfiShellProtocolGuid,
		NULL,
		&BufferSize,
		HandleBuffer);
	if (Status == EFI_BUFFER_TOO_SMALL) {
		HandleBuffer = AllocateZeroPool(BufferSize);
		if (HandleBuffer == NULL) {
			return (EFI_BUFFER_TOO_SMALL);}
		//Get all the gEfiShellProtocolGuid Protocol in the system
		Status = gBS->LocateHandle(
			ByProtocol,
			&gEfiShellProtocolGuid,
			NULL,
			&BufferSize,
			HandleBuffer);
	}
	
	//Print(L"%d handles have been found!\n",(BufferSize / sizeof(EFI_HANDLE)));	

	if (BufferSize==0) {
			Print(L"No gEfiShellProtocolGuid found!\n"); 
			return EFI_SUCCESS; }
			
	//In fact there will be only one in system (in the Shell image)
	TheHandle=HandleBuffer[0];
	FreePool(HandleBuffer);

	//Get SimpleTextOutProtocol used by Shell
	Status = gBS->HandleProtocol (
					TheHandle,
					&gEfiSimpleTextOutProtocolGuid,
					&Dev);
	if (EFI_ERROR(Status))	{
		Print(L"Error when opening SimpleTextOutProtocol\n");
		return EFI_SUCCESS;
	}

	ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(Dev);	
	
	for (i=0;i<(ConsoleInfo->ColsPerScreen+2)*4;i++) {
		if (ConsoleInfo->Buffer[i] != 0) {Print(L"%c",ConsoleInfo->Buffer[i]);}
	}
	Print(L"\n");
	
	return EFI_SUCCESS;
}

 

运行结果,这是NT32模拟环境中的运行结果。同样我还在 Intel ApolloLake 上进行了实验,结果相同。

hs

完整的代码下载:

logbuffer

编译后的Application下载(IA32和X64)

lb

不要购买白色版本的USB Host Shield

前几日入手了新版的 USB Host Shield,今天拿到手了,拆开包装大吃一惊,发现有下面几个问题:
1. USB的方向变了,之前是和 UNO板载USB相反的方向,现在变成相同的方向,这样做的好处是方便整体设计,只要在一面开口即可(这个是 USB Host Shield 2.0 设计 升级的结果)。但是如果你之前设计过盒子,那么换Shield之后只能重新设计了;
image002
2. Shield上带 ICSP脚座(下图黑色方块),看起来这个Shield应该可以直接兼容Leonardo的板子(但是有可能要 rework);
3. 引脚选择的是最便宜的那种,很长,很软,很歪,插拔不了几次。断了一根的话,板子基本上就废了,真正使用的话恐怕只能一直固定着,尽量不插拔;
image004
4. 还是引脚的问题,很长,插入之后会长出来一截,总让人觉得没有插进去;
image006

更悲剧的是,入手之后上电无法使用,使用很早之前USB Host Shield 1.0的测试代码进行最基本的SPI 测试都无法通过。板子上也没有任何跳线,严重怀疑需要Rework一些位置才能工作起来。
因为是新买的,所以最后还是直接退货了事。因此,建议有需求的玩家,慎重选择这种白色的板子,为了方便省事,不妨直接选用DFRobot的板子。价格差不多是这种白色板子的3倍(110元左右),整体用料比较好,资料全面,更可靠(产品本身,不是服务)。

写完上面的话之后差不多一周,我入手了 DFRobot 的板子,广告是下面这样的,我用过两次他们家的板子,感觉用料非常扎实,工作也很好。售价 110,远比前面的贵。
image008
拿到手又是大吃一惊,和广告上的差别也太大了。
image010

除了不是彩色的插座之外,针脚同样也是之前买的那种很长,又非常软的。根本不值这个价格啊!同时还散发着浓烈的味道。我只听说过做高仿的古董,为了增加年代感会泡在粪坑中一年,但是从来没听说过电子产品也要这样处理。
毫无疑问的再次退货。
后来,极客工坊的togke(弘毅) 讲,国内的这种插接件其实挺难买的。原因是质量只有用了一段才知道,但是价格是很明显的。这样的小配件越是便宜出货量越大,结果造成了劣币驱逐良币,在市场上很难买到质量好的排针。而对于类似富士康这样的大公司来说,他们只愿意面对“大型客户”。于是,市面上无法买到合适质量的排针了。
又过了几次,我忽然想起来为什么之前买到的 USB Host Shield没有这样的问题?那块板子着实用了快2年。仔细端详,真相只有一个:在设计上似乎考虑到了这样的问题错开了一截,这样既可兼容原来的设计,又不会有选择排针的困惑。
image012
查一下原始的设计文档【参考1】如下
image014
可以看到原本是没有这样的设计,但是通过简单的修改,让板子更加适应国情。
从整个 Arduino 的产品来看,国内的作品水平还比较低,绝大多数卖家都是凭借“价格优势”来维持生存的。所有的产品也都以仿造为主。我不反对仿造之类的,但是单纯的一直如此是不会有出路的。

ps:最后我甚至怀疑买到的 DFRobot的是假货,于是我问了淘宝上全部售卖这个产品的卖家,得到的答案都是“只有这种,没有彩色排针的。”

参考:
1. https://www.sparkfun.com/products/9947

Step to UEFI (105)DiskinfoProtocol

这次介绍一下用来取得系统上硬盘信息的 Protocol: EFI_DISK_INFO_PROTOCOL。

在\MdePkg\Include\Protocol\DiskInfo.h 有他的原型:

///
/// Forward declaration for EFI_DISK_INFO_PROTOCOL
///
typedef struct _EFI_DISK_INFO_PROTOCOL  EFI_DISK_INFO_PROTOCOL;
///
/// The EFI_DISK_INFO_PROTOCOL provides controller specific information.
///
struct _EFI_DISK_INFO_PROTOCOL {
  ///
  /// A GUID that defines the format of buffers for the other member functions 
  /// of this protocol.
  ///
  EFI_GUID                  Interface;
  ///
  /// Return the results of the Inquiry command to a drive in InquiryData. Data
  /// format of Inquiry data is defined by the Interface GUID.
  ///
  EFI_DISK_INFO_INQUIRY     Inquiry;
  ///
  /// Return the results of the Identify command to a drive in IdentifyData. Data
  /// format of Identify data is defined by the Interface GUID.
  ///
  EFI_DISK_INFO_IDENTIFY    Identify;
  ///
  /// Return the results of the Request Sense command to a drive in SenseData. Data
  /// format of Sense data is defined by the Interface GUID.
  ///
  EFI_DISK_INFO_SENSE_DATA  SenseData;
  ///
  /// Specific controller. 
  ///
  EFI_DISK_INFO_WHICH_IDE   WhichIde;
};

 

更详细的介绍可以在 PI Specification 1.4 上找到。
对于不同类型的设备,比如 IDE 和 USB ,返回的数据格式是不同的。枚举到这个 PROTOCOL 之后需要检查EFI_GUID Interface 通过不同的GUID得知当前设备的类型。
下面先编写一个简单的 Demo,检查 GUID ,判断当前设备的类型:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Protocol/DiskInfo.h>
#include  <Library/BaseMemoryLib.h>

extern EFI_BOOT_SERVICES         *gBS;

extern EFI_HANDLE				 gImageHandle;

EFI_GUID gEfiDiskInfoProtocolGuid = { 0xD432A67F, 0x14DC, 0x484B, 
					{ 0xB3, 0xBB, 0x3F, 0x02, 0x91, 0x84, 0x93, 0x27 }};

EFI_GUID gEfiDiskInfoIdeInterfaceGuid   = { 0x5E948FE3, 0x26D3, 0x42B5, 
					{ 0xAF, 0x17, 0x61, 0x02, 0x87, 0x18, 0x8D, 0xEC }};
EFI_GUID gEfiDiskInfoScsiInterfaceGuid  = { 0x08F74BAA, 0xEA36, 0x41D9, 
					{ 0x95, 0x21, 0x21, 0xA7, 0x0F, 0x87, 0x80, 0xBC }};
EFI_GUID gEfiDiskInfoUsbInterfaceGuid   = { 0xCB871572, 0xC11A, 0x47B5, 
					{ 0xB4, 0x92, 0x67, 0x5E, 0xAF, 0xA7, 0x77, 0x27 }};
EFI_GUID gEfiDiskInfoAhciInterfaceGuid  = { 0x9e498932, 0x4abc, 0x45af, 
					{ 0xa3, 0x4d, 0x02, 0x47, 0x78, 0x7b, 0xe7, 0xc6 }};
EFI_GUID gEfiDiskInfoNvmeInterfaceGuid  = { 0x3ab14680, 0x5d3f, 0x4a4d, 
					{ 0xbc, 0xdc, 0xcc, 0x38, 0x0, 0x18, 0xc7, 0xf7 }};
EFI_GUID gEfiDiskInfoUfsInterfaceGuid   = { 0x4b3029cc, 0x6b98, 0x47fb, 
					{ 0xbc, 0x96, 0x76, 0xdc, 0xb8, 0x4, 0x41, 0xf0 }};
int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
    EFI_STATUS Status;
    UINTN HandleIndex, NumHandles;
    EFI_HANDLE *ControllerHandle = NULL;
	EFI_DISK_INFO_PROTOCOL	*DiskInfoProtocol;
	
    Status = gBS->LocateHandleBuffer(
            ByProtocol,
            &gEfiDiskInfoProtocolGuid,
            NULL,
            &NumHandles,
            &ControllerHandle);
	
    for (HandleIndex = 0; HandleIndex < NumHandles; HandleIndex++) {
        Status = gBS->OpenProtocol(
                ControllerHandle[HandleIndex],
                &gEfiDiskInfoProtocolGuid, 
                (VOID**)&DiskInfoProtocol,
                gImageHandle,
                NULL,
                EFI_OPEN_PROTOCOL_GET_PROTOCOL
                );		
        if (EFI_ERROR(Status)) {
            continue;
        } 
		
		Print(L"Device[%d] GUID: %g",
				HandleIndex,
				DiskInfoProtocol->Interface);
		if (CompareGuid (
				&DiskInfoProtocol->Interface, 
			&gEfiDiskInfoIdeInterfaceGuid)) {	
				Print(L" IDE HDD\n");
			}	
		if (CompareGuid (
				&DiskInfoProtocol->Interface, 
			&gEfiDiskInfoScsiInterfaceGuid)) {	
				Print(L" Scsi HDD\n");
			}	
		if (CompareGuid (
				&DiskInfoProtocol->Interface, 
			&gEfiDiskInfoUsbInterfaceGuid)) {	
				Print(L" USB HDD\n");
			}	
		if (CompareGuid (
				&DiskInfoProtocol->Interface, 
			&gEfiDiskInfoAhciInterfaceGuid)) {	
				Print(L" AHCI HDD\n");
			}	
		if (CompareGuid (
				&DiskInfoProtocol->Interface, 
			&gEfiDiskInfoNvmeInterfaceGuid)) {	
				Print(L" NVME HDD\n");
			}	
		if (CompareGuid (
				&DiskInfoProtocol->Interface, 
			&gEfiDiskInfoUfsInterfaceGuid)) {	
				Print(L" Ufs HDD\n");
			}				
	}

  return EFI_SUCCESS;
}

 

上述代码在UDK2014中编译通过,但是无法在 NT32环境下运行。于是在实体机KabyLake HDK 上实验, 板子上挂载了一个 SATA HDD 一个eMMC和两个USB Disk。运行结果如下:

dit

可以看出,当前的SATA 是AHCI 模式。此外, eMMC 设备是无法被识别出来的,也许后面会扩展到这种设备吧。
完整的代码下载:

diskinfotest

Step to UEFI Tips :介绍 BaseMemoryLib

最近在写代码时,需要用到一些关于 GUID 处理的函数。偶然间看到了 BaseMemoryLib.h 中有一些,顺便整理了一下这个库提供的函数。完整的头文件在 \MdePkg\Include\Library\BaseMemoryLib.h .

 

CopyMem   内存拷贝函数

SetMem       用8Bit来进行内存填充

SetMem16用 16Bit来进行内存填充

SetMem32用 32Bit来进行内存填充

SetMem64用 64Bit来进行内存填充

SetMemN  用 UINTN 来进行内存填充(UINTN在IA32下和 X64下大小不同)

ZeroMem  对指定内存清零

CompareMem  比较内存函数

ScanMem8   在内存中搜索一个 8Bit的指定值

ScanMem16   在内存中搜索一个 16Bit的指定值

ScanMem32   在内存中搜索一个 32Bit的指定值

ScanMem64   在内存中搜索一个 64Bit的指定值

ScanMemN     在内存中搜索UINTN大小的指定值

CopyGuid       复制一个 GUID 到另外一个 GUID中

CompareGuid  比较2个 GUID

ScanGuid         在内存中搜索一个给定的 GUID

IsZeroGuid       检查一个 GUID是否为0

IsZeroBuffer     检查一段内存是否为为全0