UEFI开发探索92 – 调试使用了StdLib的64位程序

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

昨天有位名为“sam bing”的网友,提到用VS2015和EmulatorPkg调试UEFI程序。调试方法在之前的博客中讨论过,他是参照博客去操作的。

问题在于,他发现在工程中使用C标准库函数,也即StdLib后,在EmulatorPkg中无法编译通过,也就无法通过EmulatorPkg进行64位C标准库工程的调试了。

这个问题我也觉得奇怪,理论上不应该啊。

上午处理完项目相关的事情后,正好有点时间,就着手进行这个问题的分析了。

1 搭建开发环境

我日常都是在vUDK2018下进行开发,主要是因为它还支持Nt32Pkg,方便我随时使用模拟器进行调试。

为了分析这个问题,我得用一个相对较新的版本来测试。正好前段时间整理书稿的时候,搭建了一个开发环境,看了下版本:

robin@DESKTOP-083AISO:/mnt/c/srcEDKx/edk2$ git log
commit ca407c7246bf405da6d9b1b9d93e5e7f17b4b1f9 (HEAD, tag: edk2-stable202005)
Author: Ard Biesheuvel <ard.biesheuvel@arm.com>
Date:   Wed May 20 13:44:48 2020 +0200

ArmPkg/CompilerIntrinsicsLib: provide atomics intrinsics
…..//后略

robin@DESKTOP-083AISO:/mnt/c/srcEDKx/edk2$ ls
AppPkg          DynamicTablesPkg     License.txt      RobinPkg             StdLibPrivateInternalFiles
ArmPkg          EmbeddedPkg          Maintainers.txt  RobinPkg1            UefiCpuPkg
ArmPlatformPkg  EmulatorPkg          MdeModulePkg     SecurityPkg          UefiPayloadPkg
ArmVirtPkg      FatPkg               MdePkg           ShellPkg             UnitTestFrameworkPkg
BaseTools       FmpDevicePkg         NetworkPkg       SignedCapsulePkg     edksetup.bat
Build           IntelFsp2Pkg         OvmfPkg          SourceLevelDebugPkg  edksetup.sh
Conf            IntelFsp2WrapperPkg  PcAtChipsetPkg   StandaloneMmPkg      pip-requirements.txt
CryptoPkg       License-History.txt  ReadMe.rst       StdLib

使用的是2020年的5月版,为了方便使用,我把StdLib、AppPkg等包,以及我自己的包RobinPkg一股脑都放在了edk2的同一目录下了。

继续阅读“UEFI开发探索92 – 调试使用了StdLib的64位程序”

4,382 total views, 1 views today

UEFI开发探索91- 类型强制转换引起的问题

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

最近有个项目开发,我需要构建几个UEFI图形对话框,用来接受用户的密码修改和输入。大致的样子是这样的:

图1 UEFI下的密码对话框

开发过程中,发现使用VS编译和GCC编译的结果不同。一番折腾后,了解到是强制转换引起的问题。

之前有个问题集的博客,本想把这个问题也扔到那边去,不过在寻找问题原因的过程中,使用了各种调试手段,我觉得有必要记录下来,作为未来开发的参考。

因此有了这篇博客。

继续阅读“UEFI开发探索91- 类型强制转换引起的问题”

2,010 total views, 2 views today

UEFI开发探索90- YIE002USB开发板(13 Linux编程)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

上一篇使用hidapi的hidraw方式,实现了Linux上位机与USB HID设备通信的测试程序。不过,只实现了三种通信方式中的两种。本篇将使用hidapi的libusb方式,将三种通信方式全部实现。

1 建立开发目录

与上一篇一样,首先建立开发用的目录。新建文件夹hidlibusb,将以下文件拷贝进去:

libusb/hid.c
hidapi/hidapi.h
hidtest/test.c

为目前的代码编写Makefile,内容如下:

继续阅读“UEFI开发探索90- YIE002USB开发板(13 Linux编程)”

1,372 total views, 1 views today

UEFI开发探索89- YIE002USB开发板(12 Linux编程)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

对于USB HID的编程,在YIE002USB开篇时,就已经讨论过:

  1. 下位机是使用YIE002制作的USB HID设备,这是嵌入式开发;
  2. 上位机包括了Windows系统、UEFI系统和Linux系统。

上位机软件中,没有把Mac OSX包含进来,主要是因为我较少在苹果的系统上开发,而且也可以将其等同于Linux系统看待(同属于类Unix系)。

至今为止,Windows系统和UEFI系统,我们都已经完成了上位机的软件编写,下面该进入Linux的USB HID上位机软件开发了。

1 概述

对于Linux下的HID,网站“The Linux Kernel”上有非常详细的描述,值得仔细阅读,网址为:
https://www.kernel.org/doc/html/latest/hid/index.html。

我们所要访问的设备,是USB HID设备。在Linux系统中,常用的USB开源库,是libusb。这是一个用C语言开发的,跨平台的USB设备访问接口库。

在Github上找到这个开源库后,通读了一遍其文档。理论上使用它,可以完整地实现我们所需要的功能。不过,文档中也建议,如果是访问HID设备的话,可以使用hidapi。

hidapi是一个开源的操作HID设备的C语言库,适用于Windows、Linux和Mac OSX平台。它是针对HID设备的,对于其他USB设备不合适。

其源码仓库为:https://github.com/libusb/hidapi,主要目录如下:

hidapi: 头文件(所有平台共用一份头文件)hidapi.h
libusb:Linux系统实现源码文件hid.c,使用libusb库实现的方式
linux:Linux系统实现源码文件hid.c,使用内核接口(hidraw)实现方式
windows:Windows系统实现源码文件hid.c
mac:Mac OSX 系统实现源码文件hid.c
hidtest:测试代码 test.c
继续阅读“UEFI开发探索89- YIE002USB开发板(12 Linux编程)”

1,474 total views, no views today

UEFI开发探索88- YIE002USB开发板(11 UEFI下访问HID设备)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

通过前面几个篇章的博客,制作好了USB HID设备,并使用Windows下的上位机工具UsbHID,测试了设备的工作状态。

终于,可以在UEFI系统下构建访问USB HID设备的工程了。

我们所制作的USB HID设备,在Windows系统下可以成功通信,这也意味着,在UEFI环境下,我们也可以与之通信。

首先,使用linux下的lsusb工具,查看下我们之前实现的USB HID设备:

robin@robin-virtual-machine:~$ sudo lsusb -v -d 0x8765:4321
Bus 002 Device 004: ID 8765:4321  
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x8765 
  idProduct          0x4321 
  bcdDevice            2.00
  iManufacturer           1 Robin
  iProduct                2 Robin's UEFI Explorer
  iSerial                 3 My123
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           41
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      33
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval              32
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval              32
Device Status:     0x0003
  Self Powered
  Remote Wakeup Enabled

从中可以看出,自制的USB HID设备,端点1可以使用中断传输的方式进行通信。另外,在上述的信息中没有列出报表描述符,此设备支持通过Output report& Input report、Feature report的方式进行通信,传输字节为16字节。

本篇介绍如何在UEFI系统下,实现对应这三种通信方式的代码,主要实现步骤如下。

继续阅读“UEFI开发探索88- YIE002USB开发板(11 UEFI下访问HID设备)”

2,051 total views, 3 views today

UEFI开发探索87- YIE002USB开发板(10 UEFI对USB的支持2)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

3 EFI_USB_IO_PROTOCOL

EFI_USB_IO_PROTOCOL由USB总线驱动产生,可由UEFI应用和驱动使用,用来访问各种USB设备,比如USB键盘、鼠标和大容量存储设备等。EFI_USB_IO_PROTOCOL所提供的接口,可提供四种类型的传输方式与USB设备通信,即之前介绍过的控制传输、中断传输、批量传输和实时传输。

EFI_USB_IO_PROTOCOL的函数接口如下所示:

typedef struct _EFI_USB_IO_PROTOCOL {
  EFI_USB_IO_CONTROL_TRANSFER UsbControlTransfer;   //控制传输
  EFI_USB_IO_BULK_TRANSFER UsbBulkTransfer;          //批量传输
  EFI_USB_IO_ASYNC_INTERRUPT_TRANSFER  \
                          UsbAsyncInterruptTransfer;   //异步中断传输
  EFI_USB_IO_SYNC_INTERRPUT_TRANSFER UsbSyncInterruptTransfer //同步中断传输
  EFI_USB_IO_ISOCHRONOUS_TRANSFER UsbIsochronousTransfer;      //实时传输
  EFI_USB_IO_ASYNC_ISOCHRONOUS_TRANSFER \
                          UsbAsyncIsochronousTransfer; //异步实时传输
  EFI_USB_IO_GET_DEVICE_DESCRIPTOR UsbGetDeviceDescriptor; //获取设备描述符
  EFI_USB_IO_GET_CONFIG_DESCRIPTOR UsbGetConfigDescriptor; //获取配置描述符
  EFI_USB_IO_GET_INTERFACE_DESCRIPTOR \
                        UsbGetInterfaceDescriptor;               //获取接口描述符
EFI_USB_IO_GET_ENDPOINT_DESCRIPTOR UsbGetEndpointDescriptor;
//获取端点描述符
  EFI_USB_IO_GET_STRING_DESCRIPTOR UsbGetStringDescriptor;//获取字符串描述符
  EFI_USB_IO_GET_SUPPORTED_LANGUAGES UsbGetSupportedLanguages;//获取支持语言
  EFI_USB_IO_PORT_RESET UsbPortReset;                        //重启USB控制器
} EFI_USB_IO_PROTOCOL;

对照之前介绍过的USB协议的知识,很容易理解EFI_USB_IO_PROTOCOL所提供的各类接口函数。下面主要介绍下常用的两个接口函数,UsbGetDeviceDescriptor()和UsbControlTransfer(),其他接口函数的说明,请查询UEFI Spec。

继续阅读“UEFI开发探索87- YIE002USB开发板(10 UEFI对USB的支持2)”

1,277 total views, 1 views today

UEFI开发探索86- YIE002USB开发板(09 UEFI对USB的支持1)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

通过前面几篇博客,我们制作了具备通信能力的USB HID设备。使用之前写的Windows下的测试工具,设备工作得很好。

同样的,UEFI环境下,也可以编写上位机程序,访问USB HID设备。本篇主要介绍UEFI对USB的支持,包括UEFI的USB驱动架构和提供的USB Protocol。

1 UEFI下的USB驱动协议架构

在UEFI系统中,包含USB主控制器驱动、USB总线驱动和USB设备驱动,它们共同工作构建了UEFI平台的USB驱动协议栈。USB驱动协议栈的模型如图1所示,图中演示了USB驱动的关系和使用的Protocol。

图1 UEFI中的USB驱动协议栈

平台硬件的PCI总线上,提供了一个单独的USB控制器。PCI总线驱动为USB主控制器句柄安装Protocol,包括EFI_DEVICE_PATH_PROTOCOL和EFI_PCI_IO_PROTOCOL。而USB主控制器则使用EFI_PCI_IO_PROTOCOL,在其句柄上安装EFI_USB2_HC_PROTOCOL。

继续阅读“UEFI开发探索86- YIE002USB开发板(09 UEFI对USB的支持1)”

1,571 total views, 5 views today

UEFI开发探索85- YIE002USB开发板(08 制作HID设备)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

在介绍完所有背景知识后,终于可以进入实质的嵌入式编程了。

本篇拟使用YIE002开发板,制作一个USB HID设备,支持三种通信方式,以对应UEFI开发探索73和74所讨论的三种上位机通信。

这个系列的博客,主要还是偏向UEFI编程的探索,对于嵌入式的编程,不想讨论过多。对于YIE002的嵌入式开发,请移步我另外一个专栏“嵌入式开发”,在其中我开了一个新坑,用来探索YIE002的编程。

1 YIE002-STM32的USB编程

这款开发板的主芯片是STM32F103C8T6,是我出差最常带的版型。本篇所写的代码,适用于所有F1系列作为主芯片的开发板,比如正点原子的战舰开发板。

从意法的官方资料可知,STM32 MCU有如下USB IP:

  1. USB IP 可作为全速USB设备,存在于STM32F102、STM32F103;
  2. USB+ IP 可作为全速USB设备,存在于STM32F0x2;
  3. FS OTG IP 可作为全速和低速USB主机、全速USB设备,存在于STM32F105、STM32F107、STM32F2、STM32F4;
  4. HS OTG IP 可作为高速、全速和低速USB主机,可作为高速和全速USB设备,存在于STM32F2、STM32F4。

官方也提供了不同的USB库,以适应开发需求。比如针对USB IP和USB+ IP,提供的库如图1所示。

图1 USB(+) IP对应的USB库
继续阅读“UEFI开发探索85- YIE002USB开发板(08 制作HID设备)”

1,098 total views, 1 views today

UEFI开发探索84- YIE002USB开发板(07 制作HID设备)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

在之前的博客中,曾经谈到制作USB HID需要掌握的背景知识。包括USB软件架构、USB描述符和USB命令。前两个已经讨论过了,本篇介绍USB命令。

1 USB命令(USB Device Request)

USB规范定义了设备请求(USB Device Request),以更好地完成USB主机对总线上所有USB设备的统一控制。此设备请求由USB主机发往USB设备,为方便理解USB主机和设备间的主从关系,后续行文中一律称为“USB命令”。

USB命令包括USB标准命令、类命令和厂商命令。这些命令的格式都是相同的,如表1所示。

表1 USB命令的结构

偏移字段 长度数值描述
0  bmRequesType1位图D7:数据的传输方向
  0=主机->设备
  1=设备->主机
D6…5:命令的类型
 0=标准命令 1=类命令
 2=厂商命令 3=保留
D4…0:接收对象
 0=设备 1=接口 2=端点
 3=其他  4…31=保留
1  bRequest1命令的序号
2  wValue2根据不同的命令,含义也不同
4  wIndex2索引或偏移根据不同的命令,含义不同,主要用于传送索引或者偏移
6  wLength2如果有数据阶段,此字段为数据的字节数

标准命令是每种USB设备都要支持的,类命令则与USB设备所述类有关,比如USB HID设备有HID类特有的命令,如Get_Report、SetReport等。

继续阅读“UEFI开发探索84- YIE002USB开发板(07 制作HID设备)”

1,152 total views, 2 views today

UEFI开发探索83- YIE002USB开发板(06 制作HID设备)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

我们所要开发用来通信的USB设备,是HID类设备。HID(Human Interface Devices)为人机接口设备,是USB规范中最早提出并支持的一种设备类。我们日常使用的键盘、鼠标等,都属于HID设备,这是一种使用非常广泛的USB设备。

USB规范中,HID类设备的规范为Device Definiton for Human Interface Devices,每个HID设备都必须符合该规范中对描述符、传输类型等的定义。另外,USB-IF还提供了HID的用例规范,名为HID Usage Tables,定义了HID设备和USB主机之间通信的HID数据。所有的 HID 传输都是使用默认控制管道或是一个中断管道, HID 设备必须有一个中断输入端点来传送数据到主机,中断输出端点则不是必需的。

HID设备的标准描述符同样遵循上一篇所介绍的内容,也即拥有各种标准描述符。对于HID设备,其设备描述符的类代码、子类代码和协议代码都需要设置为0;接口描述符的类代码设为0x03,子类代码为0或者0x01,协议码为0、0x01或0x02。

当然,作为类设备,HID也有自己的描述符,也即人机接口类描述符,本篇介绍这些内容。

HID设备支持3种类描述符:HID描述符、报告描述符和物理描述符。一个USB设备只能包含一个HID描述符,可以支持多个报告描述符,而物理描述符是可选的。在本章的示例中,只用到了HID描述符和报告描述符,没有使用物理描述符,一般的HID设备也不使用该描述符,就不再进行介绍了。

继续阅读“UEFI开发探索83- YIE002USB开发板(06 制作HID设备)”

1,279 total views, 1 views today

UEFI开发探索82- YIE002USB开发板(05 制作HID设备)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

从软件的角度,制作USB HID设备,需要理解的知识包括几大块:
1) USB协议的基本架构和软件架构;
2) USB描述符,包括标准描述符和类描述符;
3) USB命令,包括标准命令和类命令。

当然,如果能从字节序上(比如USB包的构成)了解USB通信的过程,对理解整个USB协议的构成也很有好处。但在编程中,不需要理解到这个地步。大部分介绍USB协议的书籍,以及USB规范中,都很详细地描述了这些过程,非常建议读一读。

在前一篇中,已经简要地概述了USB协议的基本架构和软件架构。本篇主要介绍USB描述符中的标准描述符,这是所有USB设备都要支持的描述符。

1 USB描述符概述

为了方便USB主机对USB设备进行管理,USB-IF对USB设备的功能采用了分层结构,包括设备层、配置层、接口层和端点层。图1给出了一个复合设备的例子,展示了USB设备的分层结构。

图1 USB设备的功能分层结构

这四层的作用分别为:

  1. 设备层。说明USB设备的主要类型特征(如设备类别、接口、端点等属性),保障设备枚举过程的正常进行。
  2. 配置层。选择不同的失败配置满足USB主机对设备功能的选择,可选择复式的设备接口功能,如图1展示的选择鼠标、键盘和游戏杆的复合功能。
  3. 接口层。将具体功能分类,不同的功能对用不同的操作方式。
  4. 端点层。针对特定的设备功能,选择不同的端点,提供不同的数据管道,与USB主机进行数据通讯。
继续阅读“UEFI开发探索82- YIE002USB开发板(05 制作HID设备)”

1,544 total views, 1 views today

UEFI开发探索81- YIE002USB开发板(04 制作HID设备)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

YIE002开发板上的开发,停滞了有一段时间了,这几天重新开始编写。

在最早编写的《UEFI编程实践》的书稿中,我是使用正点原子的探索者F4来制作HID设备的。感觉在自己的书中,使用其他家的开发板和代码,总是觉得有点不对。另外,在其代码上进行改造开发,存在版权的问题。

当然,最主要的,我也希望能有一个容易携带的开发板,方便我回家、或者出差的时候使用。于是才构建了这么一个机会,取名为YIE002。YIE中文含义为“易也”,来自于好友张佩的博客网站YIIEE,同音于中文“耶”和英文“yeah”。该是来自于程序员解决BUG、完成任务时,不由自主发出的欢呼声。

YIE002开发板的开篇中,描述了USB HID通信架构,包含USB HID的设备和上位机程序编写。上位机包括Windows系统、Linux系统和UEFI系统。之前用来两篇,介绍了如何在Windows系统下进行上位机编写,并开发了一个方便使用的调试工具。从本篇开始,介绍如何使用开发板制作USB HID设备,并使之支持三种通信方式。

从我的博客编写规划来说,YIE002的开发,到现在为止,都还没有进入实质的UEFI开发。主要原因在于,USB协议比较复杂。目前的开发,主要关注的是HID类协议,所需要了解的背景知识也非常庞杂。

在没有掌握USB协议相关的知识前,去读UEFI中关于USB的Protocol,会满头雾水,无法理解的。

因此,我觉得还是有必要通过学习制作USB HID设备,用几篇博客的篇幅,大致了解了USB协议的框架和编程方法,才能深入理解UEFI下USB设备的访问方法。

1 USB规范简介

通用串行总线(Universal Serial Bus,简称USB)由Intel、IBM、微软等计算机和通信公司,于1995年联合制定,解决旧有接口的问题,以适应当时计算机的飞速发展。作为一种高速串行总线,其极高的传输速度可以满足高速数据传输的应用环境要求。并且由于它供电简单、支持热插拔、扩展端口简单以及传输方式多样化等特点,目前广泛应用于各种计算机、手机等电子设备中。

相比于RS-232、PS/2等传统接口,USB最突出的特点是,其扩展性极强。RS-232等传统接口,一个预留接口只能用来连接一个相关设备,当需要扩展时,必须占用大量的计算机内部资源(如系统I/O口、中断向量和总线地址等)。而一个USB口,可以通过USB集线器,连接127个USB设备。USB简便的外设连接方式,以及优良的数据传输功能,为计算机外设接口带来了革命性的变化。

USB标准规范包括USB1.0、USB1.1、USB2.0、USB3.0,以及2019年9月发布的USB4TM规范。如表1所示,从推出时间、传输速率等方面,对USB规范的各版本进行了描述。

表1 USB规范各版本信息

USB版本最大传输速率名称推出时间
USB1.01.5Mbps低速(Low-Speed)1996年1月
USB2.0480Mbps高速(High-Speed)2000年4月
USB3.0(USB3.2 Gen 1)5Gbps超高速(Super-Speed)2008年11月
USB3.1(USB3.2 Gen 2)10Gbps超高速(Super-Speed 10Gbps)2013年12月
USB3.2(USB3.2 Gen 2×2)20Gbps超高速(Super-Speed 20Gbps)2017年9月
USB4TM (USB4 Gen 2×2)20GbpsUSB4TM 20Gbps2019年9月
USB4TM(USB4 Gen 3×2)40GbpsUSB4TM 40Gbps2019年9月
继续阅读“UEFI开发探索81- YIE002USB开发板(04 制作HID设备)”

1,291 total views, no views today