mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
baremetal: build userland/ programs using baremetal path property instead of symlinks
Otherwise I'll go crazy with symlink action.
This commit is contained in:
73
README.adoc
73
README.adoc
@@ -1206,35 +1206,6 @@ The terminal prints:
|
|||||||
hello
|
hello
|
||||||
....
|
....
|
||||||
|
|
||||||
Now let's run link:baremetal/arch/aarch64/add.S[]:
|
|
||||||
|
|
||||||
....
|
|
||||||
./run --arch aarch64 --baremetal baremetal/arch/aarch64/add.S
|
|
||||||
....
|
|
||||||
|
|
||||||
This time, the terminal does not print anything, which indicates success.
|
|
||||||
|
|
||||||
If you look into the source, you will see that we just have an assertion there.
|
|
||||||
|
|
||||||
You can see a sample assertion fail in link:baremetal/interactive/assert_fail.c[]:
|
|
||||||
|
|
||||||
....
|
|
||||||
./run --arch aarch64 --baremetal baremetal/interactive/assert_fail.c
|
|
||||||
....
|
|
||||||
|
|
||||||
and the terminal contains:
|
|
||||||
|
|
||||||
....
|
|
||||||
lkmc_test_fail
|
|
||||||
error: simulation error detected by parsing logs
|
|
||||||
....
|
|
||||||
|
|
||||||
and the exit status of our script is 1:
|
|
||||||
|
|
||||||
....
|
|
||||||
echo $?
|
|
||||||
....
|
|
||||||
|
|
||||||
To modify a baremetal program, simply edit the file, e.g.
|
To modify a baremetal program, simply edit the file, e.g.
|
||||||
|
|
||||||
....
|
....
|
||||||
@@ -1252,17 +1223,44 @@ and rebuild:
|
|||||||
|
|
||||||
`./build-baremetal` uses crosstool-NG, and so it must be preceded by link:build-crosstool-ng[], which `./build qemu-baremetal` also calls.
|
`./build-baremetal` uses crosstool-NG, and so it must be preceded by link:build-crosstool-ng[], which `./build qemu-baremetal` also calls.
|
||||||
|
|
||||||
Alternatively, for the sake of tab completion, we also accept relative paths inside `baremetal/`, for example the following also work:
|
|
||||||
|
Now let's run link:baremetal/arch/aarch64/add.S[]:
|
||||||
|
|
||||||
....
|
....
|
||||||
./run --arch aarch64 --baremetal baremetal/c/hello.c
|
|
||||||
./run --arch aarch64 --baremetal baremetal/arch/aarch64/add.S
|
./run --arch aarch64 --baremetal baremetal/arch/aarch64/add.S
|
||||||
....
|
....
|
||||||
|
|
||||||
Absolute paths however are used as is and must point to the actual executable:
|
This time, the terminal does not print anything, which indicates success: if you look into the source, you will see that we just have an assertion there.
|
||||||
|
|
||||||
|
You can see a sample assertion fail in link:baremetal/interactive/assert_fail.c[]:
|
||||||
|
|
||||||
....
|
....
|
||||||
./run --arch aarch64 --baremetal "$(./getvar --arch aarch64 baremetal_build_dir)/hello.elf"
|
./run --arch aarch64 --baremetal userland/c/assert_fail.c
|
||||||
|
....
|
||||||
|
|
||||||
|
and the terminal contains:
|
||||||
|
|
||||||
|
....
|
||||||
|
lkmc_test_fail
|
||||||
|
error: simulation error detected by parsing logs
|
||||||
|
....
|
||||||
|
|
||||||
|
and the exit status of our script is 1:
|
||||||
|
|
||||||
|
....
|
||||||
|
echo $?
|
||||||
|
....
|
||||||
|
|
||||||
|
As suggested by the above example, several of the <<userland-content,userland examples>> can also be run in baremetal! This is largely due to the <<about-the-baremetal-setup,awesomeness of Newlib>>.
|
||||||
|
|
||||||
|
The examples that work include most <<c,C examples>> that don't rely on complicated syscalls such as threads, and almost all the <<userland-assembly>> examples.
|
||||||
|
|
||||||
|
The exact list of userland programs that work in baremetal is specified in <<path-properties>> with the `baremetal` property.
|
||||||
|
|
||||||
|
You can run all the baremetal examples in one go and check that all assertions passed with:
|
||||||
|
|
||||||
|
....
|
||||||
|
./test-baremetal --arch aarch64
|
||||||
....
|
....
|
||||||
|
|
||||||
To use gem5 instead of QEMU do:
|
To use gem5 instead of QEMU do:
|
||||||
@@ -11554,6 +11552,9 @@ Programs under link:userland/c/[] are examples of link:https://en.wikipedia.org/
|
|||||||
* Standard library
|
* Standard library
|
||||||
** assert.h
|
** assert.h
|
||||||
*** link:userland/c/assert_fail.c[]
|
*** link:userland/c/assert_fail.c[]
|
||||||
|
** `stdlib.h`
|
||||||
|
*** Exit related
|
||||||
|
**** link:userland/c/abort.c[]
|
||||||
|
|
||||||
Userland assembly content is located at: <<userland-assembly>>. It was split from this section basically becase we were hitting the HTML `h6` limit, stupid web :-)
|
Userland assembly content is located at: <<userland-assembly>>. It was split from this section basically becase we were hitting the HTML `h6` limit, stupid web :-)
|
||||||
|
|
||||||
@@ -11677,7 +11678,7 @@ Other infrastructure sanity checks that you might want to look into include:
|
|||||||
|
|
||||||
* link:userland/arch/empty.S[]
|
* link:userland/arch/empty.S[]
|
||||||
* `LKMC_FAIL` tests
|
* `LKMC_FAIL` tests
|
||||||
** link:userland/arch/fail.S[]
|
** link:userland/arch/lkmc_assert_fail.S[]
|
||||||
* `LKMC_ASSERT_EQ` tests
|
* `LKMC_ASSERT_EQ` tests
|
||||||
** link:userland/arch/x86_64/lkmc_assert_eq_fail.S[]
|
** link:userland/arch/x86_64/lkmc_assert_eq_fail.S[]
|
||||||
** link:userland/arch/arm/lkmc_assert_eq_fail.S[]
|
** link:userland/arch/arm/lkmc_assert_eq_fail.S[]
|
||||||
@@ -13609,8 +13610,8 @@ info threads
|
|||||||
shows something like:
|
shows something like:
|
||||||
|
|
||||||
....
|
....
|
||||||
* 1 Thread 1 (CPU#0 [running]) mystart
|
* 1 Thread 1 (CPU#0 [running]) lkmc_start
|
||||||
2 Thread 2 (CPU#1 [halted ]) mystart
|
2 Thread 2 (CPU#1 [halted ]) lkmc_start
|
||||||
....
|
....
|
||||||
|
|
||||||
To wake up CPU 1 on QEMU, we must use the Power State Coordination Interface (PSCI) which is documented at: link:https://developer.arm.com/docs/den0022/latest/arm-power-state-coordination-interface-platform-design-document[].
|
To wake up CPU 1 on QEMU, we must use the Power State Coordination Interface (PSCI) which is documented at: link:https://developer.arm.com/docs/den0022/latest/arm-power-state-coordination-interface-platform-design-document[].
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <lkmc/m5ops.h>
|
#include <lkmc/m5ops.h>
|
||||||
|
|
||||||
.global mystart
|
.global lkmc_start
|
||||||
mystart:
|
lkmc_start:
|
||||||
LKMC_M5OPS_EXIT_ASM
|
LKMC_M5OPS_EXIT_ASM
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#semihosting */
|
/* https://github.com/cirosantilli/linux-kernel-module-cheat#semihosting */
|
||||||
|
|
||||||
.global mystart
|
.global lkmc_start
|
||||||
mystart:
|
lkmc_start:
|
||||||
mov x1, 0x26
|
mov x1, 0x26
|
||||||
movk x1, 2, lsl 16
|
movk x1, 2, lsl 16
|
||||||
ldr x2, =semihost_args
|
ldr x2, =semihost_args
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
.global mystart
|
.global lkmc_start
|
||||||
mystart:
|
lkmc_start:
|
||||||
mov r0, #0; mov r1, #0; .inst 0xEE000110 | (0x21 << 16);
|
mov r0, #0; mov r1, #0; .inst 0xEE000110 | (0x21 << 16);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.global mystart
|
.global lkmc_start
|
||||||
mystart:
|
lkmc_start:
|
||||||
mov r0, #0x18
|
mov r0, #0x18
|
||||||
ldr r1, =#0x20026
|
ldr r1, =#0x20026
|
||||||
svc 0x00123456
|
svc 0x00123456
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/add.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/add.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/assert_fail.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/hello.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/infinite_loop.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/stderr.c
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <lkmc.h>
|
#include <lkmc.h>
|
||||||
|
|
||||||
.global mystart
|
.global lkmc_start
|
||||||
mystart:
|
lkmc_start:
|
||||||
/* = NEON setup */
|
/* = NEON setup */
|
||||||
mov x1, #(0x3 << 20)
|
mov x1, #(0x3 << 20)
|
||||||
msr cpacr_el1, x1
|
msr cpacr_el1, x1
|
||||||
@@ -20,6 +20,7 @@ mystart:
|
|||||||
bl on_exit
|
bl on_exit
|
||||||
|
|
||||||
/* Run main. */
|
/* Run main. */
|
||||||
|
mov x0, 0
|
||||||
bl main
|
bl main
|
||||||
|
|
||||||
/* If main returns, exit. */
|
/* If main returns, exit. */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <lkmc.h>
|
#include <lkmc.h>
|
||||||
|
|
||||||
.global mystart
|
.global lkmc_start
|
||||||
mystart:
|
lkmc_start:
|
||||||
/* Prepare the stack for main, mandatory for C code. */
|
/* Prepare the stack for main, mandatory for C code. */
|
||||||
ldr sp, =stack_top
|
ldr sp, =stack_top
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ mystart:
|
|||||||
bl on_exit
|
bl on_exit
|
||||||
|
|
||||||
/* Run main. */
|
/* Run main. */
|
||||||
|
mov r0, 0
|
||||||
bl main
|
bl main
|
||||||
|
|
||||||
/* If main returns, exit. */
|
/* If main returns, exit. */
|
||||||
|
|||||||
@@ -5,6 +5,13 @@
|
|||||||
#include <lkmc.h>
|
#include <lkmc.h>
|
||||||
#include <lkmc/m5ops.h>
|
#include <lkmc/m5ops.h>
|
||||||
|
|
||||||
|
void lkmc_baremetal_on_exit_callback(int status, void *arg) {
|
||||||
|
(void)arg;
|
||||||
|
if (status != 0) {
|
||||||
|
printf("lkmc_exit_status_%d\n", status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
UART_FR_RXFE = 0x10,
|
UART_FR_RXFE = 0x10,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
ENTRY(mystart)
|
ENTRY(lkmc_start)
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
.text : {
|
.text : {
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
int main(void) { return 0; }
|
|
||||||
@@ -14,6 +14,7 @@ class Main(common.BuildCliFunction):
|
|||||||
description='''\
|
description='''\
|
||||||
Build the baremetal examples with crosstool-NG.
|
Build the baremetal examples with crosstool-NG.
|
||||||
''',
|
''',
|
||||||
|
is_baremetal=True,
|
||||||
supported_archs=common.consts['crosstool_ng_supported_archs']
|
supported_archs=common.consts['crosstool_ng_supported_archs']
|
||||||
)
|
)
|
||||||
self._add_argument('--ccflags')
|
self._add_argument('--ccflags')
|
||||||
@@ -137,7 +138,10 @@ Build the baremetal examples with crosstool-NG.
|
|||||||
|
|
||||||
def setup_one(self):
|
def setup_one(self):
|
||||||
self.env['targets'] = self.resolve_targets(
|
self.env['targets'] = self.resolve_targets(
|
||||||
self.env['baremetal_source_dir'],
|
[
|
||||||
|
self.env['baremetal_source_dir'],
|
||||||
|
self.env['userland_source_dir']
|
||||||
|
],
|
||||||
self.env['targets']
|
self.env['targets']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Main(common.BuildCliFunction):
|
|||||||
kwargs['description'] = '''\
|
kwargs['description'] = '''\
|
||||||
Build our compiled userland examples.
|
Build our compiled userland examples.
|
||||||
'''
|
'''
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, is_userland=True, **kwargs)
|
||||||
self._add_argument('--ccflags')
|
self._add_argument('--ccflags')
|
||||||
self._add_argument('--force-rebuild')
|
self._add_argument('--force-rebuild')
|
||||||
self._add_argument('--optimization-level')
|
self._add_argument('--optimization-level')
|
||||||
@@ -109,7 +109,7 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
|
|
||||||
def setup_one(self):
|
def setup_one(self):
|
||||||
self.env['targets'] = self.resolve_targets(
|
self.env['targets'] = self.resolve_targets(
|
||||||
self.env['userland_source_dir'],
|
[self.env['userland_source_dir']],
|
||||||
self.env['targets']
|
self.env['targets']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
90
common.py
90
common.py
@@ -162,6 +162,7 @@ class LkmcCliFunction(cli_function.CliFunction):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*args,
|
*args,
|
||||||
|
is_baremetal=False,
|
||||||
is_userland=False,
|
is_userland=False,
|
||||||
defaults=None,
|
defaults=None,
|
||||||
supported_archs=None,
|
supported_archs=None,
|
||||||
@@ -175,7 +176,8 @@ class LkmcCliFunction(cli_function.CliFunction):
|
|||||||
kwargs['extra_config_params'] = os.path.basename(inspect.getfile(self.__class__))
|
kwargs['extra_config_params'] = os.path.basename(inspect.getfile(self.__class__))
|
||||||
if defaults is None:
|
if defaults is None:
|
||||||
defaults = {}
|
defaults = {}
|
||||||
self._is_userland = is_userland
|
self.is_baremetal = is_baremetal
|
||||||
|
self.is_userland = is_userland
|
||||||
self._defaults = defaults
|
self._defaults = defaults
|
||||||
self._is_common = True
|
self._is_common = True
|
||||||
self._common_args = set()
|
self._common_args = set()
|
||||||
@@ -1035,8 +1037,12 @@ lunch aosp_{}-eng
|
|||||||
self._common_args.add(key)
|
self._common_args.add(key)
|
||||||
super().add_argument(*args, **kwargs)
|
super().add_argument(*args, **kwargs)
|
||||||
|
|
||||||
def assert_is_subpath(self, subpath, parent):
|
def assert_is_subpath(self, subpath, parents):
|
||||||
if not self.is_subpath(subpath, parent):
|
is_subpath = False
|
||||||
|
for parent in parents:
|
||||||
|
if self.is_subpath(subpath, parent):
|
||||||
|
is_subpath = True
|
||||||
|
if not is_subpath:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
'Can only accept targets inside {}, given: {}'.format(
|
'Can only accept targets inside {}, given: {}'.format(
|
||||||
parent,
|
parent,
|
||||||
@@ -1204,7 +1210,7 @@ lunch aosp_{}-eng
|
|||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
raise Exception('native emulator only supported in if target arch == host arch')
|
raise Exception('native emulator only supported in if target arch == host arch')
|
||||||
if env['userland'] is None and not self._is_userland:
|
if env['userland'] is None and not self.is_userland:
|
||||||
if real_all_emulators:
|
if real_all_emulators:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
@@ -1314,7 +1320,7 @@ lunch aosp_{}-eng
|
|||||||
def resolve_executable(
|
def resolve_executable(
|
||||||
self,
|
self,
|
||||||
in_path,
|
in_path,
|
||||||
magic_in_dir,
|
magic_in_dirs,
|
||||||
magic_out_dir,
|
magic_out_dir,
|
||||||
executable_ext
|
executable_ext
|
||||||
):
|
):
|
||||||
@@ -1331,35 +1337,47 @@ lunch aosp_{}-eng
|
|||||||
'''
|
'''
|
||||||
if not self.env['dry_run'] and not os.path.exists(in_path):
|
if not self.env['dry_run'] and not os.path.exists(in_path):
|
||||||
raise Exception('Input path does not exist: ' + in_path)
|
raise Exception('Input path does not exist: ' + in_path)
|
||||||
if self.is_subpath(in_path, magic_in_dir):
|
if len(magic_in_dirs) > 1:
|
||||||
# Abspath needed to remove the trailing `/.` which makes e.g. rmrf fail.
|
relative_subpath = self.env['root_dir']
|
||||||
out = os.path.abspath(os.path.join(
|
|
||||||
magic_out_dir,
|
|
||||||
os.path.relpath(
|
|
||||||
os.path.splitext(in_path)[0],
|
|
||||||
magic_in_dir
|
|
||||||
)
|
|
||||||
))
|
|
||||||
if os.path.isfile(in_path):
|
|
||||||
out += executable_ext
|
|
||||||
return out
|
|
||||||
else:
|
else:
|
||||||
return in_path
|
relative_subpath = magic_in_dirs[0]
|
||||||
|
for magic_in_dir in magic_in_dirs:
|
||||||
|
if self.is_subpath(in_path, magic_in_dir):
|
||||||
|
# Abspath needed to remove the trailing `/.` which makes e.g. rmrf fail.
|
||||||
|
out = os.path.abspath(os.path.join(
|
||||||
|
magic_out_dir,
|
||||||
|
os.path.relpath(
|
||||||
|
os.path.splitext(in_path)[0],
|
||||||
|
relative_subpath
|
||||||
|
)
|
||||||
|
))
|
||||||
|
if os.path.isfile(in_path):
|
||||||
|
out += executable_ext
|
||||||
|
return out
|
||||||
|
return in_path
|
||||||
|
|
||||||
def resolve_targets(self, source_dir, targets):
|
def resolve_targets(self, source_dirs, targets):
|
||||||
|
'''
|
||||||
|
Resolve userland or baremetal CLI provided targets to final paths.
|
||||||
|
|
||||||
|
Notably converts the toplevel directory into all source directories needed.
|
||||||
|
'''
|
||||||
if not targets:
|
if not targets:
|
||||||
targets = [source_dir]
|
targets = source_dirs.copy()
|
||||||
new_targets = []
|
new_targets = []
|
||||||
for target in targets:
|
for target in targets:
|
||||||
target = self.toplevel_to_source_dir(target, source_dir)
|
for resolved_target in self.toplevel_to_source_dirs(target, source_dirs):
|
||||||
self.assert_is_subpath(target, source_dir)
|
self.assert_is_subpath(resolved_target, source_dirs)
|
||||||
new_targets.append(target)
|
new_targets.append(resolved_target)
|
||||||
return new_targets
|
return new_targets
|
||||||
|
|
||||||
def resolve_baremetal_executable(self, path):
|
def resolve_baremetal_executable(self, path):
|
||||||
return self.resolve_executable(
|
return self.resolve_executable(
|
||||||
path,
|
path,
|
||||||
self.env['baremetal_source_dir'],
|
[
|
||||||
|
self.env['baremetal_source_dir'],
|
||||||
|
self.env['userland_source_dir']
|
||||||
|
],
|
||||||
self.env['baremetal_build_dir'],
|
self.env['baremetal_build_dir'],
|
||||||
self.env['baremetal_executable_ext'],
|
self.env['baremetal_executable_ext'],
|
||||||
)
|
)
|
||||||
@@ -1367,7 +1385,7 @@ lunch aosp_{}-eng
|
|||||||
def resolve_userland_executable(self, path):
|
def resolve_userland_executable(self, path):
|
||||||
return self.resolve_executable(
|
return self.resolve_executable(
|
||||||
path,
|
path,
|
||||||
self.env['userland_source_dir'],
|
[self.env['userland_source_dir']],
|
||||||
self.env['userland_build_dir'],
|
self.env['userland_build_dir'],
|
||||||
self.env['userland_executable_ext'],
|
self.env['userland_executable_ext'],
|
||||||
)
|
)
|
||||||
@@ -1386,12 +1404,12 @@ lunch aosp_{}-eng
|
|||||||
'''
|
'''
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def toplevel_to_source_dir(self, path, source_dir):
|
def toplevel_to_source_dirs(self, path, source_dirs):
|
||||||
path = os.path.abspath(path)
|
path = os.path.abspath(path)
|
||||||
if path == self.env['root_dir']:
|
if path == self.env['root_dir']:
|
||||||
return source_dir
|
return source_dirs
|
||||||
else:
|
else:
|
||||||
return path
|
return [path]
|
||||||
|
|
||||||
def timed_main(self):
|
def timed_main(self):
|
||||||
'''
|
'''
|
||||||
@@ -1491,13 +1509,21 @@ https://github.com/cirosantilli/linux-kernel-module-cheat#gem5-debug-build
|
|||||||
dirpath_relative_root,
|
dirpath_relative_root,
|
||||||
in_basename
|
in_basename
|
||||||
))
|
))
|
||||||
if my_path_properties.should_be_built(self.env, link):
|
if my_path_properties.should_be_built(
|
||||||
|
self.env,
|
||||||
|
link,
|
||||||
|
is_baremetal=self.is_baremetal,
|
||||||
|
is_userland=self.is_userland
|
||||||
|
):
|
||||||
if extra_objs is None:
|
if extra_objs is None:
|
||||||
extra_objs= []
|
extra_objs= []
|
||||||
if link:
|
if link:
|
||||||
if my_path_properties['extra_objs_lkmc_common']:
|
if self.is_baremetal or my_path_properties['extra_objs_lkmc_common']:
|
||||||
extra_objs.extend(extra_objs_lkmc_common)
|
extra_objs.extend(extra_objs_lkmc_common)
|
||||||
if my_path_properties['extra_objs_baremetal_bootloader']:
|
if (
|
||||||
|
self.is_baremetal and
|
||||||
|
not my_path_properties['extra_objs_disable_baremetal_bootloader']
|
||||||
|
):
|
||||||
extra_objs.extend(extra_objs_baremetal_bootloader)
|
extra_objs.extend(extra_objs_baremetal_bootloader)
|
||||||
if self.need_rebuild([in_path] + extra_objs + extra_deps, out_path):
|
if self.need_rebuild([in_path] + extra_objs + extra_deps, out_path):
|
||||||
cc_flags.extend(my_path_properties['cc_flags'])
|
cc_flags.extend(my_path_properties['cc_flags'])
|
||||||
@@ -1542,7 +1568,7 @@ https://github.com/cirosantilli/linux-kernel-module-cheat#gem5-debug-build
|
|||||||
'cc_flags_after': [],
|
'cc_flags_after': [],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
package_key = dirpath_relative_root_components[1]
|
package_key = dirpath_relative_root_components[2]
|
||||||
if package_key in packages:
|
if package_key in packages:
|
||||||
package = packages[package_key]
|
package = packages[package_key]
|
||||||
else:
|
else:
|
||||||
|
|||||||
9
lkmc.c
9
lkmc.c
@@ -23,7 +23,7 @@ LKMC_ASSERT_EQ_DEFINE(64)
|
|||||||
|
|
||||||
void lkmc_assert_fail(uint32_t line) {
|
void lkmc_assert_fail(uint32_t line) {
|
||||||
printf("error: assertion failed at line: %" PRIu32 "\n", line);
|
printf("error: assertion failed at line: %" PRIu32 "\n", line);
|
||||||
exit(1);
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void lkmc_assert_memcmp(
|
void lkmc_assert_memcmp(
|
||||||
@@ -56,13 +56,6 @@ void lkmc_assert_memcmp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lkmc_baremetal_on_exit_callback(int status, void *arg) {
|
|
||||||
(void)arg;
|
|
||||||
if (status != 0) {
|
|
||||||
printf("lkmc_exit_status_%d\n", status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
#define LKMC_SYSREG_READ_WRITE(type, name) \
|
#define LKMC_SYSREG_READ_WRITE(type, name) \
|
||||||
type LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, name), _read(void)) { \
|
type LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, name), _read(void)) { \
|
||||||
|
|||||||
1
lkmc.h
1
lkmc.h
@@ -20,7 +20,6 @@ LKMC_ASSERT_EQ_DECLARE(32);
|
|||||||
LKMC_ASSERT_EQ_DECLARE(64);
|
LKMC_ASSERT_EQ_DECLARE(64);
|
||||||
void lkmc_assert_fail(uint32_t line);
|
void lkmc_assert_fail(uint32_t line);
|
||||||
void lkmc_assert_memcmp(const void *s1, const void *s2, size_t n, uint32_t line);
|
void lkmc_assert_memcmp(const void *s1, const void *s2, size_t n, uint32_t line);
|
||||||
void lkmc_baremetal_on_exit_callback(int status, void *arg);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Assert that the given branch instruction is taken. */
|
/* Assert that the given branch instruction is taken. */
|
||||||
|
|||||||
13
lkmc/c/add.c
13
lkmc/c/add.c
@@ -1,13 +0,0 @@
|
|||||||
#include <assert.h>
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
int i, j, k;
|
|
||||||
i = 1;
|
|
||||||
/* test-gdb-op1 */
|
|
||||||
j = 2;
|
|
||||||
/* test-gdb-op2 */
|
|
||||||
k = i + j;
|
|
||||||
/* test-gdb-result */
|
|
||||||
if (k != 3)
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
def test(self):
|
|
||||||
self.sendline('tbreak main')
|
|
||||||
self.sendline('continue')
|
|
||||||
self.continue_to('op1')
|
|
||||||
assert self.get_int('i') == 1
|
|
||||||
self.continue_to('op2')
|
|
||||||
assert self.get_int('j') == 2
|
|
||||||
self.continue_to('result')
|
|
||||||
assert self.get_int('k') == 3
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
/* Let's see what happens when an assert fails.
|
|
||||||
*
|
|
||||||
* Outcome on Ubuntu 19.04 shows the failure line:
|
|
||||||
*
|
|
||||||
* assert_fail.out: /path/to/linux-kernel-module-cheat/userland/c/assert_fail.c:15: main: Assertion `0' failed.
|
|
||||||
*
|
|
||||||
* and exit status 134 == 128 + 6, which corresponds to SIGABORT (6).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
assert(0);
|
|
||||||
puts("here");
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/* Get on character from stdin, and then print it back out.
|
|
||||||
*
|
|
||||||
* Same as getc(stdin).
|
|
||||||
*
|
|
||||||
* You have to press enter for the character to go through:
|
|
||||||
* https://stackoverflow.com/questions/1798511/how-to-avoid-pressing-enter-with-getchar
|
|
||||||
*
|
|
||||||
* Used at:
|
|
||||||
* https://stackoverflow.com/questions/556405/what-do-real-user-and-sys-mean-in-the-output-of-time1/53937376#53937376
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
char c;
|
|
||||||
printf("enter a character: ");
|
|
||||||
c = getchar();
|
|
||||||
printf("you entered: %c\n", c);
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
/* Print hello to stdout ;-) */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
puts("hello");
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/* Loop infinitely. Print an integer whenever a period is reached:
|
|
||||||
*
|
|
||||||
* ....
|
|
||||||
* ./infinite_loop [period]
|
|
||||||
* ....
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
uintmax_t i, j, period;
|
|
||||||
if (argc > 1) {
|
|
||||||
period = strtoumax(argv[1], NULL, 10);
|
|
||||||
} else {
|
|
||||||
period = 100000000;
|
|
||||||
}
|
|
||||||
i = 0;
|
|
||||||
j = 0;
|
|
||||||
while (1) {
|
|
||||||
i++;
|
|
||||||
if (i % period == 0) {
|
|
||||||
printf("%ju\n", j);
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
/* Print hello to stderr. */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
fputs("hello\n", stderr);
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
|
|
||||||
from shell_helpers import LF
|
from shell_helpers import LF
|
||||||
|
|
||||||
class PathProperties:
|
class PathProperties:
|
||||||
default_c_std = 'c11'
|
default_c_std = 'c11'
|
||||||
default_cxx_std = 'c++17'
|
default_cxx_std = 'c++17'
|
||||||
|
# All new properties must be listed here or else you get an error.
|
||||||
default_properties = {
|
default_properties = {
|
||||||
'allowed_archs': None,
|
'allowed_archs': None,
|
||||||
|
# Examples that can be built in baremetal.
|
||||||
|
'baremetal': False,
|
||||||
'c_std': default_c_std,
|
'c_std': default_c_std,
|
||||||
'cc_flags': [
|
'cc_flags': [
|
||||||
'-Wall', LF,
|
'-Wall', LF,
|
||||||
@@ -29,11 +33,14 @@ class PathProperties:
|
|||||||
'cc_flags_after': ['-lm', LF],
|
'cc_flags_after': ['-lm', LF],
|
||||||
'cc_pedantic': True,
|
'cc_pedantic': True,
|
||||||
'cxx_std': default_cxx_std,
|
'cxx_std': default_cxx_std,
|
||||||
|
'disrupts_system': False,
|
||||||
# Expected program exit status. When signals are raised, this refers
|
# Expected program exit status. When signals are raised, this refers
|
||||||
# to the native exit status. as reported by Bash #?.
|
# to the native exit status. as reported by Bash #?.
|
||||||
'exit_status': 0,
|
'exit_status': 0,
|
||||||
'extra_objs': [],
|
'extra_objs': [],
|
||||||
'extra_objs_baremetal_bootloader': False,
|
# Explicitly don't add the baremetal bootloader object which normally gets automatically
|
||||||
|
# added to baremetal examples.
|
||||||
|
'extra_objs_disable_baremetal_bootloader': False,
|
||||||
# We should get rid of this if we ever properly implement dependency graphs.
|
# We should get rid of this if we ever properly implement dependency graphs.
|
||||||
'extra_objs_lkmc_common': False,
|
'extra_objs_lkmc_common': False,
|
||||||
'interactive': False,
|
'interactive': False,
|
||||||
@@ -45,10 +52,7 @@ class PathProperties:
|
|||||||
# it only generates intermediate object files. Therefore it
|
# it only generates intermediate object files. Therefore it
|
||||||
# should not be run while testing.
|
# should not be run while testing.
|
||||||
'no_executable': False,
|
'no_executable': False,
|
||||||
# the test receives a signal. We skip those tests for now,
|
'receives_signal': None,
|
||||||
# on userland because we are lazy to figure out the exact semantics
|
|
||||||
# of how Python + QEMU + gem5 determine the exit status of signals.
|
|
||||||
'receives_signal': False,
|
|
||||||
# The script requires a non-trivial argument to be passed to run properly.
|
# The script requires a non-trivial argument to be passed to run properly.
|
||||||
'requires_argument': False,
|
'requires_argument': False,
|
||||||
'requires_dynamic_library': False,
|
'requires_dynamic_library': False,
|
||||||
@@ -68,6 +72,8 @@ class PathProperties:
|
|||||||
# Aruments added automatically to run when running tests,
|
# Aruments added automatically to run when running tests,
|
||||||
# but not on manual running.
|
# but not on manual running.
|
||||||
'test_run_args': {},
|
'test_run_args': {},
|
||||||
|
# Examples that can be built in userland.
|
||||||
|
'userland': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@@ -93,7 +99,13 @@ class PathProperties:
|
|||||||
def set_path_components(self, path_components):
|
def set_path_components(self, path_components):
|
||||||
self.path_components = path_components
|
self.path_components = path_components
|
||||||
|
|
||||||
def should_be_built(self, env, link=False):
|
def should_be_built(
|
||||||
|
self,
|
||||||
|
env,
|
||||||
|
link=False,
|
||||||
|
is_baremetal=False,
|
||||||
|
is_userland=False,
|
||||||
|
):
|
||||||
if len(self.path_components) > 1 and \
|
if len(self.path_components) > 1 and \
|
||||||
self.path_components[1] == 'libs' and \
|
self.path_components[1] == 'libs' and \
|
||||||
not env['package_all'] and \
|
not env['package_all'] and \
|
||||||
@@ -105,14 +117,22 @@ class PathProperties:
|
|||||||
self['allowed_archs'] is None or
|
self['allowed_archs'] is None or
|
||||||
env['arch'] in self['allowed_archs']
|
env['arch'] in self['allowed_archs']
|
||||||
) and \
|
) and \
|
||||||
|
(
|
||||||
|
(is_userland and self['userland'] ) or
|
||||||
|
(is_baremetal and self['baremetal'])
|
||||||
|
) and \
|
||||||
not (
|
not (
|
||||||
link and
|
link and
|
||||||
self['no_executable']
|
self['no_executable']
|
||||||
)
|
)
|
||||||
|
|
||||||
def should_be_tested(self, env):
|
def should_be_tested(self, env, is_baremetal=False, is_userland=False):
|
||||||
return (
|
return (
|
||||||
self.should_be_built(env) and
|
self.should_be_built(
|
||||||
|
env,
|
||||||
|
is_baremetal=is_baremetal,
|
||||||
|
is_userland=is_userland
|
||||||
|
) and
|
||||||
not self['interactive'] and
|
not self['interactive'] and
|
||||||
not self['more_than_1s'] and
|
not self['more_than_1s'] and
|
||||||
not self['no_executable'] and
|
not self['no_executable'] and
|
||||||
@@ -203,6 +223,7 @@ gnu_extension_properties = {
|
|||||||
'cxx_std': 'gnu++17'
|
'cxx_std': 'gnu++17'
|
||||||
}
|
}
|
||||||
freestanding_properties = {
|
freestanding_properties = {
|
||||||
|
'baremetal': False,
|
||||||
'cc_flags': [
|
'cc_flags': [
|
||||||
'-ffreestanding', LF,
|
'-ffreestanding', LF,
|
||||||
'-nostdlib', LF,
|
'-nostdlib', LF,
|
||||||
@@ -216,8 +237,7 @@ path_properties_tuples = (
|
|||||||
{
|
{
|
||||||
'baremetal': (
|
'baremetal': (
|
||||||
{
|
{
|
||||||
'extra_objs_baremetal_bootloader': True,
|
'baremetal': True,
|
||||||
'extra_objs_lkmc_common': True,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'arch': (
|
'arch': (
|
||||||
@@ -229,7 +249,7 @@ path_properties_tuples = (
|
|||||||
'gem5_assert.S': {'requires_m5ops': True},
|
'gem5_assert.S': {'requires_m5ops': True},
|
||||||
'multicore.S': {'test_run_args': {'cpus': 2}},
|
'multicore.S': {'test_run_args': {'cpus': 2}},
|
||||||
'no_bootloader': (
|
'no_bootloader': (
|
||||||
{'extra_objs_baremetal_bootloader': False},
|
{'extra_objs_disable_baremetal_bootloader': True},
|
||||||
{
|
{
|
||||||
'gem5_exit.S': {'requires_m5ops': True},
|
'gem5_exit.S': {'requires_m5ops': True},
|
||||||
'semihost_exit.S': {'requires_semihosting': True},
|
'semihost_exit.S': {'requires_semihosting': True},
|
||||||
@@ -245,7 +265,7 @@ path_properties_tuples = (
|
|||||||
{
|
{
|
||||||
'multicore.S': {'test_run_args': {'cpus': 2}},
|
'multicore.S': {'test_run_args': {'cpus': 2}},
|
||||||
'no_bootloader': (
|
'no_bootloader': (
|
||||||
{'extra_objs_baremetal_bootloader': False},
|
{'extra_objs_disable_baremetal_bootloader': True},
|
||||||
{
|
{
|
||||||
'gem5_exit.S': {'requires_m5ops': True},
|
'gem5_exit.S': {'requires_m5ops': True},
|
||||||
'semihost_exit.S': {'requires_semihosting': True},
|
'semihost_exit.S': {'requires_semihosting': True},
|
||||||
@@ -257,32 +277,22 @@ path_properties_tuples = (
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
'c': (
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
'assert_fail.c': {'exit_status': 134},
|
|
||||||
'infinite_loop.c': {'more_than_1s': True},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
'exit1.c': {'exit_status': 1},
|
|
||||||
'lib': {'no_executable': True},
|
'lib': {'no_executable': True},
|
||||||
'getchar.c': {'interactive': True},
|
'getchar.c': {'interactive': True},
|
||||||
'return1.c': {'exit_status': 1},
|
|
||||||
'return2.c': {'exit_status': 2},
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
'lkmc.c': {
|
||||||
|
'baremetal': True,
|
||||||
|
'userland': True,
|
||||||
|
},
|
||||||
'userland': (
|
'userland': (
|
||||||
{
|
{
|
||||||
'cc_flags': [
|
'userland': True,
|
||||||
'-fopenmp', LF,
|
|
||||||
],
|
|
||||||
'cc_flags_after': [
|
|
||||||
'-pthread', LF,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'arch': (
|
'arch': (
|
||||||
{
|
{
|
||||||
|
'baremetal': True,
|
||||||
'extra_objs_lkmc_common': True,
|
'extra_objs_lkmc_common': True,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -316,11 +326,10 @@ path_properties_tuples = (
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
'freestanding': freestanding_properties,
|
'freestanding': freestanding_properties,
|
||||||
'lkmc_assert_eq_fail.S': {'exit_status': 1},
|
'lkmc_assert_eq_fail.S': {'receives_signal': signal.Signals.SIGABRT},
|
||||||
'lkmc_assert_memcmp_fail.S': {'exit_status': 1},
|
'lkmc_assert_memcmp_fail.S': {'receives_signal': signal.Signals.SIGABRT},
|
||||||
'udf.S': {
|
'udf.S': {
|
||||||
'exit_status': 132,
|
'receives_signal': signal.Signals.SIGILL
|
||||||
'receives_signal': True
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@@ -335,15 +344,16 @@ path_properties_tuples = (
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
'freestanding': freestanding_properties,
|
'freestanding': freestanding_properties,
|
||||||
'lkmc_assert_eq_fail.S': {'exit_status': 1},
|
'lkmc_assert_eq_fail.S': {'receives_signal': signal.Signals.SIGABRT},
|
||||||
'lkmc_assert_memcmp_fail.S': {'exit_status': 1},
|
'lkmc_assert_memcmp_fail.S': {'receives_signal': signal.Signals.SIGABRT},
|
||||||
'udf.S': {
|
'udf.S': {
|
||||||
'exit_status': 132,
|
'receives_signal': signal.Signals.SIGILL
|
||||||
'receives_signal': True
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
'fail.S': {'exit_status': 1},
|
'lkmc_assert_fail.S': {
|
||||||
|
'receives_signal': signal.Signals.SIGABRT,
|
||||||
|
},
|
||||||
'x86_64': (
|
'x86_64': (
|
||||||
{'allowed_archs': {'x86_64'}},
|
{'allowed_archs': {'x86_64'}},
|
||||||
{
|
{
|
||||||
@@ -353,31 +363,44 @@ path_properties_tuples = (
|
|||||||
{
|
{
|
||||||
'freestanding': freestanding_properties,
|
'freestanding': freestanding_properties,
|
||||||
'ring0.c': {
|
'ring0.c': {
|
||||||
'exit_status': 139,
|
'receives_signal': signal.Signals.SIGSEGV
|
||||||
'receives_signal': True
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
'freestanding': freestanding_properties,
|
'freestanding': freestanding_properties,
|
||||||
'lkmc_assert_eq_fail.S': {'exit_status': 1},
|
'lkmc_assert_eq_fail.S': {'receives_signal': signal.Signals.SIGABRT},
|
||||||
'lkmc_assert_memcmp_fail.S': {'exit_status': 1},
|
'lkmc_assert_memcmp_fail.S': {'receives_signal': signal.Signals.SIGABRT},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
'c': (
|
'c': (
|
||||||
{},
|
|
||||||
{
|
{
|
||||||
'assert_fail.c': {
|
'baremetal': True,
|
||||||
'exit_status': 134,
|
},
|
||||||
'receives_signal': True,
|
{
|
||||||
|
'abort.c': {
|
||||||
|
'receives_signal': signal.Signals.SIGABRT,
|
||||||
},
|
},
|
||||||
|
'assert_fail.c': {
|
||||||
|
'receives_signal': signal.Signals.SIGABRT,
|
||||||
|
},
|
||||||
|
'exit1.c': {'exit_status': 1},
|
||||||
|
'exit2.c': {'exit_status': 2},
|
||||||
'false.c': {'exit_status': 1},
|
'false.c': {'exit_status': 1},
|
||||||
'getchar.c': {'interactive': True},
|
'getchar.c': {'interactive': True},
|
||||||
'infinite_loop.c': {'more_than_1s': True},
|
'infinite_loop.c': {'more_than_1s': True},
|
||||||
|
'out_of_memory.c': {'disrupts_system': True},
|
||||||
|
'return1.c': {'exit_status': 1},
|
||||||
|
'return2.c': {'exit_status': 2},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'gcc': (
|
||||||
|
gnu_extension_properties,
|
||||||
|
{
|
||||||
|
'openmp.c': {'cc_flags': ['-fopenmp', LF]},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
'gcc': gnu_extension_properties,
|
|
||||||
'kernel_modules': {**gnu_extension_properties, **{'requires_kernel_modules': True}},
|
'kernel_modules': {**gnu_extension_properties, **{'requires_kernel_modules': True}},
|
||||||
'libs': (
|
'libs': (
|
||||||
{'requires_dynamic_library': True},
|
{'requires_dynamic_library': True},
|
||||||
@@ -398,8 +421,9 @@ path_properties_tuples = (
|
|||||||
'proc_events.c': {'requires_sudo': True},
|
'proc_events.c': {'requires_sudo': True},
|
||||||
'sched_getaffinity.c': {'requires_syscall_getcpu': True},
|
'sched_getaffinity.c': {'requires_syscall_getcpu': True},
|
||||||
'sched_getaffinity_threads.c': {
|
'sched_getaffinity_threads.c': {
|
||||||
'requires_syscall_getcpu': True,
|
'cc_flags_after': ['-pthread', LF],
|
||||||
'more_than_1s': True,
|
'more_than_1s': True,
|
||||||
|
'requires_syscall_getcpu': True,
|
||||||
},
|
},
|
||||||
'time_boot.c': {'requires_sudo': True},
|
'time_boot.c': {'requires_sudo': True},
|
||||||
'virt_to_phys_user.c': {'requires_argument': True},
|
'virt_to_phys_user.c': {'requires_argument': True},
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import thread_pool
|
|||||||
class Main(common.TestCliFunction):
|
class Main(common.TestCliFunction):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
|
is_baremetal=True,
|
||||||
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
||||||
)
|
)
|
||||||
self.add_argument(
|
self.add_argument(
|
||||||
@@ -23,7 +24,10 @@ If given, run only the given tests. Otherwise, run all tests.
|
|||||||
|
|
||||||
def setup_one(self):
|
def setup_one(self):
|
||||||
self.env['tests'] = self.resolve_targets(
|
self.env['tests'] = self.resolve_targets(
|
||||||
self.env['baremetal_source_dir'],
|
[
|
||||||
|
self.env['baremetal_source_dir'],
|
||||||
|
self.env['userland_source_dir']
|
||||||
|
],
|
||||||
self.env['tests']
|
self.env['tests']
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,7 +49,7 @@ If given, run only the given tests. Otherwise, run all tests.
|
|||||||
if os.path.splitext(in_filename)[1] in (self.env['c_ext'], self.env['asm_ext']):
|
if os.path.splitext(in_filename)[1] in (self.env['c_ext'], self.env['asm_ext']):
|
||||||
path_relative_root = os.path.join(dirpath_relative_root, in_filename)
|
path_relative_root = os.path.join(dirpath_relative_root, in_filename)
|
||||||
my_path_properties = path_properties.get(path_relative_root)
|
my_path_properties = path_properties.get(path_relative_root)
|
||||||
if my_path_properties.should_be_tested(self.env):
|
if my_path_properties.should_be_tested(self.env, is_baremetal=True):
|
||||||
cur_run_args = run_args.copy()
|
cur_run_args = run_args.copy()
|
||||||
cur_run_args.update({
|
cur_run_args.update({
|
||||||
'baremetal': os.path.relpath(os.path.join(path_abs, in_filename), os.getcwd()),
|
'baremetal': os.path.relpath(os.path.join(path_abs, in_filename), os.getcwd()),
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ If given, run only the given tests. Otherwise, run all tests.
|
|||||||
|
|
||||||
def setup_one(self):
|
def setup_one(self):
|
||||||
self.env['tests'] = self.resolve_targets(
|
self.env['tests'] = self.resolve_targets(
|
||||||
self.env['userland_source_dir'],
|
[self.env['userland_source_dir']],
|
||||||
self.env['tests']
|
self.env['tests']
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ If given, run only the given tests. Otherwise, run all tests.
|
|||||||
if os.path.splitext(in_filename)[1] in self.env['build_in_exts']:
|
if os.path.splitext(in_filename)[1] in self.env['build_in_exts']:
|
||||||
path_relative_root = os.path.join(dirpath_relative_root, in_filename)
|
path_relative_root = os.path.join(dirpath_relative_root, in_filename)
|
||||||
my_path_properties = path_properties.get(path_relative_root)
|
my_path_properties = path_properties.get(path_relative_root)
|
||||||
if my_path_properties.should_be_tested(self.env):
|
if my_path_properties.should_be_tested(self.env, is_userland=True):
|
||||||
cur_run_args = run_args.copy()
|
cur_run_args = run_args.copy()
|
||||||
cur_run_args.update({
|
cur_run_args.update({
|
||||||
'userland': os.path.relpath(os.path.join(path_abs, in_filename), os.getcwd()),
|
'userland': os.path.relpath(os.path.join(path_abs, in_filename), os.getcwd()),
|
||||||
@@ -65,8 +65,9 @@ If given, run only the given tests. Otherwise, run all tests.
|
|||||||
'run_obj': lkmc.import_path.import_path_main('run'),
|
'run_obj': lkmc.import_path.import_path_main('run'),
|
||||||
'test_id': path_relative_root,
|
'test_id': path_relative_root,
|
||||||
}
|
}
|
||||||
if my_path_properties['receives_signal']:
|
signal = my_path_properties['receives_signal']
|
||||||
run_test_args['expected_exit_status'] = 128 - my_path_properties['exit_status']
|
if signal is not None:
|
||||||
|
run_test_args['expected_exit_status'] = -signal.value
|
||||||
my_thread_pool.submit(run_test_args)
|
my_thread_pool.submit(run_test_args)
|
||||||
return self._handle_thread_pool_errors(my_thread_pool)
|
return self._handle_thread_pool_errors(my_thread_pool)
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ LKMC_PROLOGUE
|
|||||||
|
|
||||||
/* Now with a memory stored value. */
|
/* Now with a memory stored value. */
|
||||||
.data
|
.data
|
||||||
|
/* TODO why is this align required, and why only the in the baremetal toolchain?
|
||||||
|
* Otherwise at edfbe9f0d7e9cc40cffd1c68c7c7c30a47fda2a8 + 1 was failing with:
|
||||||
|
* /path/to/linux-kernel-module-cheat/userland/arch/aarch64/fadd_scalar.S:28:(.text+0x3c): relocation truncated to fit: R_AARCH64_LD_PREL_LO19 against `.data'
|
||||||
|
* /path/to/linux-kernel-module-cheat/userland/arch/aarch64/fadd_scalar.S:28: warning: One possible cause of this error is that the symbol is being referenced in the indicated code as if it had a larger alignment than was declared where it was defined.
|
||||||
|
*/
|
||||||
|
.align 4
|
||||||
my_double_0:
|
my_double_0:
|
||||||
.double 1.5
|
.double 1.5
|
||||||
my_double_1:
|
my_double_1:
|
||||||
|
|||||||
@@ -74,5 +74,6 @@ pc_relative_ldr:
|
|||||||
LKMC_ASSERT_EQ(x0, =0x123456789ABCDEF0)
|
LKMC_ASSERT_EQ(x0, =0x123456789ABCDEF0)
|
||||||
LKMC_EPILOGUE
|
LKMC_EPILOGUE
|
||||||
.data
|
.data
|
||||||
|
.align 4
|
||||||
pc_relative_str:
|
pc_relative_str:
|
||||||
.quad 0x0000000000000000
|
.quad 0x0000000000000000
|
||||||
|
|||||||
34
userland/c/abort.c
Normal file
34
userland/c/abort.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* # abort
|
||||||
|
*
|
||||||
|
* Raise a SIGABRT, an ANSI C signal which by default kills the program.
|
||||||
|
*
|
||||||
|
* ....
|
||||||
|
* man abort
|
||||||
|
* ....
|
||||||
|
*
|
||||||
|
* Bibliography:
|
||||||
|
*
|
||||||
|
* * http://stackoverflow.com/questions/397075/what-is-the-difference-between-exit-and-abort
|
||||||
|
* * http://stackoverflow.com/questions/3676221/when-abort-is-preferred-over-exit
|
||||||
|
*
|
||||||
|
* Differences from exit: does not run regular program teardown:
|
||||||
|
*
|
||||||
|
* * does not call `atexit` function.
|
||||||
|
* * does not call C++ destructors
|
||||||
|
*
|
||||||
|
* `assert()` exits the program with abort.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void atexit_func() {
|
||||||
|
puts("atexit");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
/* Will not get called. */
|
||||||
|
atexit(atexit_func);
|
||||||
|
abort();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/add.c
|
|
||||||
13
userland/c/add.c
Normal file
13
userland/c/add.c
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int i, j, k;
|
||||||
|
i = 1;
|
||||||
|
/* test-gdb-op1 */
|
||||||
|
j = 2;
|
||||||
|
/* test-gdb-op2 */
|
||||||
|
k = i + j;
|
||||||
|
/* test-gdb-result */
|
||||||
|
if (k != 3)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/add.py
|
|
||||||
9
userland/c/add.py
Normal file
9
userland/c/add.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
def test(self):
|
||||||
|
self.sendline('tbreak main')
|
||||||
|
self.sendline('continue')
|
||||||
|
self.continue_to('op1')
|
||||||
|
assert self.get_int('i') == 1
|
||||||
|
self.continue_to('op2')
|
||||||
|
assert self.get_int('j') == 2
|
||||||
|
self.continue_to('result')
|
||||||
|
assert self.get_int('k') == 3
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/assert_fail.c
|
|
||||||
18
userland/c/assert_fail.c
Normal file
18
userland/c/assert_fail.c
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/* Let's see what happens when an assert fails.
|
||||||
|
*
|
||||||
|
* Outcome on Ubuntu 19.04 shows the failure line:
|
||||||
|
*
|
||||||
|
* assert_fail.out: /path/to/linux-kernel-module-cheat/userland/c/assert_fail.c:15: main: Assertion `0' failed.
|
||||||
|
*
|
||||||
|
* and exit status 134 == 128 + 6, which corresponds to SIGABORT (6).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
assert(0);
|
||||||
|
puts("here");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
7
userland/c/exit2.c
Normal file
7
userland/c/exit2.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/getchar.c
|
|
||||||
21
userland/c/getchar.c
Normal file
21
userland/c/getchar.c
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/* Get on character from stdin, and then print it back out.
|
||||||
|
*
|
||||||
|
* Same as getc(stdin).
|
||||||
|
*
|
||||||
|
* You have to press enter for the character to go through:
|
||||||
|
* https://stackoverflow.com/questions/1798511/how-to-avoid-pressing-enter-with-getchar
|
||||||
|
*
|
||||||
|
* Used at:
|
||||||
|
* https://stackoverflow.com/questions/556405/what-do-real-user-and-sys-mean-in-the-output-of-time1/53937376#53937376
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
char c;
|
||||||
|
printf("enter a character: ");
|
||||||
|
c = getchar();
|
||||||
|
printf("you entered: %c\n", c);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/hello.c
|
|
||||||
9
userland/c/hello.c
Normal file
9
userland/c/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;
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/infinite_loop.c
|
|
||||||
29
userland/c/infinite_loop.c
Normal file
29
userland/c/infinite_loop.c
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/* Loop infinitely. Print an integer whenever a period is reached:
|
||||||
|
*
|
||||||
|
* ....
|
||||||
|
* ./infinite_loop [period]
|
||||||
|
* ....
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
uintmax_t i, j, period;
|
||||||
|
if (argc > 1) {
|
||||||
|
period = strtoumax(argv[1], NULL, 10);
|
||||||
|
} else {
|
||||||
|
period = 100000000;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
j = 0;
|
||||||
|
while (1) {
|
||||||
|
i++;
|
||||||
|
if (i % period == 0) {
|
||||||
|
printf("%ju\n", j);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
/* Test out of memory. */
|
/* Let's see how much memory Linux lets us allocate. */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
char *ptr = NULL;
|
char *ptr = NULL;
|
||||||
size_t alloc_size = 1;
|
size_t size = 1;
|
||||||
while (1) {
|
while (1) {
|
||||||
ptr = realloc(ptr, alloc_size);
|
printf("0x%zx\n", size);
|
||||||
|
ptr = realloc(ptr, size);
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
puts("out of memory");
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
alloc_size <<= 1;
|
size <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
6
userland/c/return0.c
Normal file
6
userland/c/return0.c
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/* false.c is a superset of this, this is mainly a sanity check for
|
||||||
|
* baremetal where we don't have CLI arguments yet:
|
||||||
|
* https://github.com/cirosantilli/linux-kernel-module-cheat/issues/67
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(void) { return 0; }
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../lkmc/c/stderr.c
|
|
||||||
7
userland/c/stderr.c
Normal file
7
userland/c/stderr.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/* Print hello to stderr. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
fputs("hello\n", stderr);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user