-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Tom Hromatka says: ==================== sparc64: Add privileged ADI driver ADI is a feature supported on SPARC M7 and newer processors to allow hardware to catch rogue accesses to memory. ADI is supported for data fetches only and not instruction fetches. An app can enable ADI on its data pages, set version tags on them and use versioned addresses to access the data pages. Upper bits of the address contain the version tag. On M7 processors, upper four bits (bits 63-60) contain the version tag. If a rogue app attempts to access ADI enabled data pages, its access is blocked and processor generates an exception. Please see Documentation/sparc/adi.txt for further details. This patchset implements a char driver to read/write ADI versions from privileged user space processes. Intended consumers are makedumpfile and crash. v6: * Addressed a few action items from greg k-h * Added Reviewed-by Greg Kroah-Hartman and Shuah Khan v5: * Fixed MODULE_LICENSE() for adi.c v4: * Fixed messed up subject lines. v3: * Really fixed the copyright headers to use SPDX GPL v2. Really. v2: * Simplified copyright headers * Completely reworked sparc64 selftests Makefiles. Used the android selftests Makefiles as an example * Added run.sh and drivers_test.sh to the sparc64 selftest directory. Used bpf/test_kmod.sh and the android selftests as examples * Minor cleanups in the selftest adi-test.c * Added calls to ksft_test_*() in the adi-test.c ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Showing
10 changed files
with
1,069 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Privileged ADI driver for sparc64 | ||
* | ||
* Author: Tom Hromatka <tom.hromatka@oracle.com> | ||
*/ | ||
#include <linux/kernel.h> | ||
#include <linux/miscdevice.h> | ||
#include <linux/module.h> | ||
#include <linux/proc_fs.h> | ||
#include <linux/slab.h> | ||
#include <linux/uaccess.h> | ||
#include <asm/asi.h> | ||
|
||
#define MAX_BUF_SZ PAGE_SIZE | ||
|
||
static int adi_open(struct inode *inode, struct file *file) | ||
{ | ||
file->f_mode |= FMODE_UNSIGNED_OFFSET; | ||
return 0; | ||
} | ||
|
||
static int read_mcd_tag(unsigned long addr) | ||
{ | ||
long err; | ||
int ver; | ||
|
||
__asm__ __volatile__( | ||
"1: ldxa [%[addr]] %[asi], %[ver]\n" | ||
" mov 0, %[err]\n" | ||
"2:\n" | ||
" .section .fixup,#alloc,#execinstr\n" | ||
" .align 4\n" | ||
"3: sethi %%hi(2b), %%g1\n" | ||
" jmpl %%g1 + %%lo(2b), %%g0\n" | ||
" mov %[invalid], %[err]\n" | ||
" .previous\n" | ||
" .section __ex_table, \"a\"\n" | ||
" .align 4\n" | ||
" .word 1b, 3b\n" | ||
" .previous\n" | ||
: [ver] "=r" (ver), [err] "=r" (err) | ||
: [addr] "r" (addr), [invalid] "i" (EFAULT), | ||
[asi] "i" (ASI_MCD_REAL) | ||
: "memory", "g1" | ||
); | ||
|
||
if (err) | ||
return -EFAULT; | ||
else | ||
return ver; | ||
} | ||
|
||
static ssize_t adi_read(struct file *file, char __user *buf, | ||
size_t count, loff_t *offp) | ||
{ | ||
size_t ver_buf_sz, bytes_read = 0; | ||
int ver_buf_idx = 0; | ||
loff_t offset; | ||
u8 *ver_buf; | ||
ssize_t ret; | ||
|
||
ver_buf_sz = min_t(size_t, count, MAX_BUF_SZ); | ||
ver_buf = kmalloc(ver_buf_sz, GFP_KERNEL); | ||
if (!ver_buf) | ||
return -ENOMEM; | ||
|
||
offset = (*offp) * adi_blksize(); | ||
|
||
while (bytes_read < count) { | ||
ret = read_mcd_tag(offset); | ||
if (ret < 0) | ||
goto out; | ||
|
||
ver_buf[ver_buf_idx] = (u8)ret; | ||
ver_buf_idx++; | ||
offset += adi_blksize(); | ||
|
||
if (ver_buf_idx >= ver_buf_sz) { | ||
if (copy_to_user(buf + bytes_read, ver_buf, | ||
ver_buf_sz)) { | ||
ret = -EFAULT; | ||
goto out; | ||
} | ||
|
||
bytes_read += ver_buf_sz; | ||
ver_buf_idx = 0; | ||
|
||
ver_buf_sz = min(count - bytes_read, | ||
(size_t)MAX_BUF_SZ); | ||
} | ||
} | ||
|
||
(*offp) += bytes_read; | ||
ret = bytes_read; | ||
out: | ||
kfree(ver_buf); | ||
return ret; | ||
} | ||
|
||
static int set_mcd_tag(unsigned long addr, u8 ver) | ||
{ | ||
long err; | ||
|
||
__asm__ __volatile__( | ||
"1: stxa %[ver], [%[addr]] %[asi]\n" | ||
" mov 0, %[err]\n" | ||
"2:\n" | ||
" .section .fixup,#alloc,#execinstr\n" | ||
" .align 4\n" | ||
"3: sethi %%hi(2b), %%g1\n" | ||
" jmpl %%g1 + %%lo(2b), %%g0\n" | ||
" mov %[invalid], %[err]\n" | ||
" .previous\n" | ||
" .section __ex_table, \"a\"\n" | ||
" .align 4\n" | ||
" .word 1b, 3b\n" | ||
" .previous\n" | ||
: [err] "=r" (err) | ||
: [ver] "r" (ver), [addr] "r" (addr), | ||
[invalid] "i" (EFAULT), [asi] "i" (ASI_MCD_REAL) | ||
: "memory", "g1" | ||
); | ||
|
||
if (err) | ||
return -EFAULT; | ||
else | ||
return ver; | ||
} | ||
|
||
static ssize_t adi_write(struct file *file, const char __user *buf, | ||
size_t count, loff_t *offp) | ||
{ | ||
size_t ver_buf_sz, bytes_written = 0; | ||
loff_t offset; | ||
u8 *ver_buf; | ||
ssize_t ret; | ||
int i; | ||
|
||
if (count <= 0) | ||
return -EINVAL; | ||
|
||
ver_buf_sz = min_t(size_t, count, MAX_BUF_SZ); | ||
ver_buf = kmalloc(ver_buf_sz, GFP_KERNEL); | ||
if (!ver_buf) | ||
return -ENOMEM; | ||
|
||
offset = (*offp) * adi_blksize(); | ||
|
||
do { | ||
if (copy_from_user(ver_buf, &buf[bytes_written], | ||
ver_buf_sz)) { | ||
ret = -EFAULT; | ||
goto out; | ||
} | ||
|
||
for (i = 0; i < ver_buf_sz; i++) { | ||
ret = set_mcd_tag(offset, ver_buf[i]); | ||
if (ret < 0) | ||
goto out; | ||
|
||
offset += adi_blksize(); | ||
} | ||
|
||
bytes_written += ver_buf_sz; | ||
ver_buf_sz = min(count - bytes_written, (size_t)MAX_BUF_SZ); | ||
} while (bytes_written < count); | ||
|
||
(*offp) += bytes_written; | ||
ret = bytes_written; | ||
out: | ||
__asm__ __volatile__("membar #Sync"); | ||
kfree(ver_buf); | ||
return ret; | ||
} | ||
|
||
static loff_t adi_llseek(struct file *file, loff_t offset, int whence) | ||
{ | ||
loff_t ret = -EINVAL; | ||
|
||
switch (whence) { | ||
case SEEK_END: | ||
case SEEK_DATA: | ||
case SEEK_HOLE: | ||
/* unsupported */ | ||
return -EINVAL; | ||
case SEEK_CUR: | ||
if (offset == 0) | ||
return file->f_pos; | ||
|
||
offset += file->f_pos; | ||
break; | ||
case SEEK_SET: | ||
break; | ||
} | ||
|
||
if (offset != file->f_pos) { | ||
file->f_pos = offset; | ||
file->f_version = 0; | ||
ret = offset; | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
static const struct file_operations adi_fops = { | ||
.owner = THIS_MODULE, | ||
.llseek = adi_llseek, | ||
.open = adi_open, | ||
.read = adi_read, | ||
.write = adi_write, | ||
}; | ||
|
||
static struct miscdevice adi_miscdev = { | ||
.minor = MISC_DYNAMIC_MINOR, | ||
.name = KBUILD_MODNAME, | ||
.fops = &adi_fops, | ||
}; | ||
|
||
static int __init adi_init(void) | ||
{ | ||
if (!adi_capable()) | ||
return -EPERM; | ||
|
||
return misc_register(&adi_miscdev); | ||
} | ||
|
||
static void __exit adi_exit(void) | ||
{ | ||
misc_deregister(&adi_miscdev); | ||
} | ||
|
||
module_init(adi_init); | ||
module_exit(adi_exit); | ||
|
||
MODULE_AUTHOR("Tom Hromatka <tom.hromatka@oracle.com>"); | ||
MODULE_DESCRIPTION("Privileged interface to ADI"); | ||
MODULE_VERSION("1.0"); | ||
MODULE_LICENSE("GPL v2"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
SUBDIRS := drivers | ||
|
||
TEST_PROGS := run.sh | ||
|
||
.PHONY: all clean | ||
|
||
include ../lib.mk | ||
|
||
all: | ||
@for DIR in $(SUBDIRS); do \ | ||
BUILD_TARGET=$(OUTPUT)/$$DIR; \ | ||
mkdir $$BUILD_TARGET -p; \ | ||
make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ | ||
#SUBDIR test prog name should be in the form: SUBDIR_test.sh \ | ||
TEST=$$DIR"_test.sh"; \ | ||
if [ -e $$DIR/$$TEST ]; then \ | ||
rsync -a $$DIR/$$TEST $$BUILD_TARGET/; \ | ||
fi \ | ||
done | ||
|
||
override define RUN_TESTS | ||
@cd $(OUTPUT); ./run.sh | ||
endef | ||
|
||
override define INSTALL_RULE | ||
mkdir -p $(INSTALL_PATH) | ||
install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) | ||
|
||
@for SUBDIR in $(SUBDIRS); do \ | ||
BUILD_TARGET=$(OUTPUT)/$$SUBDIR; \ | ||
mkdir $$BUILD_TARGET -p; \ | ||
$(MAKE) OUTPUT=$$BUILD_TARGET -C $$SUBDIR INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR install; \ | ||
done; | ||
endef | ||
|
||
override define EMIT_TESTS | ||
echo "./run.sh" | ||
endef | ||
|
||
override define CLEAN | ||
@for DIR in $(SUBDIRS); do \ | ||
BUILD_TARGET=$(OUTPUT)/$$DIR; \ | ||
mkdir $$BUILD_TARGET -p; \ | ||
make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ | ||
done | ||
endef |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
adi-test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
|
||
INCLUDEDIR := -I. | ||
CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g | ||
|
||
TEST_GEN_FILES := adi-test | ||
|
||
all: $(TEST_GEN_FILES) | ||
|
||
$(TEST_GEN_FILES): adi-test.c | ||
|
||
TEST_PROGS := drivers_test.sh | ||
|
||
include ../../lib.mk | ||
|
||
$(OUTPUT)/adi-test: adi-test.c |
Oops, something went wrong.