| // SPDX-License-Identifier: GPL-2.0 |
| |
| // Copyright (C) 2024 Google LLC. |
| |
| use crate::{defs::BinderTransactionDataSg, node::Node, thread::Thread, transaction::Transaction}; |
| |
| use kernel::bindings::{ |
| binder_transaction_data_sg, flat_binder_object, rust_binder_node, rust_binder_thread, |
| rust_binder_transaction, task_struct, |
| }; |
| use kernel::error::Result; |
| use kernel::ffi::{c_int, c_uint, c_ulong}; |
| use kernel::task::{Pid, Task}; |
| use kernel::tracepoint::declare_trace; |
| use kernel::uapi; |
| |
| declare_trace! { |
| unsafe fn binder_ioctl(cmd: c_uint, arg: c_ulong); |
| unsafe fn binder_ioctl_done(ret: c_int); |
| unsafe fn binder_read_done(ret: c_int); |
| unsafe fn binder_write_done(ret: c_int); |
| unsafe fn binder_set_priority(thread: *mut task_struct, desired_prio: c_int, new_prio: c_int); |
| unsafe fn android_vh_rust_binder_set_priority(t: rust_binder_transaction, task: *mut task_struct); |
| unsafe fn android_vh_rust_binder_restore_priority(task: *mut task_struct); |
| unsafe fn binder_wait_for_work(proc_work: bool, transaction_stack: bool, thread_todo: bool); |
| unsafe fn binder_transaction(reply: bool, t: rust_binder_transaction, thread: *mut task_struct); |
| unsafe fn binder_transaction_received(t: rust_binder_transaction); |
| unsafe fn binder_transaction_thread_selected(t: rust_binder_transaction, u: rust_binder_thread); |
| unsafe fn binder_transaction_node_send(t_debug_id: c_int, n: rust_binder_node, |
| orig: *const flat_binder_object, |
| trans: *const flat_binder_object); |
| unsafe fn binder_transaction_fd_send(t_debug_id: c_int, fd: c_int, offset: usize); |
| unsafe fn binder_transaction_fd_recv(t_debug_id: c_int, fd: c_int, offset: usize); |
| unsafe fn binder_transaction_alloc_buf(debug_id: c_int, d: *const binder_transaction_data_sg); |
| unsafe fn binder_transaction_buffer_release(debug_id: c_int); |
| unsafe fn binder_transaction_failed_buffer_release(debug_id: c_int); |
| unsafe fn binder_transaction_update_buffer_release(debug_id: c_int); |
| unsafe fn binder_update_page_range(pid: c_int, allocate: bool, start: usize, end: usize); |
| unsafe fn binder_alloc_lru_start(pid: c_int, page_index: usize); |
| unsafe fn binder_alloc_lru_end(pid: c_int, page_index: usize); |
| unsafe fn binder_free_lru_start(pid: c_int, page_index: usize); |
| unsafe fn binder_free_lru_end(pid: c_int, page_index: usize); |
| unsafe fn binder_alloc_page_start(pid: c_int, page_index: usize); |
| unsafe fn binder_alloc_page_end(pid: c_int, page_index: usize); |
| unsafe fn binder_unmap_user_start(pid: c_int, page_index: usize); |
| unsafe fn binder_unmap_user_end(pid: c_int, page_index: usize); |
| unsafe fn binder_unmap_kernel_start(pid: c_int, page_index: usize); |
| unsafe fn binder_unmap_kernel_end(pid: c_int, page_index: usize); |
| unsafe fn binder_command(cmd: u32); |
| unsafe fn binder_return(ret: u32); |
| } |
| |
| #[inline] |
| fn raw_transaction(t: &Transaction) -> rust_binder_transaction { |
| t as *const Transaction as rust_binder_transaction |
| } |
| |
| #[inline] |
| fn raw_thread(t: &Thread) -> rust_binder_thread { |
| t as *const Thread as rust_binder_thread |
| } |
| |
| #[inline] |
| fn raw_node(n: &Node) -> rust_binder_node { |
| n as *const Node as rust_binder_node |
| } |
| |
| #[inline] |
| fn to_errno(ret: Result) -> i32 { |
| match ret { |
| Ok(()) => 0, |
| Err(err) => err.to_errno(), |
| } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_ioctl(cmd: u32, arg: usize) { |
| // SAFETY: Always safe to call. |
| unsafe { binder_ioctl(cmd, arg as c_ulong) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_ioctl_done(ret: Result) { |
| // SAFETY: Always safe to call. |
| unsafe { binder_ioctl_done(to_errno(ret)) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_read_done(ret: Result) { |
| // SAFETY: Always safe to call. |
| unsafe { binder_read_done(to_errno(ret)) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_write_done(ret: Result) { |
| // SAFETY: Always safe to call. |
| unsafe { binder_write_done(to_errno(ret)) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_set_priority(thread: &Task, desired_prio: c_int, new_prio: c_int) { |
| // SAFETY: The pointer to the task is valid for the duration of this call. |
| unsafe { binder_set_priority(thread.as_ptr(), desired_prio, new_prio) } |
| } |
| |
| #[inline] |
| pub(crate) fn vh_set_priority(t: &Transaction, task: &Task) { |
| // SAFETY: The pointers to `t` and `task` are valid. |
| unsafe { android_vh_rust_binder_set_priority(raw_transaction(t), task.as_ptr()) } |
| } |
| |
| #[inline] |
| pub(crate) fn vh_restore_priority(task: &Task) { |
| // SAFETY: The pointer to `task` is valid. |
| unsafe { android_vh_rust_binder_restore_priority(task.as_ptr()) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_wait_for_work(proc_work: bool, transaction_stack: bool, thread_todo: bool) { |
| // SAFETY: Always safe to call. |
| unsafe { binder_wait_for_work(proc_work, transaction_stack, thread_todo) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction(reply: bool, t: &Transaction, thread: Option<&Task>) { |
| let thread = match thread { |
| Some(thread) => thread.as_ptr(), |
| None => core::ptr::null_mut(), |
| }; |
| // SAFETY: The raw transaction is valid for the duration of this call. The thread pointer is |
| // valid or null. |
| unsafe { binder_transaction(reply, raw_transaction(t), thread) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction_received(t: &Transaction) { |
| // SAFETY: The raw transaction is valid for the duration of this call. |
| unsafe { binder_transaction_received(raw_transaction(t)) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction_thread_selected(t: &Transaction, th: &Thread) { |
| // SAFETY: The raw transaction is valid for the duration of this call. |
| unsafe { binder_transaction_thread_selected(raw_transaction(t), raw_thread(th)) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction_node_send( |
| t_debug_id: usize, |
| n: &Node, |
| orig: &uapi::flat_binder_object, |
| trans: &uapi::flat_binder_object, |
| ) { |
| // CAST: Types are identical. |
| let orig = orig as *const uapi::flat_binder_object as *const flat_binder_object; |
| // CAST: Types are identical. |
| let trans = trans as *const uapi::flat_binder_object as *const flat_binder_object; |
| |
| // SAFETY: The pointers are valid for the duration of this call. |
| unsafe { binder_transaction_node_send(t_debug_id as c_int, raw_node(n), orig, trans) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction_fd_send(t_debug_id: usize, fd: u32, offset: usize) { |
| // SAFETY: This function is always safe to call. |
| unsafe { binder_transaction_fd_send(t_debug_id as c_int, fd as c_int, offset) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction_fd_recv(t_debug_id: usize, fd: u32, offset: usize) { |
| // SAFETY: This function is always safe to call. |
| unsafe { binder_transaction_fd_recv(t_debug_id as c_int, fd as c_int, offset) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction_alloc_buf(debug_id: usize, data: &BinderTransactionDataSg) { |
| let data = data as *const BinderTransactionDataSg; |
| // SAFETY: The `data` pointer is valid. |
| unsafe { binder_transaction_alloc_buf(debug_id as c_int, data.cast()) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction_buffer_release(debug_id: usize) { |
| // SAFETY: Always safe to call. |
| unsafe { binder_transaction_buffer_release(debug_id as c_int) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction_failed_buffer_release(debug_id: usize) { |
| // SAFETY: Always safe to call. |
| unsafe { binder_transaction_failed_buffer_release(debug_id as c_int) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_transaction_update_buffer_release(debug_id: usize) { |
| // SAFETY: Always safe to call. |
| unsafe { binder_transaction_update_buffer_release(debug_id as c_int) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_update_page_range(pid: Pid, allocate: bool, start: usize, end: usize) { |
| // SAFETY: Always safe to call. |
| unsafe { binder_update_page_range(pid as c_int, allocate, start, end) } |
| } |
| |
| macro_rules! define_wrapper_lru_page_class { |
| ($(fn $name:ident;)*) => {$( |
| kernel::macros::paste! { |
| #[inline] |
| pub(crate) fn [< trace_ $name >](pid: Pid, page_index: usize) { |
| // SAFETY: Always safe to call. |
| unsafe { [< binder_ $name >](pid as c_int, page_index) } |
| } |
| } |
| )*} |
| } |
| |
| define_wrapper_lru_page_class! { |
| fn alloc_lru_start; |
| fn alloc_lru_end; |
| fn free_lru_start; |
| fn free_lru_end; |
| fn alloc_page_start; |
| fn alloc_page_end; |
| fn unmap_user_start; |
| fn unmap_user_end; |
| fn unmap_kernel_start; |
| fn unmap_kernel_end; |
| } |
| |
| #[inline] |
| pub(crate) fn trace_command(cmd: u32) { |
| // SAFETY: Trivially safe to call with primitive u32. |
| unsafe { binder_command(cmd) } |
| } |
| |
| #[inline] |
| pub(crate) fn trace_return(ret: u32) { |
| // SAFETY: Trivially safe to call with primitive u32. |
| unsafe { binder_return(ret) } |
| } |