Linux Kernel: SBI MPXY

⚠️ The code is based on: https://gitlab.com/riseproject/riscv-optee/linux/-/tree/dev-optee-mpxy Commit ID: df5dc01764820f113312f7a39f221b49985bbd7a 1 2 3 4 5 6 7 8 9 10 // arch/riscv/kernel/mpxy-sbi.c struct sbi_mpxy { void *shmem; phys_addr_t shmem_phys_addr; bool active; }; // Define per-cpu varible: sbi_mpxy. DEFINE_PER_CPU(struct sbi_mpxy, sbi_mpxy); do_initcalls() … sbi_mpxy_init() sbi_mpxy_init() Check SBI version and if MPXY extension is supported by OpenSBI. ...

2024/12/31 · 2 分鐘 · 344 字 · Frank Chang

Linux Kernel: OP-TEE Supplicant

⚠️ The code is based on: https://gitlab.com/riseproject/riscv-optee/linux/-/tree/dev-optee-mpxy Commit ID: df5dc01764820f113312f7a39f221b49985bbd7a TEE supplicant /etc/init.d/S30-tee-supplicant /dev/teepriv0 main() process_one_request() process_one_request() read_request() Issue TEE_IOC_SUPPL_RECV ioctl to receive the TEE supplicant request from OP-TEE. This will be blocked until TEE supplicant request is received. Spawn a new thread to process for the new request: thread_main() process_one_request() The original thread will continue to handle the TEE supplicant request from OP-TEE: If RPC command: OPTEE_MSG_RPC_CMD_LOAD_TA: Call load_ta() to load the TA according to the UUID. load_ta() will call TEECI_LoadSecureModule() to load the TA. TEECI_LoadSecureModule() will call fopen(), ftell() to open TA and get the size of TA. If the buffer size (ta_size) is not enough to hold the TA, return the required size to let the caller increase the buffer size and try again. Otherwise, call fread() to read TA and save it to the buffer. … Call write_response() to send the TEE supplicant response to OP-TEE. write_response() Issue TEE_IOC_SUPPL_SEND ioctl to send the TEE supplicant response to OP-TEE. This will unblock Call wait_for_completion_interruptible(**&req->c**) to wait for TEE supplicant to process.

2024/12/28 · 1 分鐘 · 174 字 · Frank Chang

Linux Kernel: OP-TEE

⚠️ The code is based on: https://gitlab.com/riseproject/riscv-optee/linux/-/tree/dev-optee-mpxy Commit ID: df5dc01764820f113312f7a39f221b49985bbd7a OP-TEE provides a pseudo Trusted Application (PTA): drivers/tee/optee/device.c in order to support device enumeration. In other words, OP-TEE driver invokes this application to retrieve a list of Trusted Applications which can be registered as devices on the TEE bus. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 // drivers/tee/optee/optee_private.h /** * struct optee - main service struct * @supp_teedev: supplicant device * @teedev: client device * @ops: internal callbacks for different ways to reach secure * world * @ctx: driver internal TEE context * @smc: specific to SMC ABI * @ffa: specific to FF-A ABI * @call_queue: queue of threads waiting to call @invoke_fn * @notif: notification synchronization struct * @supp: supplicant synchronization struct for RPC to supplicant * @pool: shared memory pool * @rpc_param_count: If > 0 number of RPC parameters to make room for * @scan_bus_done flag if device registation was already done. * @scan_bus_work workq to scan optee bus and register optee drivers */ struct optee { struct tee_device *supp_teedev; struct tee_device *teedev; const struct optee_ops *ops; struct tee_context *ctx; union { struct optee_smc smc; struct optee_ffa ffa; }; struct optee_shm_arg_cache shm_arg_cache; struct optee_call_queue call_queue; struct optee_notif notif; struct optee_supp supp; struct tee_shm_pool *pool; unsigned int rpc_param_count; bool scan_bus_done; struct work_struct scan_bus_work; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // drivers/tee/optee/optee_private.h /** * struct optee_ops - OP-TEE driver internal operations * @do_call_with_arg: enters OP-TEE in secure world * @to_msg_param: converts from struct tee_param to OPTEE_MSG parameters * @from_msg_param: converts from OPTEE_MSG parameters to struct tee_param * * These OPs are only supposed to be used internally in the OP-TEE driver * as a way of abstracting the different methogs of entering OP-TEE in * secure world. */ struct optee_ops { int (*do_call_with_arg)(struct tee_context *ctx, struct tee_shm *shm_arg, u_int offs, bool system_thread); int (*to_msg_param)(struct optee *optee, struct optee_msg_param *msg_params, size_t num_params, const struct tee_param *params); int (*from_msg_param)(struct optee *optee, struct tee_param *params, size_t num_params, const struct optee_msg_param *msg_params); }; do_initcalls() … optee_core_init() optee_core_init() ...

2024/12/26 · 10 分鐘 · 1921 字 · Frank Chang

Linux Kernel: TEE

⚠️ The code is based on: https://gitlab.com/riseproject/riscv-optee/linux/-/tree/dev-optee-mpxy Commit ID: df5dc01764820f113312f7a39f221b49985bbd7a Kernel provides a TEE bus infrastructure where a Trusted Application is represented as a device identified via Universally Unique Identifier (UUID) and client drivers register a table of supported device UUIDs. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 // include/linux/tee_core.h /** * struct tee_device - TEE Device representation * @name: name of device * @desc: description of device * @id: unique id of device * @flags: represented by TEE_DEVICE_FLAG_REGISTERED above * @dev: embedded basic device structure * @cdev: embedded cdev * @num_users: number of active users of this device * @c_no_user: completion used when unregistering the device * @mutex: mutex protecting @num_users and @idr * @idr: register of user space shared memory objects allocated or * registered on this device * @pool: shared memory pool */ struct tee_device { char name[TEE_MAX_DEV_NAME_LEN]; const struct tee_desc *desc; int id; unsigned int flags; struct device dev; struct cdev cdev; size_t num_users; struct completion c_no_users; struct mutex mutex; /* protects num_users and idr */ struct idr idr; struct tee_shm_pool *pool; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // include/linux/tee_core.h /** * struct tee_desc - Describes the TEE driver to the subsystem * @name: name of driver * @ops: driver operations vtable * @owner: module providing the driver * @flags: Extra properties of driver, defined by TEE_DESC_* below */ #define TEE_DESC_PRIVILEGED 0x1 struct tee_desc { const char *name; const struct tee_driver_ops *ops; struct module *owner; u32 flags; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 // include/linux/tee_core.h /** * struct tee_driver_ops - driver operations vtable * @get_version: returns version of driver * @open: called when the device file is opened * @release: release this open file * @open_session: open a new session * @close_session: close a session * @system_session: declare session as a system session * @invoke_func: invoke a trusted function * @cancel_req: request cancel of an ongoing invoke or open * @supp_recv: called for supplicant to get a command * @supp_send: called for supplicant to send a response * @shm_register: register shared memory buffer in TEE * @shm_unregister: unregister shared memory buffer in TEE */ struct tee_driver_ops { void (*get_version)(struct tee_device *teedev, struct tee_ioctl_version_data *vers); int (*open)(struct tee_context *ctx); void (*release)(struct tee_context *ctx); int (*open_session)(struct tee_context *ctx, struct tee_ioctl_open_session_arg *arg, struct tee_param *param); int (*close_session)(struct tee_context *ctx, u32 session); int (*system_session)(struct tee_context *ctx, u32 session); int (*invoke_func)(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, struct tee_param *param); int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session); int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params, struct tee_param *param); int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params, struct tee_param *param); int (*shm_register)(struct tee_context *ctx, struct tee_shm *shm, struct page **pages, size_t num_pages, unsigned long start); int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm); }; 1 2 3 4 5 6 7 8 9 10 11 // include/linux/tee_core.h /** * struct tee_shm_pool - shared memory pool * @ops: operations * @private_data: private data for the shared memory manager */ struct tee_shm_pool { const struct tee_shm_pool_ops *ops; void *private_data; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // include/linux/tee_core.h /** * struct tee_shm_pool_ops - shared memory pool operations * @alloc: called when allocating shared memory * @free: called when freeing shared memory * @destroy_pool: called when destroying the pool */ struct tee_shm_pool_ops { int (*alloc)(struct tee_shm_pool *pool, struct tee_shm *shm, size_t size, size_t align); void (*free)(struct tee_shm_pool *pool, struct tee_shm *shm); void (*destroy_pool)(struct tee_shm_pool *pool); }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // include/linux/tee_drv.h /** * struct tee_context - driver specific context on file pointer data * @teedev: pointer to this drivers struct tee_device * @data: driver specific context data, managed by the driver * @refcount: reference counter for this structure * @releasing: flag that indicates if context is being released right now. * It is needed to break circular dependency on context during * shared memory release. * @supp_nowait: flag that indicates that requests in this context should not * wait for tee-supplicant daemon to be started if not present * and just return with an error code. It is needed for requests * that arises from TEE based kernel drivers that should be * non-blocking in nature. * @cap_memref_null: flag indicating if the TEE Client support shared * memory buffer with a NULL pointer. */ struct tee_context { struct tee_device *teedev; void *data; struct kref refcount; bool releasing; bool supp_nowait; bool cap_memref_null; }; do_initcalls() … tee_init() tee_init() ...

2024/12/24 · 5 分鐘 · 1009 字 · Frank Chang

Linux Kernel: BUILD_BUG_ON_ZERO() / BUILD_BUG_ON_NULL()

之前在 trace Linux Kernel source codes 時發現了兩個很特別的 macros:BUILD_BUG_ON_ZERO() 和 BUILD_BUG_ON_NULL() (定義在:include/linux/kernel.h) 它們的定義如下: 1 2 3 4 5 6 /* Force a compilation error if condition is true, but also produce a result (of value 0 and type size_t), so the expression can be used e.g. in a structure initializer (or where-ever else comma expressions aren't permitted). */ #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) 其中 e 是我們所傳入的判斷式,若判斷式為 true,則會造成 compile error。如此我們便可透過這個 macro 來判斷是否某些錯誤/不應發生的情況 (判斷式) 是否會發生,若會發生則可在 compile-time 的時候就顯示錯誤訊息。 ...

2012/10/14 · 3 分鐘 · 488 字 · Frank Chang

Linux Kernel: ARRAY_SIZE()

通常我們在 C 語言中取得陣列的元數個數可以透過下列的方式來計算: 1 2 3 4 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) int arr[10]; int arr_size = ARRAY_SIZE(arr); 但如同 Jserv 大大在 這篇文章 中所提到:ARRAY_SIZE() 這樣的 macro 其實是陷阱重重… 因為 macro 本身沒辦法做型態檢查,只是單純的將值帶入並展開,而在 C 中我們常常會將指標和陣列混著使用。因此若是我們將指向該陣列的指標傳入,就會得到錯誤的計算結果。 如下面的程式: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) int main(void) { int a[10]; int *a_ptr = a; printf("%d\n", ARRAY_SIZE(a)); printf("%d\n", ARRAY_SIZE(a_ptr)); return 0; } 若傳入陣列 a,則結果會正確顯示 size 大小為 10,但若傳入的是指向陣列 a 的指標 a_ptr,則因為指標的在 32 位元作業系統上大小為 4 bytes (4 / 4) 的結果則會變成 1,而並不是我們所要的答案 10。 ...

2012/10/13 · 3 分鐘 · 589 字 · Frank Chang