【UEFI实战】BIOS下的JSON

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]
  BaseLib
  SortLib	# 使用SortLib而不是BaseSortLib
  DebugLib
  MemoryAllocationLib
  UefiRuntimeServicesTableLib
  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’结尾,而文件最后是换行符(似乎不太对?)。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值