cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cma_debug.c (4641B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * CMA DebugFS Interface
      4 *
      5 * Copyright (c) 2015 Sasha Levin <sasha.levin@oracle.com>
      6 */
      7
      8
      9#include <linux/debugfs.h>
     10#include <linux/cma.h>
     11#include <linux/list.h>
     12#include <linux/kernel.h>
     13#include <linux/slab.h>
     14#include <linux/mm_types.h>
     15
     16#include "cma.h"
     17
     18struct cma_mem {
     19	struct hlist_node node;
     20	struct page *p;
     21	unsigned long n;
     22};
     23
     24static int cma_debugfs_get(void *data, u64 *val)
     25{
     26	unsigned long *p = data;
     27
     28	*val = *p;
     29
     30	return 0;
     31}
     32DEFINE_DEBUGFS_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n");
     33
     34static int cma_used_get(void *data, u64 *val)
     35{
     36	struct cma *cma = data;
     37	unsigned long used;
     38
     39	spin_lock_irq(&cma->lock);
     40	/* pages counter is smaller than sizeof(int) */
     41	used = bitmap_weight(cma->bitmap, (int)cma_bitmap_maxno(cma));
     42	spin_unlock_irq(&cma->lock);
     43	*val = (u64)used << cma->order_per_bit;
     44
     45	return 0;
     46}
     47DEFINE_DEBUGFS_ATTRIBUTE(cma_used_fops, cma_used_get, NULL, "%llu\n");
     48
     49static int cma_maxchunk_get(void *data, u64 *val)
     50{
     51	struct cma *cma = data;
     52	unsigned long maxchunk = 0;
     53	unsigned long start, end = 0;
     54	unsigned long bitmap_maxno = cma_bitmap_maxno(cma);
     55
     56	spin_lock_irq(&cma->lock);
     57	for (;;) {
     58		start = find_next_zero_bit(cma->bitmap, bitmap_maxno, end);
     59		if (start >= bitmap_maxno)
     60			break;
     61		end = find_next_bit(cma->bitmap, bitmap_maxno, start);
     62		maxchunk = max(end - start, maxchunk);
     63	}
     64	spin_unlock_irq(&cma->lock);
     65	*val = (u64)maxchunk << cma->order_per_bit;
     66
     67	return 0;
     68}
     69DEFINE_DEBUGFS_ATTRIBUTE(cma_maxchunk_fops, cma_maxchunk_get, NULL, "%llu\n");
     70
     71static void cma_add_to_cma_mem_list(struct cma *cma, struct cma_mem *mem)
     72{
     73	spin_lock(&cma->mem_head_lock);
     74	hlist_add_head(&mem->node, &cma->mem_head);
     75	spin_unlock(&cma->mem_head_lock);
     76}
     77
     78static struct cma_mem *cma_get_entry_from_list(struct cma *cma)
     79{
     80	struct cma_mem *mem = NULL;
     81
     82	spin_lock(&cma->mem_head_lock);
     83	if (!hlist_empty(&cma->mem_head)) {
     84		mem = hlist_entry(cma->mem_head.first, struct cma_mem, node);
     85		hlist_del_init(&mem->node);
     86	}
     87	spin_unlock(&cma->mem_head_lock);
     88
     89	return mem;
     90}
     91
     92static int cma_free_mem(struct cma *cma, int count)
     93{
     94	struct cma_mem *mem = NULL;
     95
     96	while (count) {
     97		mem = cma_get_entry_from_list(cma);
     98		if (mem == NULL)
     99			return 0;
    100
    101		if (mem->n <= count) {
    102			cma_release(cma, mem->p, mem->n);
    103			count -= mem->n;
    104			kfree(mem);
    105		} else if (cma->order_per_bit == 0) {
    106			cma_release(cma, mem->p, count);
    107			mem->p += count;
    108			mem->n -= count;
    109			count = 0;
    110			cma_add_to_cma_mem_list(cma, mem);
    111		} else {
    112			pr_debug("cma: cannot release partial block when order_per_bit != 0\n");
    113			cma_add_to_cma_mem_list(cma, mem);
    114			break;
    115		}
    116	}
    117
    118	return 0;
    119
    120}
    121
    122static int cma_free_write(void *data, u64 val)
    123{
    124	int pages = val;
    125	struct cma *cma = data;
    126
    127	return cma_free_mem(cma, pages);
    128}
    129DEFINE_DEBUGFS_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu\n");
    130
    131static int cma_alloc_mem(struct cma *cma, int count)
    132{
    133	struct cma_mem *mem;
    134	struct page *p;
    135
    136	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
    137	if (!mem)
    138		return -ENOMEM;
    139
    140	p = cma_alloc(cma, count, 0, false);
    141	if (!p) {
    142		kfree(mem);
    143		return -ENOMEM;
    144	}
    145
    146	mem->p = p;
    147	mem->n = count;
    148
    149	cma_add_to_cma_mem_list(cma, mem);
    150
    151	return 0;
    152}
    153
    154static int cma_alloc_write(void *data, u64 val)
    155{
    156	int pages = val;
    157	struct cma *cma = data;
    158
    159	return cma_alloc_mem(cma, pages);
    160}
    161DEFINE_DEBUGFS_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n");
    162
    163static void cma_debugfs_add_one(struct cma *cma, struct dentry *root_dentry)
    164{
    165	struct dentry *tmp;
    166	char name[16];
    167
    168	scnprintf(name, sizeof(name), "cma-%s", cma->name);
    169
    170	tmp = debugfs_create_dir(name, root_dentry);
    171
    172	debugfs_create_file("alloc", 0200, tmp, cma, &cma_alloc_fops);
    173	debugfs_create_file("free", 0200, tmp, cma, &cma_free_fops);
    174	debugfs_create_file("base_pfn", 0444, tmp,
    175			    &cma->base_pfn, &cma_debugfs_fops);
    176	debugfs_create_file("count", 0444, tmp, &cma->count, &cma_debugfs_fops);
    177	debugfs_create_file("order_per_bit", 0444, tmp,
    178			    &cma->order_per_bit, &cma_debugfs_fops);
    179	debugfs_create_file("used", 0444, tmp, cma, &cma_used_fops);
    180	debugfs_create_file("maxchunk", 0444, tmp, cma, &cma_maxchunk_fops);
    181
    182	cma->dfs_bitmap.array = (u32 *)cma->bitmap;
    183	cma->dfs_bitmap.n_elements = DIV_ROUND_UP(cma_bitmap_maxno(cma),
    184						  BITS_PER_BYTE * sizeof(u32));
    185	debugfs_create_u32_array("bitmap", 0444, tmp, &cma->dfs_bitmap);
    186}
    187
    188static int __init cma_debugfs_init(void)
    189{
    190	struct dentry *cma_debugfs_root;
    191	int i;
    192
    193	cma_debugfs_root = debugfs_create_dir("cma", NULL);
    194
    195	for (i = 0; i < cma_area_count; i++)
    196		cma_debugfs_add_one(&cma_areas[i], cma_debugfs_root);
    197
    198	return 0;
    199}
    200late_initcall(cma_debugfs_init);