【UEFI基础】BIOS下的启动项管理

news2024/9/20 7:07:05

启动管理

启动管理(Boot Manager)是UEFI BIOS中重要的一部分,它通过一系列的变量来确定启动策略,包括:

  • 执行启动还是恢复操作
  • 启动顺序是如何

本文会介绍下面的内容:

  • 与启动管理相关的变量
  • 启动或恢复的流程策略
  • 加载项结构体
  • 创建加载项

注意本文只关注UEFI BIOS的启动项,涉及的是UEFI BIOS启动管理,至于Legacy的,这里不会描述。

另外,虽然是“启动管理”,但是这里的“启动”并不都是“启动操作系统”的意思,代码操作的也不叫“启动项”,而是“加载项”(Load Option),后面文档中出现的“启动”也并不一定是启动操作系统的意思,也可能仅仅是加载一个UEFI应用或UEFI驱动。

启动一般流程

以下是《UEFI Spec》中的一般规定:

  • 如果OsIndications指定了要执行恢复操作,则不会进入通常的启动流程,而是进入恢复选项。
  • Driver####会优先于Boot####执行。
  • 执行Boot加载项时,先执行BootNext对应的加载项,然后按照BootOrder中的顺序执行Boot####
  • 如果BootNextBoot####中的执行都失败了,则进入启动项恢复操作,主要就是PlatformRecovery####

实际上真实的BIOS中,其实现可以有很多中,因此并不完全按照上述的规则。比如最后一步BootNextBoot####中的执行都失败,一般会选择进入Setup,而不是PlatformRecovery####

启动管理变量

  1. 真正描述加载项的变量:
变量名作用域说明
Boot####NV、BS、RTA boot load option.
Driver####NV、BS、RTA driver load option.
SysPrep####NV、BS、RTA System Prep application load option containing a EFI_LOAD_OPTION descriptor.
OsRecovery####NV、BS、RT
PlatformRecovery####NV、BS、RTPlatform-specified recovery options. These variables are only modified by firmware and are read-only to the OS.

需要注意这些变量的名称是Load Option,并不是叫启动项,虽然流程上差不多,但是很多并不是为了启动操作系统,而是一些额外的操作:

  • Boot####:这些算是普通启动时的启动项。
  • Driver####:这些是用来加载驱动的。
  • SysPrep####:对应的时UEFI应用,用来为系统启动做准备的,它们会在Boot####之前执行。
  • PlatformRecovery####:这些是在最后执行的,所以其它的启动都失败之后就会执行这些。

这四种类型对应到代码中:

//
// Load Option Type
//
typedef enum {
  LoadOptionTypeDriver,
  LoadOptionTypeSysPrep,
  LoadOptionTypeBoot,
  LoadOptionTypePlatformRecovery,
  LoadOptionTypeMax
} EFI_BOOT_MANAGER_LOAD_OPTION_TYPE;

有几点需要注意的:

  • Boot####Driver####是正常启动的时候都是执行的。
  • 启动恢复项有两类,PlatformRecovery####OsRecovery####,后者没有出现在《UEFI Spec》的“Table 10. Global Variables”中,因为它使用的是其它的GUID(称为Vendor Specific VendorGuid)。

上述的变量因为有多个,所以还有一个顺序关系,对应到一个变量:

变量名作用域说明
BootOrderNV、BS、RTThe ordered boot option load list.
DriverOrderNV、BS、RTThe ordered driver load option list.
SysPrepOrderNV、BS、RTThe ordered System Prep Application load option list.
OsRecoveryOrderNV、BS、RTOS-specified recovery options.

但是没有PlatformRecoveryOrder,可以认为只有一个PlatformRecovery应用,所以不需要顺序吧。

另外OsRecoveryOrder出现在《UEFI Spec》的“Table 10. Global Variables”中也比较奇怪,因为前面已经说了它应该属于VendorGuid的变量才对,并且OsRecoveryOrder也没有出现在EDK代码中。

  1. 启动相关的变量:
变量名作用域说明
BootCurrentBS、RTThe boot option that was selected for the current boot.
BootNextNV、BS、RTThe boot option for the next boot only.

BootCurrent因为是随时可变的,所以不会存放到非易失变量中。

  1. 配置相关的变量:
变量名作用域说明
BootOptionSupportBS、RTThe types of boot options supported by the boot manager. Should be treated as read-only.
OsIndicationsNV、BS、RTAllows the OS to request the firmware to enable certain features and to take certain actions.
OsIndicationsSupportedBS、RTAllows the firmware to indicate supported features and actions to the OS.

BootOptionSupport对应的取值:

#define EFI_BOOT_OPTION_SUPPORT_KEY      0x00000001
#define EFI_BOOT_OPTION_SUPPORT_APP      0x00000002
#define EFI_BOOT_OPTION_SUPPORT_SYSPREP  0x00000010
#define EFI_BOOT_OPTION_SUPPORT_COUNT    0x00000300

这表示的其实是启动管理的能力级,其能力说明如下:

  • EFI_BOOT_OPTION_SUPPORT_KEY置位表示Boot####可以通过快捷键启动。
  • EFI_BOOT_OPTION_SUPPORT_APP置位表示支持启动带LOAD_OPTION_CATEGORY_APP属性的项。
  • EFI_BOOT_OPTION_SUPPORT_SYSPREP置位表示支持启动SysPrep####
  • EFI_BOOT_OPTION_SUPPORT_COUNT指定了快捷键支持的按键数。

OsIndicationsSupported表示BIOS告知OS的BIOS所支持的特性,而OsIndications是OS告知BIOS的目前使用的特性。所以OsIndicationsOsIndicationsSupported的一个子集,目前支持的值有:

//
// Firmware should stop at a firmware user interface on next boot
//
#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI                    0x0000000000000001
#define EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION             0x0000000000000002
#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED  0x0000000000000004
#define EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED            0x0000000000000008
#define EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED     0x0000000000000010
#define EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY          0x0000000000000040
#define EFI_OS_INDICATIONS_JSON_CONFIG_DATA_REFRESH         0x0000000000000080

其中有一些跟启动有关:

  • EFI_OS_INDICATIONS_BOOT_TO_FW_UI:表示进入启动管理菜单。
  • EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY:表示进入到平台恢复项。

启动项结构体

其结构体位于edk2\MdePkg\Include\Uefi\UefiSpec.h:

#pragma pack(1)
typedef struct _EFI_LOAD_OPTION {
  ///
  /// The attributes for this load option entry. All unused bits must be zero
  /// and are reserved by the UEFI specification for future growth.
  ///
  UINT32    Attributes;
  ///
  /// Length in bytes of the FilePathList. OptionalData starts at offset
  /// sizeof(UINT32) + sizeof(UINT16) + StrSize(Description) + FilePathListLength
  /// of the EFI_LOAD_OPTION descriptor.
  ///
  UINT16    FilePathListLength;
  ///
  /// The user readable description for the load option.
  /// This field ends with a Null character.
  ///
  // CHAR16                        Description[];
  ///
  /// A packed array of UEFI device paths. The first element of the array is a
  /// device path that describes the device and location of the Image for this
  /// load option. The FilePathList[0] is specific to the device type. Other
  /// device paths may optionally exist in the FilePathList, but their usage is
  /// OSV specific. Each element in the array is variable length, and ends at
  /// the device path end structure. Because the size of Description is
  /// arbitrary, this data structure is not guaranteed to be aligned on a
  /// natural boundary. This data structure may have to be copied to an aligned
  /// natural boundary before it is used.
  ///
  // EFI_DEVICE_PATH_PROTOCOL      FilePathList[];
  ///
  /// The remaining bytes in the load option descriptor are a binary data buffer
  /// that is passed to the loaded image. If the field is zero bytes long, a
  /// NULL pointer is passed to the loaded image. The number of bytes in
  /// OptionalData can be computed by subtracting the starting offset of
  /// OptionalData from total size in bytes of the EFI_LOAD_OPTION.
  ///
  // UINT8                         OptionalData[];
} EFI_LOAD_OPTION;
#pragma pack()

其成员说明如下(注意代码中后面三个成员注释掉了,但是并不表示它们不存在,只是因为Description的长度是不确定的,所以后面成员没有固定位置,导致这个结构体是不定长结构体):

  • Attributes:启动项的属性,包括:
//
// EFI Load Options Attributes
//
#define LOAD_OPTION_ACTIVE           0x00000001	// 该属性决定启动管理会不会自动从这个启动项启动
#define LOAD_OPTION_FORCE_RECONNECT  0x00000002	// 如果DRIVER####类型的启动项有该属性,则当所有DRIVER####类型的启动项执行完毕之后
											// 会对所有的UEFI Dirver进行disconnect和reconnect
#define LOAD_OPTION_HIDDEN           0x00000008	// 表示这个选项不会出现在启动项选择界面
#define LOAD_OPTION_CATEGORY         0x00001F00	// 这个要结合下面两个一起使用,相当于一个掩码
											// 例如 if ((Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)
#define LOAD_OPTION_CATEGORY_BOOT  0x00000000	// 表示这个启动项是普通启动的一部分
#define LOAD_OPTION_CATEGORY_APP   0x00000100	// 表示这个启动项虽然不用于普通启动,但是可以通过快捷键或者启动选项选择界面启动
  • FilePathListLengthFilePathList的长度,这个成员的存在是为了计算OptionalData在结构体中的偏移,并且根据整个结构体的大小就可以知道OptionalData的大小。
  • Description:描述启动项的字符串,会在启动项选择界面显示,以供选择。
  • FilePathList:一个Device Path数组,第一个成员(即FilePathList[0])是必须的,表示该启动项对应镜像(比如bootx64.efi)所在的设备及位置,BIOS本身只需要使用这一项即可,但是OS可能使用该数组的其它选项。
  • OptionalData:可选的数组,会传递给加载后的镜像。

以上是在《UEFI Spec》中定义的启动项,是作为BOOT####Driver####启动项存放到非易失介质中的就是这个结构体。当启动管理使用这些启动项的时候,会有进一步的扩展:

//
// Common structure definition for DriverOption and BootOption
//
typedef struct {
  //
  // Data read from UEFI NV variables
  //
  UINTN                                OptionNumber;     // #### numerical value, could be LoadOptionNumberUnassigned
  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE    OptionType;       // LoadOptionTypeBoot or LoadOptionTypeDriver
  UINT32                               Attributes;       // Load Option Attributes
  CHAR16                               *Description;     // Load Option Description
  EFI_DEVICE_PATH_PROTOCOL             *FilePath;        // Load Option Device Path
  UINT8                                *OptionalData;    // Load Option optional data to pass into image
  UINT32                               OptionalDataSize; // Load Option size of OptionalData
  EFI_GUID                             VendorGuid;

  //
  // Used at runtime
  //
  EFI_STATUS                           Status;          // Status returned from boot attempt gBS->StartImage ()
  CHAR16                               *ExitData;       // Exit data returned from gBS->StartImage ()
  UINTN                                ExitDataSize;    // Size of ExitData
} EFI_BOOT_MANAGER_LOAD_OPTION;

成员说明如下:

  • OptionNumber:就是####的值。
  • OptionType:启动项的属性,对应的取值:
//
// Load Option Type
//
typedef enum {
  LoadOptionTypeDriver,
  LoadOptionTypeSysPrep,
  LoadOptionTypeBoot,
  LoadOptionTypePlatformRecovery,
  LoadOptionTypeMax
} EFI_BOOT_MANAGER_LOAD_OPTION_TYPE;

实际上就对应到了不同的启动项变量。

  • Attributes:同EFI_LOAD_OPTION中的同名成员变量。
  • Description:同EFI_LOAD_OPTION中的同名成员变量,不过需要注意一个是数组,一个是指针。显然数组才能存放到非易失介质中。
  • FilePath:指向EFI_LOAD_OPTION中的成员FilePathList[0]
  • OptionalData:同EFI_LOAD_OPTION中的同名成员变量。
  • OptionalDataSizeOptionalData的大小。
  • VendorGuid:启动项变量对应的GUID,它一般是固定的EFI_GLOBAL_VARIABLE
  • StatusExitDataExitDataSizegBS->StartImage()的返回值,返回数据和返回数据大小。

启动管理实际上用的更多的是这个结构体。从EFI_LOAD_OPTIONEFI_BOOT_MANAGER_LOAD_OPTION的转变可以参考函数(位于edk2\MdeModulePkg\Library\UefiBootManagerLib\BmLoadOption.c):

/**
  Build the Boot#### or Driver#### option from the VariableName.

  @param  VariableName          Variable name of the load option
  @param  VendorGuid            Variable GUID of the load option
  @param  Option                Return the load option.

  @retval EFI_SUCCESS     Get the option just been created
  @retval EFI_NOT_FOUND   Failed to get the new option

**/
EFI_STATUS
EFIAPI
EfiBootManagerVariableToLoadOptionEx (
  IN CHAR16                            *VariableName,
  IN EFI_GUID                          *VendorGuid,
  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION  *Option
  )

创建启动项

BIOS进入到BDS阶段,其流程中跟启动项有关的操作大致包含如下的内容(edk2\MdeModulePkg\Universal\BdsDxe\BdsEntry.c):

启动项相关变量处理
创建PlatformDefaultBootOption
PlatformBootManagerBeforeConsole
EfiBootManagerStartHotkeyService
PlatformBootManagerAfterConsole
根据启动策略执行各种启动项

当然这只是一个简单的版本,实际上它包含很多变量获取以及根据变量值执行不同的启动策略的操作,不过这里主要关心的是启动项的创建,所以比较重要的是函数PlatformBootManagerBeforeConsole()PlatformBootManagerAfterConsole(),它们是库函数(库名PlatformBootManagerLib),这意味着不同的平台代码可以有自己的实现,在EDK代码中就有很多的不同实现:

在这里插入图片描述

不过无论是哪种实现,创建启动项都是其中很重要的一部分。

启动项的创建依赖于特定的几个Protocol:

  • gEfiBlockIoProtocolGuid
  • gEfiSimpleFileSystemProtocolGuid
  • gEfiLoadFileProtocolGuid

在《UEFI Spec》中只描述了后面两个,但是在EDK代码中会首先处理BlockIoProtocol(不过不同版本的EDK代码可能处理方式也不一样)。由于目前的启动主要是通过BootLoader或者网络启动,所以重要的还是后面两个,SimpleFileSystemProtocol表明了有文件系统可以获取BootLoader然后启动,而LoadFileProtocol说明了有网络可以进行PXE或Http等启动。代码处理主要在如下的函数:

/**
  The function creates boot options for all possible bootable medias in the following order:
  1. Removable BlockIo            - The boot option only points to the removable media
                                    device, like USB key, DVD, Floppy etc.
  2. Fixed BlockIo                - The boot option only points to a Fixed blockIo device,
                                    like HardDisk.
  3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
                                    SimpleFileSystem Protocol, but not supporting BlockIo
                                    protocol.
  4. LoadFile                     - The boot option points to the media supporting
                                    LoadFile protocol.
  Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior

  The function won't delete the boot option not added by itself.
**/
VOID
EFIAPI
EfiBootManagerRefreshAllBootOption (
  VOID
  );

除了Protocol对应的启动设备之后,还有一种常见的启动方式就是进入Setup、启动管理菜单和UEFI Shell,它们也同样是通过创建启动项来完成,下面是创建Shell启动项的一个例子:

  //
  // Register UEFI Shell
  //
  PlatformRegisterFvBootOption (
    &gUefiShellFileGuid,
    L"EFI Internal Shell",
    LOAD_OPTION_ACTIVE
    );

创建启动管理菜单也是要给创建的例子:

    //
    // If not found the BootManagerMenuApp, create it.
    //
    OptionNumber = (UINT16)RegisterBootManagerMenuAppBootOption (&mBootMenuFile, L"UEFI BootManagerMenuApp", (UINTN)-1, FALSE);

最终两者调用的函数都是:

/**
  Initialize a load option.

  @param Option           Pointer to the load option to be initialized.
  @param OptionNumber     Option number of the load option.
  @param OptionType       Type of the load option.
  @param Attributes       Attributes of the load option.
  @param Description      Description of the load option.
  @param FilePath         Device path of the load option.
  @param OptionalData     Optional data of the load option.
  @param OptionalDataSize Size of the optional data of the load option.

  @retval EFI_SUCCESS           The load option was initialized successfully.
  @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
**/
EFI_STATUS
EFIAPI
EfiBootManagerInitializeLoadOption (
  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION    *Option,
  IN  UINTN                              OptionNumber,
  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType,
  IN  UINT32                             Attributes,
  IN  CHAR16                             *Description,
  IN  EFI_DEVICE_PATH_PROTOCOL           *FilePath,
  IN  UINT8                              *OptionalData,
  IN  UINT32                             OptionalDataSize
  );

不过这个函数并不会设置变量,该操作有下面的函数完成:

/**
  This function will register the new Boot####, Driver#### or SysPrep#### option.
  After the *#### is updated, the *Order will also be updated.

  @param  Option            Pointer to load option to add. If on input
                            Option->OptionNumber is LoadOptionNumberUnassigned,
                            then on output Option->OptionNumber is updated to
                            the number of the new Boot####,
                            Driver#### or SysPrep#### option.
  @param  Position          Position of the new load option to put in the ****Order variable.

  @retval EFI_SUCCESS           The *#### have been successfully registered.
  @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.
                                Note: this API only adds new load option, no replacement support.
  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used when the
                                option number specified in the Option is LoadOptionNumberUnassigned.
  @return                       Status codes of gRT->SetVariable ().

**/
EFI_STATUS
EFIAPI
EfiBootManagerAddLoadOptionVariable (
  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION  *Option,
  IN     UINTN                         Position
  )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2143694.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Git rebase 的使用(结合图与案例)

目录 Git rebase 的使用Git rebase 概念Git rebase 原理rebase和merge的选择 Git rebase 的使用 在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase Git rebase 概念 **rebase概念:**用来重新应用提交(commits&#xff09…

Vue2知识点

注意:笔记内容来自网络 1Vue指令 指令是指&#xff1a;带有v-前缀的特殊标签属性 1.1 v-html v-html&#xff08;类似 innerHTML&#xff09; 使用语法&#xff1a;<p v-html"intro">hello</p>&#xff0c;意思是将 intro 值渲染到 p 标签中 类似 i…

神经网络-MNIST数据集训练

文章目录 一、MNIST数据集1.数据集概述2.数据集组成3.文件结构4.数据特点 二、代码实现1.数据加载与预处理2. 模型定义3. 训练和测试函数4.训练和测试结果 三、总结 一、MNIST数据集 MNIST数据集是深度学习和计算机视觉领域非常经典且基础的数据集&#xff0c;它包含了大量的手…

链表的合并,结点逆置,顺序表的高效划分(数据结构作业02)

目录 链表的合并 链表的结点逆置 顺序表的高效划分 链表的合并 已知两个递增有序的单链表A和B&#xff0c;分别表示两个集合。试设计一个算法&#xff0c;用于求出A与B的交集&#xff0c;并存储在C链表中。例如 : La {2&#xff0c;4&#xff0c;6&#xff0c;8}&#xff1b;…

闯关leetcode——28. Find the Index of the First Occurrence in a String

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/description/ 内容 Given two strings needle and haystack, return the index of the first occurrence of needle in haystack, or -1 if …

冒泡排序的C++语言实现(不用std::sort)

自己写一个冒泡排序的代码。 void vSort(std::vector<int> & vec, bool bDescending) {//冒泡排序int iTail vec.size()-1;while(iTail > 0){for(int k 0; k < iTail; k){int f1 vec.at(k);int f2 vec.at(k1);if(f1 < f2){//默认是降序int iTmp vec.a…

为什么大公司不用pandas取代excel?

如果你熟练使用Excel的话&#xff0c;你就会发现有些pandas的功能&#xff0c;在Excel中也可以实现&#xff0c;而且对比下来&#xff0c;Excel操作更简单&#xff0c;从效率上跟pandas更无二致&#xff0c;这样Excel的优势就比较突出了&#xff0c;比如下面使用pandas和Excel分…

【实战篇】幻读是什么,幻读有什么问题?

背景 我们先使用一个小一点儿的表。建表和初始化语句如下&#xff1a; CREATE TABLE t (id int(11) NOT NULL,c int(11) DEFAULT NULL,d int(11) DEFAULT NULL,PRIMARY KEY (id),KEY c (c) ) ENGINEInnoDB; insert into t values(0,0,0),(5,5,5), (10,10,10),(15,15,15),(20,…

2010-2022 CSP-J/普及组T1-T4考点统计

T1考点统计 T2考点统计 T3考点统计 T4考点统计 总结

MOE论文汇总2

TASK-CUSTOMIZED MASKED AUTOENCODER VIA MIXTURE OF CLUSTER-CONDITIONAL Experts 这篇论文提出了一种新颖的自监督学习方法&#xff0c;名为“Mixture of Cluster-conditional Experts (MoCE)”&#xff0c;旨在解决传统Masked Autoencoder (MAE)在不同下游任务中可能遇到的负…

蓝桥杯-STM32G431RBT6(UART解析字符串sscanf和解决串口BUG)

一、C语言常识 printf和sprintf的主要区别在于它们的功能和用途&#xff1a; printf&#xff1a;主要用于将格式化的数据输出到标准输出&#xff08;如屏幕&#xff09;。sprintf&#xff1a;则是将格式化的数据存储到一个指定的字符串缓冲区中&#xff0c;而不是直接输出。 pr…

Docker实操:安装MySQL5.7详解(保姆级教程)

介绍 Docker 中文网址: https://www.dockerdocs.cn Docker Hub官方网址&#xff1a;https://hub.docker.com Docker Hub中MySQL介绍&#xff1a;https://hub.docker.com/_/mysql ​ 切换到“Tags”页面&#xff0c;复制指定的MySQL版本拉取命令&#xff0c;例如 &#xff1a…

LabVIEW提高开发效率技巧----使用LabVIEW工具

LabVIEW为开发者提供了多种工具和功能&#xff0c;不仅提高工作效率&#xff0c;还能确保项目的质量和可维护性。以下详细介绍几种关键工具&#xff0c;并结合实际案例说明它们的应用。 1. VI Analyzer&#xff1a;自动检查代码质量 VI Analyzer 是LabVIEW提供的一款强大的工…

架构师,被严重低估的角色!

在企业数字化转型与变革的壮阔浪潮中&#xff0c;企业架构&#xff08;Enterprise Architecture&#xff0c;EA&#xff09;作为一门高度复杂且跨学科的知识体系&#xff0c;无可争议地成为了驱动组织战略深化与技术创新的核心引擎。尽管市场上充斥着丰富的指导理论与参考资料&…

202409012在飞凌的OK3588-C的核心板上使用Rockchip原厂的Buildroot点MIPI屏【背光篇】

202409012在飞凌的OK3588-C的核心板上使用Rockchip原厂的Buildroot点MIPI屏【背光篇】 2024/9/12 10:44 缘起&#xff0c;拿到一块MIPI屏&#xff0c;需要使用飞凌的OK3588-C的核心板在Android12下点亮。 在飞凌的Linux R4下修改部分屏参之后即可直接点亮。 但是在飞凌的Andro…

Java笔记-MinIO Java SDK的使用

此博文内容为&#xff1a; 使用SDK创建bucket&#xff1b; 使用SDK上传文件&#xff1b; 使用SDK下载文件。 maven添加&#xff1a; <dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.2</versi…

Linux使用Clash,clash-for-linux

文件下载 clash-for-linuxhttps://link.zhihu.com/?targethttps%3A//zywang.lanzn.com/ijE2a1m7h6mb&#xff08;百度和阿里云盘都不支持这个文件分享&#xff09;。 使用须知 - 此项目不提供任何订阅信息&#xff0c;请自行准备Clash订阅地址。 - 运行前请手动更改.env文件…

嵌入式开发—CAN通信协议详解与应用(中)

书接上回&#xff1a;嵌入式开发—CAN通信协议详解与应用&#xff08;上&#xff09; 文章目录 CAN通讯中的位时间和位同步位时间的构成采样点 位时间的计算公式时间量子&#xff08;Time Quantum, TQ&#xff09;位时间的阶段示意图位同步机制 CAN通信中的仲裁规则仲裁规则的…

03-Mac系统PyCharm主题设置

目录 1. 打开PyCharm窗口 2. Mac左上角点击PyCharm&#xff0c;点击Settings 3. 点击第一项Appearance& Behavior 4. 点击Appearance 5. 找到Theme进行设置 1. 打开PyCharm窗口 2. Mac左上角点击PyCharm&#xff0c;点击Settings 3. 点击第一项Appearance& Behavi…

【例题】lanqiao4425 咖啡馆订单系统

样例输入 3 2 2 1 3 1 2样例输出 3 2样例说明 输入的数组为&#xff1a;【3&#xff0c;1&#xff0c;2】 增量序列为&#xff1a;【2&#xff0c;1】 当增量 h2&#xff1a;对于每一个索引 i&#xff0c;我们会将数组元素 arr[i] 与 arr[i−h] 进行比较&#xff0c;并进行可…