mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-25 11:11:35 +01:00
baremetal: ah, actually nope, it didn't work :-(
Workaround for now. Works on asserts, but not on exit 1. Some other day, maybe. https://github.com/cirosantilli/linux-kernel-module-cheat/issues/59
This commit is contained in:
73
README.adoc
73
README.adoc
@@ -9,7 +9,7 @@
|
||||
:toclevels: 6
|
||||
:toc-title:
|
||||
|
||||
The perfect emulation setup to study and modify the <<linux-kernel>>, kernel modules, <<qemu-buildroot-setup,QEMU>> and <<gem5-buildroot-setup,gem5>>. Highly automated. Thoroughly documented. <<gdb>> and <<kgdb>> just work. Automated <<test-this-repo,tests>>. Powered by <<about-the-qemu-buildroot-setup,Buildroot>>. "Tested" in Ubuntu 18.04 host, x86_64, ARMv7 and ARMv8 guests with kernel v5.0.
|
||||
The perfect emulation setup to study and develop the <<linux-kernel>>, kernel modules, <<qemu-buildroot-setup,QEMU>> and <<userland-assembly,userland>> and <<baremetal-setup,baremetal>> assembly. Highly automated. Thoroughly documented. <<gdb>> and <<kgdb>> just work. Automated <<test-this-repo,tests>>. Powered by <<about-the-qemu-buildroot-setup,Buildroot>> and <<about-the-baremetal-setup,crosstool-NG>>. "Tested" in Ubuntu 18.04 host, x86_64, ARMv7 and ARMv8 guests with kernel v5.0.
|
||||
|
||||
TL;DR: <<qemu-buildroot-setup-getting-started>>
|
||||
|
||||
@@ -3923,37 +3923,6 @@ Error while loading /path/to/linux-kernel-module-cheat/out/userland/default/x86_
|
||||
|
||||
Tested in de77c62c091f6418e73b64e8a0a19639c587a103 + 1.
|
||||
|
||||
=== User mode simulation path_properties
|
||||
|
||||
In order to build and run each example properly, we need some file metadata which is stored in link:path_properties.py[] at `path_properties_tuples`.
|
||||
|
||||
Maybe we should embed it magically into source files directories? But this was easier to implement so we started like this.
|
||||
|
||||
The format is as follows:
|
||||
|
||||
....
|
||||
'path_component': (
|
||||
{'property': value},
|
||||
{
|
||||
'child_path_component':
|
||||
{
|
||||
{'child_property': },
|
||||
{}
|
||||
}
|
||||
}
|
||||
)
|
||||
....
|
||||
|
||||
and as a shortcut, paths that don't have any children can be written directly as:
|
||||
|
||||
.....
|
||||
'path_component': {'property': value}
|
||||
.....
|
||||
|
||||
Properties of parent directories apply to all children.
|
||||
|
||||
Lists coming from parent directories are extended instead of overwritten by children, this is especially useful for C compiler flags.
|
||||
|
||||
== Kernel module utilities
|
||||
|
||||
=== insmod
|
||||
@@ -13957,6 +13926,10 @@ You can then see which tests failed on the test summary report at the end.
|
||||
|
||||
===== Test userland in full system
|
||||
|
||||
TODO: we really need a mechanism to automatically generate the test list automatically e.g. based on <<path-properties>>, currently there are many tests missing, and we have to add everything manually which is very annoying.
|
||||
|
||||
We could just generate it on the fly on the host, and forward it to guest through CLI arguments.
|
||||
|
||||
Run all userland tests from inside full system simulation (i.e. not <<user-mode-simulation>>):
|
||||
|
||||
....
|
||||
@@ -13971,8 +13944,6 @@ Failure is detected by looking for the <<magic-failure-string>>
|
||||
|
||||
Most userland programs that don't rely on kernel modules can also be tested in user mode simulation as explained at: <<user-mode-tests>>.
|
||||
|
||||
TODO: we really need a mechanism to automatically generate the test list much like user-mode-tests, currently there are many tests missing, and we have to add everything manually which is very annoying.
|
||||
|
||||
===== Test GDB
|
||||
|
||||
We have some link:https://github.com/pexpect/pexpect[pexpect] automated tests for the baremetal programs!
|
||||
@@ -14115,6 +14086,40 @@ git submodule update
|
||||
|
||||
TODO broken, fix: An example of Linux kernel commit bisection on gem5 boots can be found at: link:bisect-linux-boot-gem5[].
|
||||
|
||||
[[path-properties]]
|
||||
=== path_properties
|
||||
|
||||
In order to build and run each userland and <<baremetal-setup,baremetal>> example properly, we need per-file metadata such as compiler flags and required number of cores.
|
||||
|
||||
This data is stored is stored in link:path_properties.py[] at `path_properties_tuples`.
|
||||
|
||||
Maybe we should embed it magically into source files directories to make it easier to see? But one big Python dict was easier to implement so we started like this. And it allows factoring chunks out easily.
|
||||
|
||||
The format is as follows:
|
||||
|
||||
....
|
||||
'path_component': (
|
||||
{'property': value},
|
||||
{
|
||||
'child_path_component':
|
||||
{
|
||||
{'child_property': },
|
||||
{}
|
||||
}
|
||||
}
|
||||
)
|
||||
....
|
||||
|
||||
and as a shortcut, paths that don't have any children can be written directly as:
|
||||
|
||||
.....
|
||||
'path_component': {'property': value}
|
||||
.....
|
||||
|
||||
Properties of parent directories apply to all children.
|
||||
|
||||
Lists coming from parent directories are extended instead of overwritten by children, this is especially useful for C compiler flags.
|
||||
|
||||
=== Update a forked submodule
|
||||
|
||||
This is a template update procedure for submodules for which we have some patches on on top of mainline.
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
puts("hello");
|
||||
return 0;
|
||||
}
|
||||
1
baremetal/hello.c
Symbolic link
1
baremetal/hello.c
Symbolic link
@@ -0,0 +1 @@
|
||||
../lkmc/hello.c
|
||||
@@ -63,10 +63,6 @@ int _write(int file, char *ptr, int len) {
|
||||
}
|
||||
|
||||
void _exit(int status) {
|
||||
if (status != 0) {
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||
printf("lkmc_exit_status_%d\n", status);
|
||||
}
|
||||
#if defined(GEM5)
|
||||
LKMC_M5OPS_EXIT;
|
||||
#else
|
||||
|
||||
@@ -136,9 +136,14 @@ Build the baremetal examples with crosstool-NG.
|
||||
in_ext in (self.env['c_ext'], self.env['asm_ext'])
|
||||
):
|
||||
out = os.path.join(out_dir, in_name + self.env['baremetal_build_ext'])
|
||||
print(out)
|
||||
src = os.path.join(self.env['baremetal_source_dir'], in_path)
|
||||
if self.need_rebuild(
|
||||
common_objs_bootloader + [self.env['baremetal_link_script'] + self.env['common_h']],
|
||||
common_objs_bootloader +
|
||||
[
|
||||
src,
|
||||
self.env['baremetal_link_script'],
|
||||
self.env['common_h']
|
||||
],
|
||||
out
|
||||
):
|
||||
self.sh.run_cmd(
|
||||
@@ -150,7 +155,7 @@ Build the baremetal examples with crosstool-NG.
|
||||
'-T', self.env['baremetal_link_script'], LF,
|
||||
] +
|
||||
[
|
||||
os.path.join(self.env['baremetal_source_dir'], in_path), LF,
|
||||
src, LF,
|
||||
] +
|
||||
self.sh.add_newlines(common_objs_bootloader) +
|
||||
cflags_after
|
||||
|
||||
3
lkmc.c
3
lkmc.c
@@ -12,7 +12,8 @@ void lkmc_assert(bool condition) {
|
||||
}
|
||||
|
||||
void lkmc_assert_fail(void) {
|
||||
puts("lkmc_test_fail");
|
||||
printf("%s\n", __func__);
|
||||
puts("lkmc_exit_status_1");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
#include <lkmc.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void atexit_cb(void) {
|
||||
puts("atexit");
|
||||
}
|
||||
|
||||
void onexit_cb(int status, void *arg) {
|
||||
printf("status %d\n", status);
|
||||
}
|
||||
|
||||
void __attribute__ ((constructor)) premain() {
|
||||
printf("premain2()\n");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
atexit(atexit_cb);
|
||||
on_exit(onexit_cb, NULL);
|
||||
lkmc_assert_fail();
|
||||
}
|
||||
|
||||
9
lkmc/hello.c
Normal file
9
lkmc/hello.c
Normal file
@@ -0,0 +1,9 @@
|
||||
/* Print hello to stdout ;-) */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
puts("hello");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -9,7 +9,6 @@ class PathProperties:
|
||||
default_cxx_std = 'c++17'
|
||||
default_properties = {
|
||||
'allowed_archs': None,
|
||||
'allowed_emulators': None,
|
||||
'c_std': default_c_std,
|
||||
'cc_flags': [
|
||||
'-Wall', LF,
|
||||
@@ -42,6 +41,11 @@ class PathProperties:
|
||||
'receives_signal': False,
|
||||
# The script requires a non-trivial argument to be passed to run properly.
|
||||
'requires_argument': False,
|
||||
'requires_dynamic_library': False,
|
||||
'requires_m5ops': False,
|
||||
# gem5 fatal: syscall getcpu (#168) unimplemented.
|
||||
'requires_syscall_getcpu': False,
|
||||
'requires_semihosting': False,
|
||||
# Requires certain of our custom kernel modules to be inserted to run.
|
||||
'requires_kernel_modules': False,
|
||||
# The example requires sudo, which usually implies that it can do something
|
||||
@@ -59,7 +63,6 @@ class PathProperties:
|
||||
'show_time': False,
|
||||
'background': True,
|
||||
},
|
||||
'uses_dynamic_library': False,
|
||||
}
|
||||
|
||||
'''
|
||||
@@ -97,27 +100,37 @@ class PathProperties:
|
||||
self['allowed_archs'] is None or
|
||||
env['arch'] in self['allowed_archs']
|
||||
) and \
|
||||
(
|
||||
self['allowed_emulators'] is None or
|
||||
env['emulator'] in self['allowed_emulators']
|
||||
) and \
|
||||
not (
|
||||
link and
|
||||
self['no_executable']
|
||||
)
|
||||
|
||||
def should_be_tested(self, env):
|
||||
return \
|
||||
self.should_be_built(env) and \
|
||||
not self['interactive'] and \
|
||||
not self['more_than_1s'] and \
|
||||
not self['no_executable'] and \
|
||||
not self['receives_signal'] and \
|
||||
not self['requires_argument'] and \
|
||||
not self['requires_kernel_modules'] and \
|
||||
not self['requires_sudo'] and \
|
||||
not self['skip_run_unclassified'] and \
|
||||
not (self['uses_dynamic_library'] and env['emulator'] == 'gem5')
|
||||
return (
|
||||
self.should_be_built(env) and
|
||||
not self['interactive'] and
|
||||
not self['more_than_1s'] and
|
||||
not self['no_executable'] and
|
||||
not self['receives_signal'] and
|
||||
not self['requires_argument'] and
|
||||
not self['requires_kernel_modules'] and
|
||||
not self['requires_sudo'] and
|
||||
not self['skip_run_unclassified'] and
|
||||
not (
|
||||
env['emulator'] == 'gem5' and
|
||||
(
|
||||
self['requires_dynamic_library'] or
|
||||
self['requires_semihosting'] or
|
||||
self['requires_syscall_getcpu']
|
||||
)
|
||||
) and
|
||||
not (
|
||||
env['emulator'] == 'qemu' and
|
||||
(
|
||||
self['requires_m5ops']
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def update(self, other):
|
||||
other_tmp_properties = other.properties.copy()
|
||||
@@ -185,7 +198,7 @@ freestanding_properties = {
|
||||
],
|
||||
'extra_objs_userland_asm': False,
|
||||
}
|
||||
# See: https://github.com/cirosantilli/linux-kernel-module-cheat#user-mode-simulation-path_properties
|
||||
# See: https://github.com/cirosantilli/linux-kernel-module-cheat#path-properties
|
||||
path_properties_tuples = (
|
||||
PathProperties.default_properties,
|
||||
{
|
||||
@@ -198,16 +211,16 @@ path_properties_tuples = (
|
||||
'arm': (
|
||||
{'allowed_archs': {'arm'}},
|
||||
{
|
||||
'gem5_assert.S': {'allowed_emulators': {'gem5'}},
|
||||
'gem5_assert.S': {'requires_m5ops': True},
|
||||
'multicore.S': {'test_run_args': {'cpus': 2}},
|
||||
'no_bootloader': (
|
||||
{'extra_objs_baremetal_bootloader': False},
|
||||
{
|
||||
'gem5_exit.S': {'allowed_emulators': {'gem5'}},
|
||||
'semihost_exit.S': {'allowed_emulators': {'qemu'}},
|
||||
'gem5_exit.S': {'requires_m5ops': True},
|
||||
'semihost_exit.S': {'requires_semihosting': True},
|
||||
}
|
||||
),
|
||||
'semihost_exit.S': {'allowed_emulators': {'qemu'}},
|
||||
'semihost_exit.S': {'requires_semihosting': True},
|
||||
},
|
||||
|
||||
),
|
||||
@@ -218,11 +231,11 @@ path_properties_tuples = (
|
||||
'no_bootloader': (
|
||||
{'extra_objs_baremetal_bootloader': False},
|
||||
{
|
||||
'gem5_exit.S': {'allowed_emulators': {'gem5'}},
|
||||
'semihost_exit.S': {'allowed_emulators': {'qemu'}},
|
||||
'gem5_exit.S': {'requires_m5ops': True},
|
||||
'semihost_exit.S': {'requires_semihosting': True},
|
||||
}
|
||||
),
|
||||
'semihost_exit.S': {'allowed_emulators': {'qemu'}},
|
||||
'semihost_exit.S': {'requires_semihosting': True},
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -343,7 +356,7 @@ path_properties_tuples = (
|
||||
}
|
||||
),
|
||||
'libs': (
|
||||
{'uses_dynamic_library': True},
|
||||
{'requires_dynamic_library': True},
|
||||
{
|
||||
'libdrm': {'requires_sudo': True},
|
||||
}
|
||||
@@ -359,7 +372,11 @@ path_properties_tuples = (
|
||||
'poweroff.c': {'requires_sudo': True},
|
||||
'proc_events.c': {'requires_sudo': True},
|
||||
'proc_events.c': {'requires_sudo': True},
|
||||
'sched_getaffinity_threads.c': {'more_than_1s': True},
|
||||
'sched_getaffinity.c': {'requires_syscall_getcpu': True},
|
||||
'sched_getaffinity_threads.c': {
|
||||
'requires_syscall_getcpu': True,
|
||||
'more_than_1s': True,
|
||||
},
|
||||
'time_boot.c': {'requires_sudo': True},
|
||||
'virt_to_phys_user.c': {'requires_argument': True},
|
||||
}
|
||||
|
||||
@@ -49,12 +49,16 @@ If given, run only the given tests. Otherwise, run all tests.
|
||||
'baremetal': os.path.relpath(os.path.join(path_abs, in_filename), os.getcwd()),
|
||||
})
|
||||
cur_run_args.update(my_path_properties['test_run_args'])
|
||||
error = thread_pool.submit({
|
||||
test_args = {
|
||||
'expected_exit_status': my_path_properties['exit_status'],
|
||||
'run_args': cur_run_args,
|
||||
'run_obj': self.import_path_main('run'),
|
||||
'test_id': path_relative_root,
|
||||
})
|
||||
}
|
||||
if path_relative_root != os.path.join('baremetal', 'assert_fail.c'):
|
||||
# Workaround fro: https://github.com/cirosantilli/linux-kernel-module-cheat/issues/59
|
||||
test_args['expected_exit_status'] = 0
|
||||
error = thread_pool.submit(test_args)
|
||||
if error is not None:
|
||||
if self.env['quit_on_fail']:
|
||||
raise common.ExitLoop()
|
||||
|
||||
@@ -15,7 +15,7 @@ https://github.com/cirosantilli/linux-kernel-module-cheat#test-userland-in-full-
|
||||
def timed_main(self):
|
||||
run = self.import_path_main('run')
|
||||
run_args = self.get_common_args()
|
||||
run_args['eval_after'] = '/test_all.sh;{};'.format(self.env['userland_quit_cmd'])
|
||||
run_args['eval_after'] = './test_all.sh;{};'.format(self.env['userland_quit_cmd'])
|
||||
self.run_test(run, run_args)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#sanity-checks */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
puts("hello");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
1
userland/c/hello.c
Symbolic link
1
userland/c/hello.c
Symbolic link
@@ -0,0 +1 @@
|
||||
../../lkmc/hello.c
|
||||
Reference in New Issue
Block a user