K1的TCM对单次申请的空间大小是否有尺寸要求?当我先申请32KB并释放,再申请512KB空间时,会稳定触发一个Oops。假如我先申请的是64KB或128KB,则不会产生这个问题。
Oops信息如下:
[ 274.717106] Unable to handle kernel access to user memory without uaccess routines at virtual address 0000000000060010
[ 274.727961] Oops [#1]
[ 274.730253] Modules linked in: algif_hash algif_skcipher af_alg 8852bs binfmt_misc sch_fq_codel ip_tables autofs4
[ 274.740637] CPU: 1 PID: 1707 Comm: tcm-crash Not tainted 6.6.63 #2.2.7.2
[ 274.747399] Hardware name: spacemit k1-x deb1 board (DT)
[ 274.752755] epc : add_node.isra.0+0x30/0x120
[ 274.757052] ra : node_fission.isra.0+0xae/0xe2
[ 274.761611] epc : ffffffff80894dee ra : ffffffff808959ce sp : ffffffc80813bb60
[ 274.768898] gp : ffffffff82301cf8 tp : ffffffd90e790000 t0 : 0000000000000003
[ 274.776165] t1 : ffffffc80813bc78 t2 : 0000000000000002 s0 : ffffffc80813bb80
[ 274.783443] s1 : ffffffd904889c38 a0 : ffffffd904889c38 a1 : ffffffd904889c20
[ 274.790709] a2 : ffffffff81b1dfb8 a3 : ffffffd90eb3a800 a4 : 0000000000000000
[ 274.797975] a5 : 0000000000060000 a6 : ffffffd90eb3a800 a7 : 0000000000060fff
[ 274.805240] s2 : ffffffd904889c20 s3 : ffffffd90eadae80 s4 : 0000000000060000
[ 274.812516] s5 : ffffffff81cd6d70 s6 : 0000000000000fff s7 : 0000000000060000
[ 274.819793] s8 : ffffffd904889c00 s9 : 0000000000000000 s10: ffffffd920d3de20
[ 274.827059] s11: fffffffffffff000 t3 : ffffffd904889c00 t4 : ffffffc80813bc78
[ 274.834325] t5 : 0000000000000002 t6 : ffffffff81e016a8
[ 274.839657] status: 0000000200000120 badaddr: 0000000000060010 cause: 000000000000000d
[ 274.847620] [<ffffffff80894dee>] add_node.isra.0+0x30/0x120
[ 274.853249] [<ffffffff808959ce>] node_fission.isra.0+0xae/0xe2
[ 274.859117] [<ffffffff80895b62>] tcm_mmap+0x160/0x30a
[ 274.864199] [<ffffffff801d4304>] mmap_region+0x1d6/0x698
[ 274.869550] [<ffffffff801d49e0>] do_mmap+0x21a/0x3a8
[ 274.874560] [<ffffffff801adf26>] vm_mmap_pgoff+0xb4/0x138
[ 274.879994] [<ffffffff801d1ab2>] ksys_mmap_pgoff+0x11e/0x178
[ 274.885689] [<ffffffff800054a0>] __riscv_sys_mmap+0x2a/0x36
[ 274.891304] [<ffffffff81017c0a>] do_trap_ecall_u+0x114/0x128
[ 274.897003] [<ffffffff810213f2>] ret_from_exception+0x0/0x6e
[ 274.902719] Code: 0363 0cf5 611c 0c63 02f5 6998 a021 639c 8763 02f4 (6b88) 7ce3
[ 274.910505] ---[ end trace 0000000000000000 ]---
[ 274.911614] kauditd_printk_skb: 115 callbacks suppressed
[ 274.911626] audit: type=1400 audit(1772776417.007:127): apparmor="DENIED" operation="open" class="file" profile="rsyslogd" name="/run/systemd/sessions/" pid=836 comm=72733A6D61696E20513A526567 requested_mask="r" denied_mask="r" fsuid=102 ouid=0
[ 274.942452] audit: type=1400 audit(1772776417.007:128): apparmor="DENIED" operation="open" class="file" profile="rsyslogd" name="/run/systemd/sessions/" pid=836 comm=72733A6D61696E20513A526567 requested_mask="r" denied_mask="r" fsuid=102 ouid=0
复现代码如下:
/// ==== BEGIN list.h ====
#ifndef __AIMM_LIST_H__
#define __AIMM_LIST_H__
#ifdef __cplusplus
extern "C" {
#endif
struct list_head {
struct list_head *next, *prev;
};
#define offsetof(type, member) ((size_t)&(((type *)0)->member))
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
#define list_entry(ptr, type, member) container_of(ptr, type, member)
#define list_first_entry(ptr, type, member) list_entry((ptr)->next, type, member)
#define list_next_entry(pos, member) list_entry((pos)->member.next, typeof(*(pos)), member)
#define list_for_each_entry(pos, head, member) for (pos = list_first_entry(head, typeof(*pos), member); &pos->member != (head); pos = list_next_entry(pos, member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member), n = list_next_entry(pos, member); &pos->member != (head); pos = n, n = list_next_entry(n, member))
#define list_prev_entry(pos, member) list_entry((pos)->member.prev, typeof(*(pos)), member)
static inline int list_empty(const struct list_head *head) { return head->next == head; }
static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; }
static void __list_add(struct list_head *node, struct list_head *prev, struct list_head *next) {
node->next = next;
node->prev = prev;
prev->next = node;
next->prev = node;
}
static void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); }
static void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); }
static void list_del(struct list_head *node) {
struct list_head *prev = node->prev;
struct list_head *next = node->next;
prev->next = next;
next->prev = prev;
}
static inline void INIT_LIST_HEAD(struct list_head *list) {
list->next = list;
list->prev = list;
}
#ifdef __cplusplus
}
#endif
#endif
/// ==== END list.h ====
/// ==== BEGIN tcm.c ====
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define TCM_NAME "tcm"
#define IOC_MAGIC 'c'
#define TCM_MEM_SHOW _IOR(IOC_MAGIC, 2, int)
#define TCM_VA_TO_PA _IOR(IOC_MAGIC, 4, int)
#define TCM_REQUEST_MEM _IOR(IOC_MAGIC, 5, int)
#define TCM_RELEASE_MEM _IOR(IOC_MAGIC, 6, int)
#define tcm_mutex_init() pthread_mutex_init(&tcm.mutex, NULL)
#define tcm_mutex_lock() pthread_mutex_lock(&tcm.mutex)
#define tcm_mutex_try_lock() pthread_mutex_trylock(&tcm.mutex)
#define tcm_mutex_unlock() pthread_mutex_unlock(&tcm.mutex)
#define tcm_mutex_deinit() pthread_mutex_destroy(&tcm.mutex)
#define tcm_check_return_val(X, ret) \
do { \
if (!(X)) { \
printf("tcm check param err--->fun:%s + line:%d", __func__, __LINE__); \
return ret; \
} \
} while (0)
#define tcm_check_return(X) \
do { \
if (!(X)) { \
printf("tcm check param err--->fun:%s + line:%d", __func__, __LINE__); \
return; \
} \
} while (0)
#define timeval_sub(a, b, res) \
do { \
(res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((res)->tv_usec < 0) { \
(res)->tv_sec--; \
(res)->tv_usec += 1000000; \
} \
} while (0)
typedef struct {
struct list_head list;
void *ptr;
size_t size;
} mm_node_t;
typedef struct {
int inited;
int debug;
int fd;
int block_num;
pthread_mutex_t mutex;
struct list_head head;
} tcm_t;
typedef struct {
void *vaddr;
void *paddr;
} va_to_pa_msg_t;
static tcm_t tcm;
static void mem_show(void) { ioctl(tcm.fd, TCM_MEM_SHOW, NULL); }
static int mem_open(void) {
int fd = open("/dev/" TCM_NAME, (O_RDWR | O_SYNC));
if (fd < 0) {
printf("open failed(%d)\n", fd);
return -1;
}
tcm.fd = fd;
return 0;
}
static int mem_close(void) {
close(tcm.fd);
return 0;
}
static int add_node(mm_node_t *node) {
list_add(&node->list, &tcm.head);
return 0;
}
static int del_node(mm_node_t *node) {
list_del(&node->list);
return 0;
}
static mm_node_t *get_node(void *ptr) {
mm_node_t *node;
list_for_each_entry(node, &tcm.head, list) {
if (node->ptr == ptr) {
return node;
}
}
return NULL;
}
static mm_node_t *match_node(void *ptr) {
mm_node_t *node;
list_for_each_entry(node, &tcm.head, list) {
if ((size_t)ptr >= (size_t)node->ptr && (size_t)ptr < ((size_t)node->ptr + node->size)) {
return node;
}
}
return NULL;
}
static void *alloc(size_t size) {
mm_node_t *node = malloc(sizeof(mm_node_t));
if (!node)
return NULL;
void *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, tcm.fd, 0);
if (p == MAP_FAILED) {
free(node);
printf("%s failed(%ld)\n", __func__, size);
return NULL;
}
node->ptr = p;
node->size = size;
tcm_mutex_lock();
add_node(node);
tcm_mutex_unlock();
return p;
}
void *tcm_malloc_sync(size_t size, int timeout) {
tcm_check_return_val(tcm.inited, NULL);
struct timeval now;
struct timeval end;
struct timeval sub;
int remain_wait = timeout;
gettimeofday(&now, NULL);
void *p = alloc(size);
while ((p == NULL) && (timeout != 0)) {
int ret;
struct pollfd events;
events.fd = tcm.fd;
events.events = POLLIN | POLLERR;
if (tcm.debug)
printf("thread(%d) %s timeout:%d(ms)\n", getpid(), __func__, remain_wait);
tcm_mutex_lock();
if (ioctl(tcm.fd, TCM_REQUEST_MEM, &size) < 0) {
tcm_mutex_unlock();
return NULL;
}
ret = poll((struct pollfd *)&events, 1, remain_wait);
if (ret <= 0 && events.revents == POLLERR) {
tcm_mutex_unlock();
break;
}
if (ioctl(tcm.fd, TCM_RELEASE_MEM, &size) < 0) {
tcm_mutex_unlock();
return NULL;
}
tcm_mutex_unlock();
if (tcm.debug)
printf("thread(%d) %s wait\n", getpid(), __func__);
p = alloc(size);
if (p) {
break;
}
if (tcm.debug)
printf("thread(%d) %s failed\n", getpid(), __func__);
if (timeout != -1) {
gettimeofday(&end, NULL);
timeval_sub(&end, &now, &sub);
long elapsed = end.tv_sec * 1000 + end.tv_usec / 1000;
if (elapsed > timeout) {
if (tcm.debug)
printf("thread(%d) %s timeout\n", getpid(), __func__);
break;
} else {
remain_wait = (timeout - elapsed);
}
}
}
return p;
}
void *tcm_malloc(size_t size) {
tcm_check_return_val(tcm.inited, NULL);
return alloc(size);
}
void *tcm_calloc(size_t nmemb, size_t size) {
tcm_check_return_val(tcm.inited, NULL);
return alloc(size * nmemb);
}
void tcm_free(void *ptr) {
tcm_check_return(tcm.inited);
mm_node_t *node = get_node(ptr);
if (!node)
return;
munmap(ptr, node->size);
tcm_mutex_lock();
del_node(node);
tcm_mutex_unlock();
free(node);
}
int is_tcm_mm(void *p) {
mm_node_t *node = match_node(p);
return node ? 0 : -1;
}
void *tcm_va_to_pa(void *va) {
va_to_pa_msg_t msg;
msg.vaddr = va;
if (ioctl(tcm.fd, TCM_VA_TO_PA, &msg) < 0) {
return NULL;
}
return msg.paddr;
}
void tcm_mm_show(void) { mem_show(); }
int tcm_init(void) {
int ret = 0;
if (!tcm.inited) {
ret = mem_open();
if (ret == 0) {
INIT_LIST_HEAD(&tcm.head);
tcm_mutex_init();
tcm.inited = 1;
tcm.debug = 1;
}
}
return ret;
}
int tcm_deinit(void) {
if (tcm.inited) {
mem_close();
tcm_mutex_deinit();
tcm.inited = 0;
return 0;
}
return -1;
}
/// ==== END tcm.c ====
#include <stdio.h>
int error_code;
int sizes_kb[] = {32, 512};
int main() {
if ((error_code = tcm_init())) {
printf("TCM init failed. (Error code is %d)\n", error_code);
return 1;
}
int num_tests = sizeof(sizes_kb) / sizeof(sizes_kb[0]);
for (int i = 0; i < num_tests; i++) {
printf("Running with size = %dKB... ", sizes_kb[i]);
fflush(stdout);
int size = sizes_kb[i] * 1024;
void *buf = tcm_malloc(size);
if (!buf) {
printf("malloc failed\n");
continue;
}
tcm_free(buf);
printf("OK\n");
}
if ((error_code = tcm_deinit())) {
printf("TCM deinit failed. (Error code is %d)\n", error_code);
return 1;
}
return 0;
}