嵌入式系统:数据大小管理(64 位主机向 32 位设备发送数据)

Embedded systems : data size management (64bits host sending data to a 32bits device)

我正在构建一个 32 位 嵌入式设备,外部参与者可以通过 PKCS#11 接口与之通信。

基本上有 3 个组成部分:

我正在开发设备和主机库,我现在的主要问题是确保与 32 位和 64 位主机应用程序的兼容性。

pkcs11t.h 定义 CK_ULONG :

/* an unsigned value, at least 32 bits long */
typedef unsigned long int CK_ULONG;

问题是 long int 大小在主机(8 字节)和我们的设备(4 字节)上是不一样的。

我很想使用 uint32_t 而不是 unsigned long int。但是 the standard 声明如下:

It follows that many of the data and pointer types will vary somewhat from one environment to another (e.g., a CK_ULONG will sometimes be 32 bits, and sometimes perhaps 64 bits). However, these details should not affect an application, assuming it is compiled with Cryptoki header files consistent with the Cryptoki library to which the application is linked.

主机将向嵌入式设备发送请求,假设主机发送的请求 ID 为 0。嵌入式设备如何知道它是 32 位还是 64 位值?

所以我的问题如下:在 32 位嵌入式设备中处理 64 位数据类型的最佳方法是什么?我正在考虑主机库中的类似内容:

CK_ULONG data = 0x42; // user input, could be anything

#ifdef HOST_64
assert(data <= 4294967295);
#endif

send_data_to_device((uint32_t)data);

但是感觉不对...

您的嵌入式设备大概执行一项服务。此服务需要一个接口。

您需要指定该接口。每个可用的命令、值、操作等都应与可接受的值范围以及错误条件下发生的情况一起记录下来。然后你只需在两边实现规范。

双方的位深度或数据类型无关。如果数据不符合接口要求,则必须转换后才能使用接口。

这里真的没有问题。 您的嵌入式系统仅支持 32 位值。 您将使用一些指定的 link 在系统之间进行通信,我确信这些已经定义好了,例如TCP/IP、RS232等

无论传输层是什么,您都需要定义一个协议来打包您在两个系统之间传输的数据。

此协议应处理数据大小,还应考虑到较大数据类型的数据打包与各个 CPU 的字节顺序之间的任何差异。

例如,您可能认为一个 32 位值在内存中被打包为 [byte1][byte2][byte3][byte4],但实际上它可能被其中一个处理器处理为 [byte3][byte4][byte1][byte2],这意味着您必须主动将数据打包成协议中指定的约定格式,而不是仅仅从内存中复制数据。

如果您的 32 位系统必须支持 64 位值,那么您将需要为其编写自己的处理程序 - 即使将 64 位值解包为两个 32 位值,例如 64bit_value -> 32bit_value_high_bytes + 32bit_value_low_bytes.

您的 64 位系统可以继续支持 64 位,尽管您希望在传输到 32 位系统之前解析的任何值都应根据您的协议进行转换。

如果您提供库代码来执行协议处理,那么我建议所有库函数调用 return 一个错误消息值。

因此您可以在 64 位系统上拥有:

if(send_data_to_device(data) != RESULT_SUCCESS)
{
   // some error handling
}

您的图书馆代码可以是:

int send_data_to_device(ULONG data)
{
    #ifdef HOST_64
       if(data > 4294967295) return RESULT_VALUE_OUT_OF_BOUNDS;
    #endif
    // preform data transport

   return RESULT_SUCCESS;
}

注意事项:

  • 谨慎地将 64 位值转换为 32 位值作为 带正号的 64 位值可以给出带负号的 32 位值。

  • 不要依赖于使用结构和联合在实时数据和打包数据之间切换。