Далее описывается процедура чтения / записи SCTLR_EL1
из Linux пользовательского режима. Возможно или недостаточно чтение / запись SCTLR_EL1
в работающей Linux системе для возможности очистки sh кеша не получен ответ.
Это, очевидно, небезопасная практика, поскольку она, очевидно, делает нарушить Armv8-a
схему безопасности - не пытайтесь делать это дома , но для целей обучения.
Процедура была выполнена на OrangePi PC2
работающем Armbian Buster (версия ядра была Linux orangepipc2 5.4.28-sunxi64 #20.02.7 SMP Sat Mar 28 17:25:10 CET 2020 aarch64 GNU/Linux
.
Установка последнего ядра / linux заголовки:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install linux-headers-current-sunxi64
sudo shutdown -r now
Компиляция минимально загружаемого модуля ядра с поддержкой procfs
:
Makefile
:
obj-m+=/sctlr_el1.o
KBUILD_DIR=/usr/src/linux-headers-5.4.28-sunxi64
all:
make -C $(KBUILD_DIR) M=$(PWD) modules
# Kernel module clean dependency
clean:
make -C $(KBUILD_DIR) M=$(PWD) clean
install:
insmod sctlr_el1.ko
remove:
rmmod sctlr_el1
sctlr_el1.c
:
// Credits:
//
// minimal kernel module: https://docs.legato.io/17_07/yoctoOutofTreeKernelModule.html
// procfs example: https://gist.github.com/BrotherJing/c9c5ffdc9954d998d1336711fa3a6480
#include<linux/module.h>
#include<linux/init.h>
#include<linux/proc_fs.h>
#include<linux/sched.h>
#include<linux/uaccess.h>
#include<linux/fs.h>
#include<linux/seq_file.h>
#include<linux/slab.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Frant");
MODULE_DESCRIPTION("Minimal kernel module suitable for reading/writing SCTLR_EL1");
MODULE_VERSION("0.0.1");
// write system register SCTLR_EL1 (s3_0_c1_c0_0) with specified value.
static inline void system_write_SCTLR_EL1(uint64_t val)
{
asm volatile("msr s3_0_c1_c0_0 , %0" : : "r" (val));
asm volatile("isb" : : : "memory");
}
// read system register value SCTLR_EL1 (s3_0_c1_c0_0).
static inline uint64_t system_read_SCTLR_EL1(void)
{
uint64_t val;
asm volatile("mrs %0, s3_0_c1_c0_0" : "=r" (val));
return val;
}
static int my_proc_show(struct seq_file *m,void *v) {
uint64_t value = system_read_SCTLR_EL1();
printk(KERN_INFO "Read value <0x%016llx> from SCTLR_EL1.", value);
seq_printf(m,"0x%016llx\n",value);
return 0;
}
static ssize_t my_proc_write(struct file* file,const char __user *buffer,size_t count,loff_t *f_pos){
int rc = -1;
uint64_t value = 0;
char *tmp = kzalloc((count+1),GFP_KERNEL);
if(!tmp)return -ENOMEM;
if(copy_from_user(tmp,buffer,count)){
kfree(tmp);
return EFAULT;
}
rc = kstrtoul (tmp, 0, (unsigned long*) &value);
if (rc != 0) {
printk(KERN_ERR "Value <%s> is invalid.", tmp);
kfree(tmp);
return EFAULT;
}
kfree(tmp);
system_write_SCTLR_EL1(value);
printk(KERN_INFO "Wrote value <0x%016llx> to SCTLR_EL1.", value);
return count;
}
static int my_proc_open(struct inode *inode,struct file *file){
return single_open(file,my_proc_show,NULL);
}
static struct file_operations my_fops={
.owner = THIS_MODULE,
.open = my_proc_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek,
.write = my_proc_write
};
static int __init sctlr_el1_init(void) {
struct proc_dir_entry *entry;
entry = proc_create("SCTLR_EL1",0777,NULL,&my_fops);
if(!entry){
return -1;
} else {
printk(KERN_INFO "Entering sctlr_el1\n");
}
return 0;
}
static void __exit sctlr_el1_exit(void) {
remove_proc_entry("SCTLR_EL1",NULL);
printk(KERN_INFO "Exiting sctlr_el1\n");
}
module_init(sctlr_el1_init);
module_exit(sctlr_el1_exit);
Установка:
make install
insmod sctlr_el1.ko
dmesg
[ 927.217571] sctlr_el1: loading out-of-tree module taints kernel.
[ 927.218556] Entering sctlr_el1
Чтение SCTLR_EL1
cat /proc/SCTLR_EL1
0x0000000034d4d91d
SCTLR_EL1.UCI
в моей системе, похоже, установлено .
Переписываете то же значение:
echo 0x0000000034d4d91d > /proc/SCTLR_EL1
dmesg
[ 1130.967798] Wrote value <0x0000000034d4d91d> to SCTLR_EL1.
Нет эффекта. Запись 0x0
приводит к зависанию система, что означает, что SCTLR_EL1
, вероятно, было обновлено, но это обновление, очевидно, вызвало (ожидаемую) систему cra sh:
echo 0x0 > /proc/SCTLR_EL1