【UEFI实战】BIOS下的JSON
迪丽瓦拉
2025-05-31 02:02:16
0

JSON简述

关于JSON的描述:

  • JSON是存储和传输数据的格式。
  • JSON经常在数据从服务器发送到网页时使用。
  • JSON指的是 JavaScript Object Notation。
  • JSON是轻量级的数据交换格式。
  • JSON独立于语言。
  • JSON是“自描述的”且易于理解。

当数据在浏览器与服务器之间进行交换时,这些数据只能是文本。JSON属于文本,并且我们能够把任何JavaScript对象转换为JSON,然后将JSON发送到服务器。我们也能把从服务器接收到的任何JSON转换为JavaScript对象。

JSON使用JavaScript语法,但是JSON格式是纯文本的。文本可被任何编程语言作为数据来读取和使用。

JSON与BIOS

目前EDK开源的代码中已经有对JSON的使用,它在RedfishPkg中体现:

PS D:\Gitee\edk2-beni\edk2> git submodule
-b64af41c3276f97f0e181920400ee056b9c88037 ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
-f4153a09f87cbb9c826d8fc12c74642bb2d879ea BaseTools/Source/C/BrotliCompress/brotli
-d82e959e621a3d597f1e0d50ff8c2d8b96915fd7 CryptoPkg/Library/OpensslLib/openssl
-f4153a09f87cbb9c826d8fc12c74642bb2d879ea MdeModulePkg/Library/BrotliCustomDecompressLib/brotli
-abfc8ff81df4067f309032467785e06975678f0d MdeModulePkg/Universal/RegularExpressionDxe/oniguruma
-e9ebfa7e77a6bee77df44e096b100e7131044059 RedfishPkg/Library/JsonLib/jansson  # RedfishPkg中包含的子模块
-1cc9cde3448cdd2e000886a26acf1caac2db7cf1 UnitTestFrameworkPkg/Library/CmockaLib/cmocka
-86add13493e5c881d7e4ba77fb91c1f57752b3a4 UnitTestFrameworkPkg/Library/GoogleTestLib/googletest

它是JSON的c语言实现,对应的开源库是https://github.com/akheron/jansson.git。

之所以会在RedfishPkg中,是因为Redfish传输数据的最通用方式就是JSON,为了在BIOS下实现Redfish(目前正式的EDK开源代码中还没有包含),就需要处理JSON。在RedfishPkg中提供了JSON的操作接口,位于RedfishPkg\Include\Library\JsonLib.h,由于涉及到的函数很多,这里就不全部列出。

BIOS下使用JSON

本节介绍在BIOS下使用JSON的示例,最终的代码可以在https://gitee.com/jiangwei0512/edk2-beni.git找到。

  1. 首先创建一个简单的JSON文件(example.json):
{"name": "BENI","age": 18
}

我们会在Shell下操作它,所以需要将它放到FileSystem中,对应FS0:

在这里插入图片描述

  1. 然后在BIOS下包含JsonLib库:
JsonLib|RedfishPkg/Library/JsonLib/JsonLib.inf

该库还依赖于其它的一些库,比如Ucs2Utf8Lib、RedfishCrtLib等,也需要包含进去。

  1. 之后先一个Shell命令来测试该库,对应BeniPkg\DynamicCommand\TestDynamicCommand\TestDynamicCommand.inf。

这里需要注意一个问题,在JsonLib依赖的RedfishCrtLib会使用到另外的一个库BaseSortLib,而这个库Shell应用也需要用到(实际使用的是SortLib,但是两者对应的是一样的接口,但是实现不同),两者使用的是不同的代码实现,这导致了Shell命令需要使用的StringNoCaseCompare()被ASSERT,导致使用异常,这里的解决方式是修改RedfishCrtLib的实现(对应RedfishPkg\PrivateLibrary\RedfishCrtLib\RedfishCrtLib.inf):

[LibraryClasses]BaseLibSortLib	# 使用SortLib而不是BaseSortLibDebugLibMemoryAllocationLibUefiRuntimeServicesTableLib
  1. 之后就是代码的具体实现。

这里首先获取文件example.json:

  Status = ShellOpenFileByName (FileName,&FileHandle,EFI_FILE_MODE_READ,0);if (EFI_ERROR (Status)) {DEBUG ((EFI_D_ERROR, "[%a][%d] Failed. - %r\n", __FUNCTION__, __LINE__, Status));goto DONE;}Status = gEfiShellProtocol->GetFileSize (FileHandle, &FileSize);if (EFI_ERROR (Status)) {DEBUG ((EFI_D_ERROR, "[%a][%d] Failed. - %r\n", __FUNCTION__, __LINE__, Status));goto DONE;}Data = AllocateZeroPool (FileSize);if (NULL == Data) {DEBUG ((EFI_D_ERROR, "[%a][%d] Out of memory\n", __FUNCTION__, __LINE__));goto DONE;}Status = ShellReadFile (FileHandle, &FileSize, Data);if (EFI_ERROR (Status)) {DEBUG ((EFI_D_ERROR, "[%a][%d] Failed. - %r\n", __FUNCTION__, __LINE__, Status));return;}

这样就得到了JSON文件的数据。下一步是将数据转换成JSON,这需要使用JsonLib中的JsonLoadBuffer()函数:

  Json = JsonLoadBuffer (Data, FileSize, 0x4, &JsonError);if (NULL == Json) {DEBUG ((EFI_D_ERROR, "[%a][%d] Failed. - %r\n", __FUNCTION__, __LINE__, Status));goto DONE;}Print (L"JsonValueIsObject: %d\r\n", JsonValueIsObject (Json));Print (L"Json: %a\r\n", JsonDumpString (Json, EDKII_JSON_COMPACT));

测试得到的结果:

在这里插入图片描述

可以看到这里已经生成了BIOS下的JSON对象。如果想要得到其中具体的某一项:

  JsonData = JsonObjectGetValue (Json, "name");if (JsonValueIsString (JsonData)) {Print (L"Name: %a\r\n", JsonValueGetAsciiString (JsonData));}

这样就会打印name键对应的值:

在这里插入图片描述

除了读取键值,还可以通过键修改对应的值,比如这里的name

  // Create new JSON object for string.NewData = JsonValueInitAsciiString ("JIANGWEI");if (NULL == NewData) {DEBUG ((EFI_D_ERROR, "[%a][%d] Failed. - %r\n", __FUNCTION__, __LINE__, Status));goto DONE;}// Set JSON value.Status = JsonObjectSetValue (Json, "name", NewData);if (EFI_ERROR (Status)) {DEBUG ((EFI_D_ERROR, "[%a][%d] Failed. - %r\n", __FUNCTION__, __LINE__, Status));goto DONE;}

这里JSON对象就被修改了。如果想要将修改的值保存到文件,目前的JsonLib中似乎没有对应的函数,不过还是可以通过一些处理将数据写入文件:

  FileSize = AsciiStrLen (NewJson);FileData = AllocateZeroPool (FileSize + 2);CopyMem (FileData, JsonDumpString (Json, EDKII_JSON_ENSURE_ASCII), FileSize);FileData[FileSize] = 0xD;FileData[FileSize + 1] = 0xA;FileSize = FileSize + 2;BeniDumpHex (2, 0, FileSize, FileData);Status = ShellWriteFile (FileHandle, &FileSize, FileData);

这里是将字符串转换成了文件内容然后写入文件,区别是字符串以’\0’结尾,而文件最后是换行符(似乎不太对?)。

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...