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:
Ciro Santilli 六四事件 法轮功
2019-05-07 00:00:00 +00:00
parent 26cab92bfc
commit 3d83206461
11 changed files with 127 additions and 87 deletions

View File

@@ -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.

View File

@@ -1,6 +0,0 @@
#include <stdio.h>
int main(void) {
puts("hello");
return 0;
}

1
baremetal/hello.c Symbolic link
View File

@@ -0,0 +1 @@
../lkmc/hello.c

View File

@@ -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

View File

@@ -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
View File

@@ -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);
}

View File

@@ -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
View File

@@ -0,0 +1,9 @@
/* Print hello to stdout ;-) */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
puts("hello");
return EXIT_SUCCESS;
}

View File

@@ -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},
}

View File

@@ -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()

View File

@@ -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__':

View File

@@ -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
View File

@@ -0,0 +1 @@
../../lkmc/hello.c