baremetal: symlink all programs that currently run on both userland and baremetal

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-05-21 00:00:00 +00:00
parent 492d9cdf3f
commit 6fe9e5bae7
35 changed files with 138 additions and 109 deletions

View File

@@ -755,7 +755,7 @@ Or to run a baremetal example instead:
....
./run \
--arch aarch64 \
--baremetal baremetal/hello.c \
--baremetal baremetal/c/hello.c \
--qemu-which host \
;
....
@@ -1193,11 +1193,11 @@ Our C bare-metal compiler is built with link:https://github.com/crosstool-ng/cro
Every `.c` file inside link:baremetal/[] and `.S` file inside `baremetal/arch/<arch>/` generates a separate baremetal image.
For example, to run link:baremetal/hello.c[] in QEMU do:
For example, to run link:baremetal/c/hello.c[] in QEMU do:
....
./build --arch aarch64 --download-dependencies qemu-baremetal
./run --arch aarch64 --baremetal baremetal/hello.c
./run --arch aarch64 --baremetal baremetal/c/hello.c
....
The terminal prints:
@@ -1238,14 +1238,14 @@ echo $?
To modify a baremetal program, simply edit the file, e.g.
....
vim baremetal/hello.c
vim baremetal/c/hello.c
....
and rebuild:
....
./build-baremetal --arch aarch64
./run --arch aarch64 --baremetal baremetal/hello.c
./run --arch aarch64 --baremetal baremetal/c/hello.c
....
`./build qemu-baremetal` that we run previously is only needed for the initial build. That script calls link:build-baremetal[] for us, in addition to building prerequisites such as QEMU and crosstool-NG.
@@ -1255,7 +1255,7 @@ and rebuild:
Alternatively, for the sake of tab completion, we also accept relative paths inside `baremetal/`, for example the following also work:
....
./run --arch aarch64 --baremetal baremetal/hello.c
./run --arch aarch64 --baremetal baremetal/c/hello.c
./run --arch aarch64 --baremetal baremetal/arch/aarch64/add.S
....
@@ -1269,7 +1269,7 @@ To use gem5 instead of QEMU do:
....
./build --download-dependencies gem5-baremetal
./run --arch aarch64 --baremetal baremetal/hello.c --emulator gem5
./run --arch aarch64 --baremetal baremetal/c/hello.c --emulator gem5
....
and then <<qemu-buildroot-setup,as usual>> open a shell with:
@@ -1281,7 +1281,7 @@ and then <<qemu-buildroot-setup,as usual>> open a shell with:
Or as usual, <<tmux>> users can do both in one go with:
....
./run --arch aarch64 --baremetal baremetal/hello.c --emulator gem5 --tmux
./run --arch aarch64 --baremetal baremetal/c/hello.c --emulator gem5 --tmux
....
TODO: the carriage returns are a bit different than in QEMU, see: <<gem5-baremetal-carriage-return>>.
@@ -1289,8 +1289,8 @@ TODO: the carriage returns are a bit different than in QEMU, see: <<gem5-baremet
Note that `./build-baremetal` requires the `--emulator gem5` option, and generates separate executable images for both, as can be seen from:
....
echo "$(./getvar --arch aarch64 --baremetal baremetal/hello.c --emulator qemu image)"
echo "$(./getvar --arch aarch64 --baremetal baremetal/hello.c --emulator gem5 image)"
echo "$(./getvar --arch aarch64 --baremetal baremetal/c/hello.c --emulator qemu image)"
echo "$(./getvar --arch aarch64 --baremetal baremetal/c/hello.c --emulator gem5 image)"
....
This is unlike the Linux kernel that has a single image for both QEMU and gem5:
@@ -1306,14 +1306,14 @@ The reason for that is that on baremetal we don't parse the <<device-tree,device
....
./build-baremetal --arch aarch64 --emulator gem5 --machine RealViewPBX
./run --arch aarch64 --baremetal baremetal/hello.c --emulator gem5 --machine RealViewPBX
./run --arch aarch64 --baremetal baremetal/c/hello.c --emulator gem5 --machine RealViewPBX
....
This generates yet new separate images with new magic constants:
....
echo "$(./getvar --arch aarch64 --baremetal baremetal/hello.c --emulator gem5 --machine VExpress_GEM5_V1 image)"
echo "$(./getvar --arch aarch64 --baremetal baremetal/hello.c --emulator gem5 --machine RealViewPBX image)"
echo "$(./getvar --arch aarch64 --baremetal baremetal/c/hello.c --emulator gem5 --machine VExpress_GEM5_V1 image)"
echo "$(./getvar --arch aarch64 --baremetal baremetal/c/hello.c --emulator gem5 --machine RealViewPBX image)"
....
But just stick to newer and better `VExpress_GEM5_V1` unless you have a good reason to use `RealViewPBX`.
@@ -12685,7 +12685,7 @@ Guaranteed undefined! Therefore raise illegal instruction signal. Used by GCC `_
* link:userland/arch/arm/udf.S[]
* link:userland/arch/aarch64/udf.S[]
TODO: why GNU GAS 2.29 does not have a mnemonic for it?
Why GNU GAS 2.29 does not have a mnemonic for it in A64 because it is very recent: shows in [[armarm8-db]] but not `ca`.
=== ARM SIMD
@@ -12932,12 +12932,30 @@ https://static.docs.arm.com/ddi0487/ca/DDI0487C_a_armv8_arm.pdf
Latest version: https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile
Versions are determined by two letteres in lexicographical order, e.g.:
* a
* af
* aj
* aj
* b
* ba
* bb
* ca
The link: https://static.docs.arm.com/ddi0487/ca/DDI0487C_a_armv8_arm.pdf is the `ca` version for example.
The official comprehensive ARMv8 reference.
ISA quick references can be found in some places:
* https://web.archive.org/web/20161009122630/http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001m/QRC0001_UAL.pdf
[[armarm8-db]]
===== ARMv8 architecture reference manual db
https://static.docs.arm.com/ddi0487/db/DDI0487D_b_armv8_arm.pdf
[[armv8-programmers-guide]]
===== Programmer's Guide for ARMv8-A
@@ -12962,19 +12980,19 @@ Except that is is even cooler here since we can easily control and understand ev
For example, on the first shell:
....
./run --arch arm --baremetal baremetal/hello.c --gdb-wait
./run --arch arm --baremetal baremetal/c/hello.c --gdb-wait
....
then on the second shell:
....
./run-gdb --arch arm --baremetal baremetal/hello.c -- main
./run-gdb --arch arm --baremetal baremetal/c/hello.c -- main
....
Or if you are a <<tmux,tmux pro>>, do everything in one go with:
....
./run --arch arm --baremetal baremetal/hello.c --gdb
./run --arch arm --baremetal baremetal/c/hello.c --gdb
....
Alternatively, to start from the very first executed instruction of our tiny <<baremetal-bootloaders>>:
@@ -12982,13 +13000,13 @@ Alternatively, to start from the very first executed instruction of our tiny <<b
....
./run \
--arch arm \
--baremetal baremetal/hello.c \
--baremetal baremetal/c/hello.c \
--gdb-wait \
--tmux-args=--no-continue \
;
....
Now you can just `stepi` to when jumping into main to go to the C code in link:baremetal/hello.c[].
Now you can just `stepi` to when jumping into main to go to the C code in link:baremetal/c/hello.c[].
This is specially interesting for the executables that don't use the bootloader from under `baremetal/arch/<arch>/no_bootloader/*.S`, e.g.:
@@ -13125,7 +13143,7 @@ For `arm`, some baremetal examples compile fine with:
....
sudo apt-get install gcc-arm-none-eabi qemu-system-arm
./build-baremetal --arch arm --gcc-which host-baremetal
./run --arch arm --baremetal baremetal/hello.c --qemu-which host
./run --arch arm --baremetal baremetal/c/hello.c --qemu-which host
....
However, there are as usual limitations to using prebuilts:
@@ -13154,7 +13172,7 @@ TODO: any advantage over QEMU? I doubt it, mostly using it as as toy for now:
Without running `./run`, do directly:
....
./run-gdb --arch arm --baremetal baremetal/hello.c --sim
./run-gdb --arch arm --baremetal baremetal/c/hello.c --sim
....
Then inside GDB:
@@ -13720,12 +13738,12 @@ Source: link:test-baremetal[]
Analogously to <<user-mode-tests>>, we can select individual tests or directories with:
....
./test-baremetal --arch aarch64 baremetal/hello.c baremetal/arch/aarch64/no_bootloader/
./test-baremetal --arch aarch64 baremetal/c/hello.c baremetal/arch/aarch64/no_bootloader/
....
which would run all of:
* link:baremetal/hello.c[]
* link:baremetal/c/hello.c[]
* all tests under the directory: link:baremetal/arch/aarch64/no_bootloader/[]
We detect if tests failed by parsing logs for the <<magic-failure-string>>.
@@ -15097,14 +15115,14 @@ Sources:
If a test fails, re-run the test commands manually and use `--verbose` to understand what happened:
....
./run --arch arm --background --baremetal baremetal/add.c --gdb-wait &
./run-gdb --arch arm --baremetal baremetal/add.c --verbose -- main
./run --arch arm --background --baremetal baremetal/c/add.c --gdb-wait &
./run-gdb --arch arm --baremetal baremetal/c/add.c --verbose -- main
....
and possibly repeat the GDB steps manually with the usual:
....
./run-gdb --arch arm --baremetal baremetal/add.c --no-continue --verbose
./run-gdb --arch arm --baremetal baremetal/c/add.c --no-continue --verbose
....
To debug GDB problems on gem5, you might want to enable the following <<gem5-tracing,tracing>> options:
@@ -15112,7 +15130,7 @@ To debug GDB problems on gem5, you might want to enable the following <<gem5-tra
....
./run \
--arch arm \
--baremetal baremetal/add.c \
--baremetal baremetal/c/add.c \
--gdb-wait \
--trace GDBRecv,GDBSend \
--trace-stdout \
@@ -15163,7 +15181,7 @@ So setup this `on_exit` automatically from all our <<baremetal-bootloaders>>, so
+
The following examples end up testing that our setup is working:
+
* link:baremetal/assert_fail.c[]
* link:baremetal/c/assert_fail.c[]
* link:baremetal/return1.c[]
* link:baremetal/return2.c[]
* link:baremetal/exit0.c[]

View File

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

View File

@@ -1 +0,0 @@
../lkmc/add.py

View File

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

1
baremetal/c/add.c Symbolic link
View File

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

1
baremetal/c/add.py Symbolic link
View File

@@ -0,0 +1 @@
../../lkmc/c/add.py

1
baremetal/c/assert_fail.c Symbolic link
View File

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

1
baremetal/c/hello.c Symbolic link
View File

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

1
baremetal/c/infinite_loop.c Symbolic link
View File

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

1
baremetal/c/stderr.c Symbolic link
View File

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

View File

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

View File

@@ -1,4 +0,0 @@
int main(void) {
while(1) {}
return 0;
}

View File

@@ -1,22 +1,17 @@
/* Test that input request through serial also works. */
/* Test out of memory. */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char c;
char *ptr = NULL;
size_t alloc_size = 1;
while (1) {
printf("enter a character\n");
c = getchar();
printf("got: %c\n", c);
ptr = realloc(ptr, alloc_size);
if (ptr == NULL) {
puts("out of memory");
break;
} else {
printf("new alloc of %zu bytes at address 0x%p\n", alloc_size, ptr);
alloc_size <<= 1;
}
}

6
bisect-gem5-gdb Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
# https://github.com/cirosantilli/linux-kernel-module-cheat#bisection
set -eu
cd ../..
./build-gem5 --arch aarch64 --gem5-build-id bisect
./test-gdb --arch aarch64 --quit-on-fail

View File

@@ -155,10 +155,14 @@ class LkmcCliFunction(cli_function.CliFunction):
It would be beautiful to do this evaluation in a lazy way, e.g. with functions +
cache decorators:
https://stackoverflow.com/questions/815110/is-there-a-decorator-to-simply-cache-function-return-values
:param is_userland: on ./run, we detect if userland based on --userland. However, ./test-user-mode
does not take --userland, and that causes problems.
'''
def __init__(
self,
*args,
is_userland=False,
defaults=None,
supported_archs=None,
**kwargs
@@ -171,6 +175,7 @@ class LkmcCliFunction(cli_function.CliFunction):
kwargs['extra_config_params'] = os.path.basename(inspect.getfile(self.__class__))
if defaults is None:
defaults = {}
self._is_userland = is_userland
self._defaults = defaults
self._is_common = True
self._common_args = set()
@@ -1199,7 +1204,7 @@ lunch aosp_{}-eng
continue
else:
raise Exception('native emulator only supported in if target arch == host arch')
if env['userland'] is None:
if env['userland'] is None and not self._is_userland:
if real_all_emulators:
continue
else:

21
lkmc/c/getchar.c Normal file
View 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;
}

29
lkmc/c/infinite_loop.c Normal file
View 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++;
}
}
}

7
lkmc/c/stderr.c Normal file
View File

@@ -0,0 +1,7 @@
/* Print hello to stderr. */
#include <stdio.h>
int main(void) {
fputs("hello\n", stderr);
}

View File

@@ -258,9 +258,14 @@ path_properties_tuples = (
)
}
),
'assert_fail.c': {'exit_status': 134},
'c': (
{},
{
'assert_fail.c': {'exit_status': 134},
'infinite_loop.c': {'more_than_1s': True},
}
),
'exit1.c': {'exit_status': 1},
'infinite_loop.c': {'more_than_1s': True},
'lib': {'no_executable': True},
'getchar.c': {'interactive': True},
'return1.c': {'exit_status': 1},

View File

@@ -17,7 +17,7 @@ TODO: expose all userland relevant ./run args here as well somehow.
'''
if not 'defaults' in kwargs:
kwargs['defaults'] = {}
super().__init__(*args, **kwargs)
super().__init__(*args, is_userland=True, **kwargs)
self.add_argument(
'tests',
nargs='*',

1
userland/c/add.c Symbolic link
View File

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

1
userland/c/add.py Symbolic link
View File

@@ -0,0 +1 @@
../../lkmc/c/add.py

View File

@@ -1 +1 @@
../../lkmc/assert_fail.c
../../lkmc/c/assert_fail.c

View File

@@ -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
userland/c/getchar.c Symbolic link
View File

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

View File

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

View File

@@ -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
userland/c/infinite_loop.c Symbolic link
View File

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

View File

@@ -1,7 +0,0 @@
/* Print hello to stderr. */
#include <stdio.h>
int main(void) {
fputs("hello\n", stderr);
}

1
userland/c/stderr.c Symbolic link
View File

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

View File

@@ -1 +0,0 @@
Testing mostly infrastructure of this repository rather than anything else.

View File

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

View File

@@ -1 +0,0 @@
../../lkmc/add.py