UEFI源码解析之UEFI_DRIVER

2023-10-27

Dxe Driver可以视作UEFI中的一个服务,在entry中通过protocol安装自己的服务,在Bds等位置通过locate protocol使用该服务,不必依赖与具体的硬件。当需要封装某个设备/控制器或总线的时候,对应于具体的物理实现,需要用到UEFI Driver的模型实现。UEFI Driver模型实现设备/总线的检测,安装,卸载,更新,启动,停止等;一个Driver可能适配多个设备,一个设备可能连接管理多个子设备等,因此UEFI Driver还可以多次安装。以下从GraphicsOutput设备为入口来解读UEFI driver的源码。

1. UEFI Driver的实现

源码路径为MdeModulePkg\Universal\Console\GraphicsOutputDxe\GraphicsOutput.c。从driver的入口开始:

InitializeGraphicsOutput (
  IN EFI_HANDLE                        ImageHandle,
  IN EFI_SYSTEM_TABLE                  *SystemTable
  )
{
  // 从PEI阶段的HOB中获取Graphic的信息,如Edid等
  HobStart = GetFirstGuidHob (&gEfiGraphicsInfoHobGuid);
  // 将mGraphicsOutputDriverBinding 安装到Dxe环境里面
  Status = EfiLibInstallDriverBindingComponentName2 (
             ImageHandle,
             SystemTable,
             &mGraphicsOutputDriverBinding,
             ImageHandle,
             &mGraphicsOutputComponentName,
             &mGraphicsOutputComponentName2
             );

  return Status;
}

EfiLibInstallDriverBindingComponentName2()根据入参以及实际pcd的配置安装driver的protocol和名字等信息;

       Status = gBS->InstallMultipleProtocolInterfaces (
                       &DriverBinding->DriverBindingHandle,
                       &gEfiDriverBindingProtocolGuid, DriverBinding,
                       &gEfiComponentNameProtocolGuid, ComponentName,
                       &gEfiComponentName2ProtocolGuid, ComponentName2,
                       NULL
                       );

驱动模型的核心通过EFI_DRIVER_BINDING_PROTOCOL实现,通过该protocol判断一个driver是否支持某个控制器,以及启动和停止该控制器;

struct _EFI_DRIVER_BINDING_PROTOCOL {

  EFI_DRIVER_BINDING_SUPPORTED  Supported;  //判断driver是否支持该控制器

  EFI_DRIVER_BINDING_START      Start;  //安装driver到设备/总线控制器

  EFI_DRIVER_BINDING_STOP       Stop;  //卸载设备/总线控制器driver

  UINT32                        Version;

  EFI_HANDLE                    ImageHandle;   //当前driver的image handle

  EFI_HANDLE                    DriverBindingHandle;  //该protocol应该安装到的handle,大部分时候与ImageHandle相同,如果

};

graphicsOutput的实现为:

EFI_DRIVER_BINDING_PROTOCOL mGraphicsOutputDriverBinding = {
  GraphicsOutputDriverBindingSupported,
  GraphicsOutputDriverBindingStart,
  GraphicsOutputDriverBindingStop,
  0x10,
  NULL,
  NULL
};

EFI_COMPONENT_NAME_PROTOCOL/EFI_COMPONENT_NAME2_PROTOCOL 描述Driver的名字,提供获取driver名字和控制器名字的接口,支持的语言类型;

struct _EFI_COMPONENT_NAME2_PROTOCOL {

  EFI_COMPONENT_NAME2_GET_DRIVER_NAME      GetDriverName;

  EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME  GetControllerName;

  CHAR8                                    *SupportedLanguages;

};

graphicsOutput的实现为:

// EFI Component Name Protocol
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  mGraphicsOutputComponentName = {
  GraphicsOutputComponentNameGetDriverName,
  GraphicsOutputComponentNameGetControllerName,
  "eng"
};

// EFI Component Name 2 Protocol
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mGraphicsOutputComponentName2 = {
  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GraphicsOutputComponentNameGetDriverName,
  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GraphicsOutputComponentNameGetControllerName,
  "en"
};

从EfiLibInstallDriverBindingComponentName2接口的实现中发现, EFI_DRIVER_BINDING_PROTOCOL安装在gEfiDriverBindingProtocolGuid上,EFI_COMPONENT_NAME_PROTOCOL安装在gEfiComponentNameProtocolGuid上,EFI_COMPONENT_NAME2_PROTOCOL安装在gEfiComponentName2ProtocolGuid上。

详细安装流程参考《UEFI源码解析之PROTOCOL&HANDLE》。

2. UEFI Driver的使用

Driver的使用入口为gBS->ConnectController(), 将一个或多个driver链接到控制器;一般在Bds阶段的EfiBootManagerConnectAll ()接口中发起;其中调用BmConnectAllDriversToAllControllers ()实现;一般是Bds在load DriverOption或BootOption之前发起连接,因为实际Load启动项过程中会依赖具体的设备,如存储设备中读取启动文件等;

EfiBootManagerConnectAll ()
{
  // Connect the platform console first
  EfiBootManagerConnectAllDefaultConsoles ();

  // Generic way to connect all the drivers
  BmConnectAllDriversToAllControllers ();

  // Here we have the assumption that we have already had
  // platform default console
  EfiBootManagerConnectAllDefaultConsoles ();
}

BmConnectAllDriversToAllControllers实现为:

BmConnectAllDriversToAllControllers ()
{
  do {
    // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
    gBS->LocateHandleBuffer (
           AllHandles,
           NULL,
           NULL,
           &HandleCount,
           &HandleBuffer
           );
    // 遍历说有的image handle,链接该handle上的driver
    for (Index = 0; Index < HandleCount; Index++) {
      gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
    }

    // dispatch过程中可能或出现新的Dxe Driver,因此要多次链接
    Status = gDS->Dispatch ();

  } while (!EFI_ERROR (Status));
}

3. ConnectController的实现

源码在MdeModulePkg\Core\Dxe\Hand\DriverSupport.c的CoreConnectController();

CoreConnectController (

  IN  EFI_HANDLE                ControllerHandle,  //driver需要连接的控制器handle

  IN  EFI_HANDLE                *DriverImageHandle   // 支持该driver的handle 可选

  IN  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath // controller设备路径,可选

  IN  BOOLEAN                   Recursive  // 是否允许递归调用,因为可能存在子设备

  )

{

// 确保控制器handle有效

CoreValidateHandle (ControllerHandle);

//如果需要签名验证,如Secure Boot开启,则做签名检查

 if (gSecurity2 != NULL) {

    Status = CoreHandleProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);

    if (!EFI_ERROR (Status)) {

      FilePath     = HandleFilePath;

      if (RemainingDevicePath != NULL && !Recursive) {

        HandleFilePathSize      = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);

        RemainingDevicePathSize = GetDevicePathSize (RemainingDevicePath);

        TempFilePath = AllocateZeroPool (HandleFilePathSize + RemainingDevicePathSize);

        ASSERT (TempFilePath != NULL);

        CopyMem (TempFilePath, HandleFilePath, HandleFilePathSize);

        CopyMem ((UINT8 *) TempFilePath + HandleFilePathSize, RemainingDevicePath, RemainingDevicePathSize);

        FilePath = TempFilePath;

      }

      Status = gSecurity2->FileAuthentication (

                            gSecurity2,

                            FilePath,

                            NULL,

                            0,

                            FALSE

                            );

    }

  }

// 实际连接操作,如果返回EFI_NOT_READY,表示binding handle个数有变化,需要重新连接

do {

    ReturnStatus = CoreConnectSingleController (

                     ControllerHandle,

                     DriverImageHandle,

                     AlignedRemainingDevicePath

                     );

  } while (ReturnStatus == EFI_NOT_READY);

//子设备递归处理

1. 统计子设备个数,每次打开一个记录在ControllerHandle的OpenData中,被子设备打开一次增加一个记录,见 《UEFI源码解析之PROTOCOL&HANDLE》opendata描述;

    for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {

      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);

      for (ProtLink = Prot->OpenList.ForwardLink;

          ProtLink != &Prot->OpenList;

          ProtLink = ProtLink->ForwardLink) {

        OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);

        if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {

          ChildHandleCount++;

        }

      }

2. 获取子设备的handle

for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {

      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);

      for (ProtLink = Prot->OpenList.ForwardLink;

          ProtLink != &Prot->OpenList;

          ProtLink = ProtLink->ForwardLink) {

        OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);

        if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {

          ChildHandleBuffer[ChildHandleCount] = OpenData->ControllerHandle;

          ChildHandleCount++;

        }

      }

    }

    }

3. 递归连接每个子设备

for (Index = 0; Index < ChildHandleCount; Index++) {

      CoreConnectController (

        ChildHandleBuffer[Index],

        NULL,

        NULL,

        TRUE

        );

    }

}

CoreConnectSingleController ()的实现:

1. 从前面实现阶段描述可知,所有binding handles安装在一个protocol(gEfiDriverBindingProtocolGuid)上,因此可以一次性获取所有binding handle;

Status = CoreLocateHandleBuffer (

             ByProtocol,

             &gEfiDriverBindingProtocolGuid,

             NULL,

             &DriverBindingHandleCount,

             &DriverBindingHandleBuffer

             );

2. AddSortedDriverBindingProtocol()主要完成BindingProtocol的过滤和排序,将入参中handle描述支持的binding以及平台重写的handle中支持的binding加入最终的binding列表SortedDriverBindingProtocols中;该接口逻辑和实现背景还需要深入研究,当前还不是很清楚。

Status = CoreHandleProtocol(
             DriverBindingHandle,
             &gEfiDriverBindingProtocolGuid,
             (VOID **) &DriverBinding
             );
  //
  // If DriverBindingHandle does not support the Driver Binding Protocol then return
  //
  if (EFI_ERROR (Status) || DriverBinding == NULL) {
    return;
  }

  //
  // See if DriverBinding is already in the sorted list
  //
  for (Index = 0; Index < *NumberOfSortedDriverBindingProtocols && Index < DriverBindingHandleCount; Index++) {
    if (DriverBinding == SortedDriverBindingProtocols[Index]) {
      return;
    }
  }

  //
  // Add DriverBinding to the end of the list
  //
  if (*NumberOfSortedDriverBindingProtocols < DriverBindingHandleCount) {
    SortedDriverBindingProtocols[*NumberOfSortedDriverBindingProtocols] = DriverBinding;
  }
  *NumberOfSortedDriverBindingProtocols = *NumberOfSortedDriverBindingProtocols + 1;

  //
  // Mark the cooresponding handle in DriverBindingHandleBuffer as used
  //
  for (Index = 0; Index < DriverBindingHandleCount; Index++) {
    if (DriverBindingHandleBuffer[Index] == DriverBindingHandle) {
      DriverBindingHandleBuffer[Index] = NULL;
    }
  }

3. 如果binding 数量增加,说明调用connect过程中有新的binding进来,返回EFI_NOT_READY,使得上层可以重新进入connnect执行;

// If the number of Driver Binding Protocols has increased since this function started, then return
  // EFI_NOT_READY, so it will be restarted
  //
  Status = CoreLocateHandleBuffer (
             ByProtocol,
             &gEfiDriverBindingProtocolGuid,
             NULL,
             &NewDriverBindingHandleCount,
             &NewDriverBindingHandleBuffer
             );
  CoreFreePool (NewDriverBindingHandleBuffer);
  if (NewDriverBindingHandleCount > DriverBindingHandleCount) {
    //
    // Free any buffers that were allocated with AllocatePool()
    //
    CoreFreePool (SortedDriverBindingProtocols);

    return EFI_NOT_READY;
  }

4. binding protocol根据版本排序;  为什么要排序??

// Sort the remaining DriverBinding Protocol based on their Version field from
  // highest to lowest.
  //
  for ( ; SortIndex < NumberOfSortedDriverBindingProtocols; SortIndex++) {
    HighestVersion = SortedDriverBindingProtocols[SortIndex]->Version;
    HighestIndex   = SortIndex;
    for (Index = SortIndex + 1; Index < NumberOfSortedDriverBindingProtocols; Index++) {
      if (SortedDriverBindingProtocols[Index]->Version > HighestVersion) {
        HighestVersion = SortedDriverBindingProtocols[Index]->Version;
        HighestIndex   = Index;
      }
    }
    if (SortIndex != HighestIndex) {
      DriverBinding = SortedDriverBindingProtocols[SortIndex];
      SortedDriverBindingProtocols[SortIndex] = SortedDriverBindingProtocols[HighestIndex];
      SortedDriverBindingProtocols[HighestIndex] = DriverBinding;
    }
  }

5. 遍历所有排序后的binding protocol,一次调用support检查是否该binding支持controller,如果support成功则设置DriverFound找到标记,标记该controller的Driver已找到,然后调用start加载driver,设置OneStart标记表示有一个驱动已经加载;否则返回EFI_NOT_FOUND;

OneStarted = FALSE;
  do {

    //
    // Loop through the sorted Driver Binding Protocol Instances in order, and see if
    // any of the Driver Binding Protocols support the controller specified by
    // ControllerHandle.
    //
    DriverBinding = NULL;
    DriverFound = FALSE;
    for (Index = 0; (Index < NumberOfSortedDriverBindingProtocols) && !DriverFound; Index++) {
      if (SortedDriverBindingProtocols[Index] != NULL) {
        DriverBinding = SortedDriverBindingProtocols[Index];
        PERF_DRIVER_BINDING_SUPPORT_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
        Status = DriverBinding->Supported(
                                  DriverBinding,
                                  ControllerHandle,
                                  RemainingDevicePath
                                  );
        PERF_DRIVER_BINDING_SUPPORT_END (DriverBinding->DriverBindingHandle, ControllerHandle);
        if (!EFI_ERROR (Status)) {
          SortedDriverBindingProtocols[Index] = NULL;
          DriverFound = TRUE;

          //
          // A driver was found that supports ControllerHandle, so attempt to start the driver
          // on ControllerHandle.
          //
          PERF_DRIVER_BINDING_START_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
          Status = DriverBinding->Start (
                                    DriverBinding,
                                    ControllerHandle,
                                    RemainingDevicePath
                                    );
          PERF_DRIVER_BINDING_START_END (DriverBinding->DriverBindingHandle, ControllerHandle);

          if (!EFI_ERROR (Status)) {
            //
            // The driver was successfully started on ControllerHandle, so set a flag
            //
            OneStarted = TRUE;
          }
        }
      }
    }
  } while (DriverFound);

6. 如果没有驱动被加载且时结尾设备节点,返回成功;

  // If no drivers started and RemainingDevicePath is an End Device Path Node, then return EFI_SUCCESS
  //
  if (RemainingDevicePath != NULL) {
    if (IsDevicePathEnd (RemainingDevicePath)) {
      return EFI_SUCCESS;
    }
  }

4. gDS->Dispatch ()实现

Dxe Driver的分发,实现在CoreDispatcher,源码分析在将来《UEFI源码解析之D'x'e'Core》再详细描述;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UEFI源码解析之UEFI_DRIVER 的相关文章

  • css样式兼容、注释_CSS中的伪注释(或者,浏览器如何解析样式)

    css样式兼容 注释 The CSS spec does not mention it but you can mimic C style and or Unix style line comments in CSS files with
  • Android 内核调用充电状态和电池电量

    Android 内核调用充电状态和电池电量 前言 一 调用的文件 二 调用函数 1 引入使用 2 返回值说明 小结 前言 因为Android项目需求 不是什么时候都是用APP来实现功能 部分项目是要求需要驱动需要独立完成部分系统层面的功能
  • 日志收集-elk

    04 4 日志收集 1 日志收集方式 Kubernetes的业务Pod日志有两种输出方式 一种是直接打到标准输出或者标准错误 第二种是将日志写到特定目录下的文件种 针对这两种不同场景 提供了不同的容器日志收集思路 1 1 Kubernete
  • 联想笔记本无线网络无法使用(无线开关已打开,但搜不到无线网络)

    今天 同事拿过来一台笔记本 说收不到无线网络了 插上有线可以上网 让给她看看 我看了一眼 果然是 插上网上后 是可以上网的 但就是收不到无线网络 本子是联想的 应该是很老的本子了 也没找到型号在哪 看了一下它的无线外置开关 是打开状态 但是
  • 联想G480 win10系统的电脑开启虚拟机bios设置

    启动虚拟机时不成功 要求开启bios设置 在网上搜了很多经验 又说开机时按F1键的 又说F2键的 还有F12的 我开机试了无数次就不能打开BIOS设置 联想电脑win10系统不靠按键还有其他的办法吗 当然有 1 打开设置 2 点立即重启之后
  • UEFI-SHELL 环境 U盘制作

    访问 https github com pbatard UEFI Shell releases 下载最新的ISO 然后用rufus 做启动盘 Rufus https rufus ie en map list device DUMP BIOS
  • Win10下VS2019双机调试之调试驱动

    转载于 https blog csdn net m0 48995611 article details 112211268 有现成的写的非常详细就不重复造轮子了 ps 1 注意文章字体加深部分 非常重要 2 原文bcdefit dbgset
  • 应用程序如何调用驱动

    以write函数举例 详细调用流程 insmod驱动程序 申请设备名 设备号以及指定fops方法 这些可以在 proc devices中获得 从 proc devices中获得主设备号 并使用mknode命令来建立设备节点文件 这是通过主设
  • windbg+vmware双机调试配置教程及可能出现的问题

    一 设备参数说明 1 调试机 物理机windows 10 windbg 10 0 22000 194 2 被调试机 虚拟机windows xp sp3 3 虚拟机软件 VMware workstation 16 1 2 二 虚拟机配置调试串
  • linux驱动模块的加载和卸载

    Linux 驱动有两种运行方式 第一种就是将驱动编译进 Linux 内核中 这样当 Linux 内核启动的时候就会自动运行驱动程序 第二种就是将驱动编译成模块 Linux 下模块扩展名为 ko 在Linux 内核启动以后使用 insmod
  • 字符设备驱动相关函数

    Linux内核中 a 使用cdev结构体来描述字符设备 b 通过其成员dev t来定义设备号 分为主 次设备号 以确定字符设备的唯一性 c 通过其成员file operations来定义字符设备驱动提供给VFS的接口函数 如常见的open
  • 利用外部程序对存储BIOS设置参数的CMOS RAM进行读取操作的可行性分析

    电脑的启动过程如下 机后主动执行BIOS程序 可以通过BIOS去设置CMOS 也可以不设置 然后BOIS会去识别操作系统引导设备的引导分区 一般也就是电脑里的硬盘中的第一个扇区 这个扇区中有分区表和主引导分区MBR 我们找到了MBR MBR
  • 我可以使用 EFI 在本地文件系统上写入吗

    我正在开发这个项目 以便在操作系统通过 EFI 应用程序启动后立即将文件写入本地文件系统 我需要知道是否可能 如果是的话 请指导我一点 谢谢 好吧 我会好好提醒你的 首先枚举系统中的所有 FS 协议 EFI BOOT SERVICES bs
  • 在linux下构建edk2

    我开始用 edk2 编写一个小而简单的应用程序 因此 要编写一个简单的 edk2 UEFI 应用程序 我是这样开始的 git克隆https github com tianocore edk2 git edksetup sh BaseTool
  • 我的 BIOS 设置中没有启用 Hyper-V 的选项

    我是 Windows Phone 8 应用程序开发新手 我安装了SDK 8 0 当我运行应用程序时 它显示一条错误 告诉我启用 Hyper V 在搜索过程中我发现这个 MSDN 文档BIOS 中有解决方案 但是当进入我的BIOS设置时 却没
  • 为什么引导加载程序中的字节“0xea 0000 ffff”会导致计算机重新启动?

    我正在研究引导加载程序 发现了这个有趣的组件 Sends us to the end of the memory causing reboot db 0x0ea dw 0x0000 dw 0xffff 通过评论我知道它的作用 将计算机发送到
  • 找出 x86 引导加载程序中引导了哪个驱动器

    我正在为 x86 编写游戏引导加载程序 在启动早期的某一时刻 我需要将启动驱动器中的一些扇区加载到内存中 我使用中断 0x13 ah 02 来执行此操作 当我在虚拟机中尝试它时 它就像一个魅力 然而 当我将映像刻录到 USB 驱动器时 机器
  • 使用 int 13h 读取的扇区数量多于磁道上的扇区数量

    顺序是什么int 13h with ah 02h会读19部门起始于 C H S 0 0 1 提供了 2 个磁头 每磁道 18 个扇区 每面 80 个磁道的 软盘 磁盘几何结构 或者 更一般地说 当它到达磁道 0 的末尾 磁头 0 时会发生什
  • 没有操作系统直接运行的程序叫什么名字?

    当我试图提出有关该主题的其他问题时 我很难正确表达我的问题 那么直接在相关计算机上运行的程序的正确名称是什么 一个可以描述内核和引导加载程序的术语 因为它们是在没有操作系统的情况下直接执行的 C 标准称之为 独立环境 我觉得这个术语和我见过
  • 生成唯一硬件 ID 的可靠方法

    问题 我必须为每个联网客户端提供唯一的 ID 例如 一旦客户端软件安装在目标计算机上 它 ID 应该持续存在 并且如果在同一台计算机和相同的操作系统安装上重新安装软件 它应该继续存在 如果以大多数方式修改硬件配置 除了更改主板 它不应该改变

随机推荐

  • 交易中间件消息中间件_什么是中间件

    交易中间件消息中间件 什么是中间件 What Is Middleware In network architecture a middleware is a layer of software that creates a network
  • 答题小程序常用脚本整理

    答题小程序常用脚本整理 本文主要描述答题活动小程序运营过程中 高频使用的 几个脚本操作 1 如何清理当前题库 在开发控制台的高级操作右侧有个加号按钮 点击下 选择空白模板即可 将下面的脚本复制进去 db collection questio
  • 聚簇索引和二级索引

    原文链接 https blog csdn net jijianshuai article details 79084874
  • SpringCloud项目如何成功打包以及其中的一些坑

    我的项目结构 其中edu online和edu admin是前端项目 其他是后端模块 首先需要在父工程中添加需要打包的模块和打包依赖 如果在父工程中配置过打包依赖则子模块中不需要配置打包依赖 但是如果有子模块需要被其他模块依赖 则需要在被依
  • ROS:解决Error:cannot launch node of type [map_server/map_server]: can't locate node [map_server] in......

    写在前面 本文为原创 如需转载请注明出处 https www jianshu com p e9981bc35cff 欢迎大家留言共同探讨 有误的地方也希望指出 另如果有好的SLAM ROS等相关交流群也希望可以留言给我 在此先谢过了 1 E
  • Gof23设计模式之建造者模式

    1 概述 建造者模式 Builder Pattern 又叫生成器模式 是一种对象构建模式 它可以将复杂对象的建造过程抽象出来 抽象类别 使这个抽象过程的不同实现方法可以构造出不同表现 属性 的对象 建造者模式是一步一步创建一个复杂的对象 它
  • 要求用成员函数实现以下功能由键盘输入,计算长方体的体积,输出3个长方体的体积。

    题目 需要求三个长方体的体积 请编写一个基于对象的程序 数据成员包括length 长 width 宽 height 高 要求用成员函数实现以下功能 1 由键盘输入3个长方体的长 宽 高 2 计算长方体的体积 3 输出3个长方体的体积 请编程
  • linux 关于修改命令提示符

    1 首先 进入root 用户获得权限 输入 su root 2 进入修改提示符的文件 输入 vim etc profile 3 进入文件 不要修改任何地方 在最后加入命令 1 输入 export PS1 e 1 32 40m 孔子曰 e 1
  • Flink将本地数据写入Redis

    第一步 配置文件redis conf cd usr apps redis vim redis conf 先输入 set nu 打开行号标识 69行 bind 127 0 0 1加上注释 取消IP绑定 否则其他主机不能连接 88行 prote
  • sqli-labs第十八十九关

    这两关为头注入 Less 18 POST Header Injection Uagent field Error based 手工注入 这关和下一关必须要抓包才能完成 因为在这里怎么是都没有反应 全是报错的状态 那么我估计就要抓包了 根本判
  • pythonqt对比_用 Python 和 C++ 创建 Qt 程序的简单对比

    假设要做一个简单的小窗口 如下图所示 PyQt 和 C 要用多少代码可以完成呢 效果图 注 本文内容较多 主要是 C 的部分 若有必要请直接跳到最后看结论 一 C 版本 除了最基础的 pro 文件之外 我一共创建了 5 个文件 custom
  • 电脑固定ip地址之后重启却失效了的解决办法

    开始 运行 cmd 回车 英文状态下输入 netsh winsock reset 回车后会提示重启 先不重启 继续输入 netsh int ip reset reset log 回车后会提示重启 此时先重启电脑 重启之后再次设置好固定ip地
  • SQL 映射文件

    SQL 映射文件 SQL 映射文件只有很少的几个顶级元素 按照应被定义的顺序列出 cache 对给定命名空间的缓存配置 cache ref 对其他命名空间缓存配置的引用 resultMap 是最复杂也是最强大的元素 用来描述如何从数据库结果
  • 使用LeNet-5识别手写数字MNIST

    LeNet5 LeNet 5卷积神经网络模型 LeNet 5 是Yann LeCun在1998年设计的用于手写数字识别的卷积神经网络 当年美国大多数银行就是用它来识别支票上面的手写数字的 它是早期卷积神经网络中最有代表性的实验系统之一 Le
  • 管理系统权限篇

    目录 前言 cooike 登录篇 登录 router beforeEach 登录拦截 axios拦截器 token过期出处理 权限篇 router js store permission js 前言 登录 当用户填写完账号和密码后向服务端验
  • 热门Android Studio 插件

    Android Studio是基于JetBrains公司的IntelliJ开发的一款功能强大的开发工具 它具有构建出色Android应用所需要的一切 借助基于IntelliJ IDEA的强大的功能 插件非常丰富 正确的使用插件可以帮助你提高
  • linux脚本判断输出结果,shell脚本中的逻辑判断

    if语法 格式1 if 条件 then 语句 fi 格式2 if 条件 then 语句 else 语句 fi 格式3 if then elif then else fi 逻辑判断表达式 if a gt b if a lt 5 if b eq
  • C进阶:通讯录(动态版本 + 文件操作)附源码

    本文主要讲解通讯录的代码 需要拥有结构体 动态内存开辟 文件操作的知识 目录 一 通讯录思路 二 三个文件的建立 三 所需要使用的变量的创建 包含在头文件contact h中 四 主函数的书写 包含在 test c 中 五 通讯录功能的实现
  • HM Fast Learning

    Whole Structure 7 projects App means application T stands for test TLib is library for developer not for application Vid
  • UEFI源码解析之UEFI_DRIVER

    Dxe Driver可以视作UEFI中的一个服务 在entry中通过protocol安装自己的服务 在Bds等位置通过locate protocol使用该服务 不必依赖与具体的硬件 当需要封装某个设备 控制器或总线的时候 对应于具体的物理实