mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-26 03:31:36 +01:00
create userland tests
Fix some more tabs. Parse the "Simulated exit code not 0!" string in gem5 and exit with the proper status
This commit is contained in:
44
README.adoc
44
README.adoc
@@ -3065,6 +3065,32 @@ Step debug also works:
|
||||
;
|
||||
....
|
||||
|
||||
===== gem5 syscall emulation exit status
|
||||
|
||||
As of gem5 7fa4c946386e7207ad5859e8ade0bbfc14000d91, the crappy `se.py` script does not forward the exit status of syscall emulation mode, you can test it with:
|
||||
|
||||
....
|
||||
./run --dry-run --gem5 --userland false --userland-build-id static
|
||||
....
|
||||
|
||||
Source: link:userland/false[].
|
||||
|
||||
Then manually run the generated gem5 CLI, and do:
|
||||
|
||||
....
|
||||
echo $?
|
||||
....
|
||||
|
||||
and the output is always `0`.
|
||||
|
||||
Instead, it just outputs a message to stdout just like for <<m5-fail>>:
|
||||
|
||||
....
|
||||
Simulated exit code not 0! Exit code is 1
|
||||
....
|
||||
|
||||
which we parse in link:run[] and then exit with the correct result ourselves...
|
||||
|
||||
==== User mode vs full system benchmark
|
||||
|
||||
Let's see if user mode runs considerably faster than full system or not.
|
||||
@@ -3125,6 +3151,18 @@ Result on <<p51>> at bad30f513c46c1b0995d3a10c0d9bc2a33dc4fa0:
|
||||
* QEMU user: 45 seconds
|
||||
* QEMU full system: 223 seconds
|
||||
|
||||
=== User mode testing
|
||||
|
||||
Automatically run non-interactive userland tests that don't depend on nay kernel modules:
|
||||
|
||||
....
|
||||
./test-userland
|
||||
....
|
||||
|
||||
Source: link:test-userland[]
|
||||
|
||||
The gem5 tests require building statically with build id `static`, see also: <<gem5-syscall-emulation-mode>>. TODO automate this better.
|
||||
|
||||
== Kernel module utilities
|
||||
|
||||
=== insmod
|
||||
@@ -7390,7 +7428,7 @@ Looks like a more raw alternative to libdrm:
|
||||
....
|
||||
./build-buildroot --config 'BR2_PACKABE_LIBDRI2=y'
|
||||
wget \
|
||||
-O "$(./getvar userland_src_dir)/dri2test.c" \
|
||||
-O "$(./getvar userland_source_dir)/dri2test.c" \
|
||||
https://raw.githubusercontent.com/robclark/libdri2/master/test/dri2test.c \
|
||||
;
|
||||
./build-userland
|
||||
@@ -9551,7 +9589,9 @@ Simulated exit code not 0! Exit code is 1
|
||||
|
||||
and exits with status 0.
|
||||
|
||||
TODO: it used to exit non 0, be like that, but it actually got changed to just print the message. Why? https://gem5-review.googlesource.com/c/public/gem5/+/4880
|
||||
We then parse that string ourselves in link:run[] and exit with the correct status...
|
||||
|
||||
TODO: it used to be like that, but it actually got changed to just print the message. Why? https://gem5-review.googlesource.com/c/public/gem5/+/4880
|
||||
|
||||
`m5 fail` is just a superset of `m5 exit`, which is just:
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include <common.h>
|
||||
|
||||
int main(void) {
|
||||
int i, j, k;
|
||||
i = 1;
|
||||
int i, j, k;
|
||||
i = 1;
|
||||
/* test-gdb-op1 */
|
||||
j = 2;
|
||||
j = 2;
|
||||
/* test-gdb-op2 */
|
||||
k = i + j;
|
||||
k = i + j;
|
||||
/* test-gdb-result */
|
||||
if (k != 3)
|
||||
common_assert_fail();
|
||||
if (k != 3)
|
||||
common_assert_fail();
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
int main(void) {
|
||||
register uint64_t x0 __asm__ ("x0");
|
||||
__asm__ ("mrs x0, CurrentEL;" : : : "%x0");
|
||||
printf("%" PRIu64 "\n", x0 >> 2);
|
||||
return 0;
|
||||
register uint64_t x0 __asm__ ("x0");
|
||||
__asm__ ("mrs x0, CurrentEL;" : : : "%x0");
|
||||
printf("%" PRIu64 "\n", x0 >> 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
int main(void) {
|
||||
register uint32_t r0 __asm__ ("r0");
|
||||
__asm__ ("mrs r0, CPSR" : : : "%r0");
|
||||
printf("%" PRIu32 "\n", r0 & 0x1F);
|
||||
return 0;
|
||||
register uint32_t r0 __asm__ ("r0");
|
||||
__asm__ ("mrs r0, CPSR" : : : "%r0");
|
||||
printf("%" PRIu32 "\n", r0 & 0x1F);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <common.h>
|
||||
|
||||
int main(void) {
|
||||
common_assert_fail();
|
||||
common_assert_fail();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
puts("hello");
|
||||
return 0;
|
||||
puts("hello");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -64,24 +64,24 @@ int _write(int file, char *ptr, int len) {
|
||||
void _exit(int status) {
|
||||
#if defined(GEM5)
|
||||
#if defined(__arm__)
|
||||
__asm__ __volatile__ ("mov r0, #0; mov r1, #0; .inst 0xEE000110 | (0x21 << 16);");
|
||||
__asm__ __volatile__ ("mov r0, #0; mov r1, #0; .inst 0xEE000110 | (0x21 << 16);");
|
||||
#elif defined(__aarch64__)
|
||||
__asm__ __volatile__ ("mov x0, #0; .inst 0XFF000110 | (0x21 << 16);");
|
||||
__asm__ __volatile__ ("mov x0, #0; .inst 0XFF000110 | (0x21 << 16);");
|
||||
#endif
|
||||
#else
|
||||
#if defined(__arm__)
|
||||
__asm__ __volatile__ ("mov r0, #0x18; ldr r1, =#0x20026; svc 0x00123456");
|
||||
#elif defined(__aarch64__)
|
||||
/* TODO actually use the exit value here, just for fun. */
|
||||
/* TODO actually use the exit value here, just for fun. */
|
||||
__asm__ __volatile__ (
|
||||
"mov x1, #0x26\n" \
|
||||
"movk x1, #2, lsl #16\n" \
|
||||
"str x1, [sp,#0]\n" \
|
||||
"mov x0, #0\n" \
|
||||
"str x0, [sp,#8]\n" \
|
||||
"mov x1, sp\n" \
|
||||
"mov w0, #0x18\n" \
|
||||
"hlt 0xf000\n"
|
||||
"mov x1, #0x26\n" \
|
||||
"movk x1, #2, lsl #16\n" \
|
||||
"str x1, [sp,#0]\n" \
|
||||
"mov x0, #0\n" \
|
||||
"str x0, [sp,#8]\n" \
|
||||
"mov x1, sp\n" \
|
||||
"mov w0, #0x18\n" \
|
||||
"hlt 0xf000\n"
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -61,7 +61,7 @@ has the OpenBLAS libraries and headers installed.
|
||||
'make', LF,
|
||||
'-j', str(self.env['nproc']), LF,
|
||||
'ARCH={}'.format(self.env['arch']), LF,
|
||||
'CCFLAGS_SCRIPT={} {}'.format('-I', self.env['userland_src_dir']), LF,
|
||||
'CCFLAGS_SCRIPT={} {}'.format('-I', self.env['userland_source_dir']), LF,
|
||||
'COMMON_DIR={}'.format(self.env['root_dir']), LF,
|
||||
'CC={}'.format(cc), LF,
|
||||
'CXX={}'.format(cxx), LF,
|
||||
@@ -73,7 +73,7 @@ has the OpenBLAS libraries and headers installed.
|
||||
shlex.split(self.env['make_args']) +
|
||||
self.sh.add_newlines([os.path.join(build_dir, os.path.splitext(os.path.split(target)[1])[0]) + self.env['userland_build_ext'] for target in self.env['targets']])
|
||||
),
|
||||
cwd=self.env['userland_src_dir'],
|
||||
cwd=self.env['userland_source_dir'],
|
||||
extra_paths=[self.env['ccache_dir']],
|
||||
)
|
||||
self.sh.copy_dir_if_update_non_recursive(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import argparse
|
||||
import imp
|
||||
import os
|
||||
import sys
|
||||
|
||||
class _Argument:
|
||||
def __init__(
|
||||
@@ -193,6 +194,12 @@ class CliFunction:
|
||||
args = parser.parse_args(args=cli_args)
|
||||
return self(**vars(args))
|
||||
|
||||
def cli_exit(self, *args, **kwargs):
|
||||
'''
|
||||
Same as cli, but also exit the program with int(cli().
|
||||
'''
|
||||
sys.exit(int(self.cli(*args, **kwargs)))
|
||||
|
||||
@staticmethod
|
||||
def get_key(*args, **kwargs):
|
||||
return _Argument.get_key(*args, **kwargs)
|
||||
|
||||
@@ -49,7 +49,7 @@ consts['packages_dir'] = os.path.join(consts['root_dir'], 'buildroot_packages')
|
||||
consts['kernel_modules_subdir'] = 'kernel_modules'
|
||||
consts['kernel_modules_src_dir'] = os.path.join(consts['root_dir'], consts['kernel_modules_subdir'])
|
||||
consts['userland_subdir'] = 'userland'
|
||||
consts['userland_src_dir'] = os.path.join(consts['root_dir'], consts['userland_subdir'])
|
||||
consts['userland_source_dir'] = os.path.join(consts['root_dir'], consts['userland_subdir'])
|
||||
consts['userland_build_ext'] = '.out'
|
||||
consts['include_subdir'] = 'include'
|
||||
consts['include_src_dir'] = os.path.join(consts['root_dir'], consts['include_subdir'])
|
||||
@@ -783,7 +783,7 @@ Use gem5 instead of QEMU. Shortcut for `--emulator gem5`.
|
||||
def resolve_userland(self, path):
|
||||
return self.resolve_executable(
|
||||
path,
|
||||
self.env['userland_src_dir'],
|
||||
self.env['userland_source_dir'],
|
||||
self.env['userland_build_dir'],
|
||||
self.env['userland_build_ext'],
|
||||
)
|
||||
|
||||
30
gem5-shell
30
gem5-shell
@@ -1,17 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
|
||||
import common
|
||||
from shell_helpers import LF
|
||||
|
||||
parser = self.get_argparse(
|
||||
default_args={'gem5':True},
|
||||
argparse_args={'description':'Connect a terminal to a running gem5 instance'}
|
||||
)
|
||||
args = self.setup(parser)
|
||||
sys.exit(self.sh.run_cmd([
|
||||
kwargs['gem5_m5term'], LF,
|
||||
'localhost', LF,
|
||||
str(kwargs['gem5_telnet_port']), LF,
|
||||
]))
|
||||
class Main(common.LkmcCliFunction):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
defaults={
|
||||
'gem5': True,
|
||||
},
|
||||
description='Connect a terminal to a running gem5 instance',
|
||||
)
|
||||
def timed_main(self):
|
||||
return self.sh.run_cmd([
|
||||
self.env['gem5_m5term'],
|
||||
'localhost',
|
||||
str(self.env['gem5_telnet_port']),
|
||||
LF,
|
||||
])
|
||||
|
||||
if __name__ == '__main__':
|
||||
Main().cli_exit()
|
||||
|
||||
33
run
33
run
@@ -343,7 +343,7 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
||||
if self.env['userland'] is not None:
|
||||
cmd.extend([
|
||||
self.env['gem5_se_file'], LF,
|
||||
'-c', self.resolve_userland(self.env['userland']), LF,
|
||||
'--cmd', self.resolve_userland(self.env['userland']), LF,
|
||||
])
|
||||
else:
|
||||
if self.env['gem5_script'] == 'fs':
|
||||
@@ -578,7 +578,8 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
||||
tmux_args += " --baremetal '{}'".format(self.env['baremetal'])
|
||||
if self.env['userland']:
|
||||
tmux_args += " --userland '{}'".format(self.env['userland'])
|
||||
tmux_args += ' {}'.format(self.env['tmux'])
|
||||
if self.env['tmux_args'] is not None:
|
||||
tmux_args += ' {}'.format(self.env['tmux_args'])
|
||||
subprocess.Popen([
|
||||
os.path.join(self.env['root_dir'], 'tmu'),
|
||||
"sleep 2;{} {}".format(tmux_cmd, tmux_args)
|
||||
@@ -599,22 +600,24 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
||||
panic_msg = b'Kernel panic - not syncing'
|
||||
panic_re = re.compile(panic_msg)
|
||||
error_string_found = False
|
||||
exit_status = 0
|
||||
if out_file is not None and not self.env['dry_run']:
|
||||
with open(self.env['termout_file'], 'br') as logfile:
|
||||
for line in logfile:
|
||||
if panic_re.search(line):
|
||||
error_string_found = True
|
||||
if os.path.exists(self.env['guest_terminal_file']):
|
||||
with open(self.env['guest_terminal_file'], 'br') as logfile:
|
||||
lines = logfile.readlines()
|
||||
if lines:
|
||||
last_line = lines[-1]
|
||||
if last_line.rstrip() == self.env['magic_fail_string']:
|
||||
error_string_found = True
|
||||
if error_string_found:
|
||||
self.log_error('simulation error detected by parsing logs')
|
||||
return 1
|
||||
return 0
|
||||
exit_status = 1
|
||||
last_line = line.rstrip()
|
||||
match = re.search(b'Simulated exit code not 0! Exit code is (\d+)', last_line)
|
||||
if match:
|
||||
exit_status = int(match.group(1))
|
||||
if not self.env['userland']:
|
||||
if os.path.exists(self.env['guest_terminal_file']):
|
||||
with open(self.env['guest_terminal_file'], 'br') as logfile:
|
||||
if logfile.readlines()[-1].rstrip() == self.env['magic_fail_string']:
|
||||
exit_status = 1
|
||||
if exit_status != 0:
|
||||
self.log_error('simulation error detected by parsing logs')
|
||||
return exit_status
|
||||
|
||||
if __name__ == '__main__':
|
||||
Main().cli()
|
||||
Main().cli_exit()
|
||||
|
||||
7
test-gdb
7
test-gdb
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import functools
|
||||
import threading
|
||||
import os
|
||||
|
||||
@@ -29,13 +28,15 @@ class Main(common.LkmcCliFunction):
|
||||
arch=arch,
|
||||
background=True,
|
||||
baremetal=test_script_noext,
|
||||
print_time=False,
|
||||
emulator=emulator,
|
||||
wait_gdb=True
|
||||
))
|
||||
run_thread.start()
|
||||
run_gdb(
|
||||
arch=arch, baremetal=test_script_noext, print_time=False, emulator=emulator, test=True
|
||||
arch=arch,
|
||||
baremetal=test_script_noext,
|
||||
emulator=emulator,
|
||||
test=True,
|
||||
)
|
||||
run_thread.join()
|
||||
|
||||
|
||||
47
test-userland
Executable file
47
test-userland
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
|
||||
import common
|
||||
|
||||
class Main(common.LkmcCliFunction):
|
||||
def timed_main(self):
|
||||
run = self.import_path('run').Main()
|
||||
sources = [
|
||||
'add.c',
|
||||
'hello.c',
|
||||
'hello_cpp.cpp',
|
||||
'print_argv.c',
|
||||
]
|
||||
# for emulator in self.env['emulators']:
|
||||
for emulator in ['gem5']:
|
||||
if emulator == 'gem5':
|
||||
extra_args = {
|
||||
'userland_build_id': 'static',
|
||||
}
|
||||
else:
|
||||
extra_args = {}
|
||||
for arch in self.env['all_archs']:
|
||||
if arch == 'x86_64':
|
||||
arch_sources = [
|
||||
'asm_hello'
|
||||
]
|
||||
elif arch == 'aarch64':
|
||||
arch_sources = [
|
||||
'asm_hello'
|
||||
]
|
||||
else:
|
||||
arch_sources = []
|
||||
arch_sources[:] = [os.path.join('arch', arch, arch_source) for arch_source in arch_sources]
|
||||
for source in sources + arch_sources:
|
||||
exit_status = run(
|
||||
arch=arch,
|
||||
userland=source,
|
||||
emulator=emulator,
|
||||
**extra_args,
|
||||
)
|
||||
if exit_status != 0:
|
||||
raise Exception('Test failed: {} {} {} {}'.format(emulator, arch, source, exit_status))
|
||||
|
||||
if __name__ == '__main__':
|
||||
Main().cli()
|
||||
@@ -1 +0,0 @@
|
||||
name: USERLAND
|
||||
13
userland/false.c
Normal file
13
userland/false.c
Normal file
@@ -0,0 +1,13 @@
|
||||
/* Test that emulators forward the exit status properly. */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ret;
|
||||
if (argc == 1) {
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = strtoull(argv[1], NULL, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user