diff --git a/README.adoc b/README.adoc index 4fed229..875d847 100644 --- a/README.adoc +++ b/README.adoc @@ -2617,6 +2617,8 @@ cat "$(./getvar run_dir)/run.sh" Instead, we used the QEMU `-initrd` option to point to the `.cpio` filesystem that Buildroot generated for us. +Try removing that `-initrd` option to watch the kernel panic without rootfs at the end of boot. + When using `.cpio`, there can be no filesystem persistency across boots, since all file operations happen in memory in a tmpfs: .... @@ -2674,25 +2676,25 @@ Related: https://stackoverflow.com/questions/6405083/initrd-and-booting-the-linu TODO: broken when we started building the Linux manually with `./build-linux` instead of Buildroot. Was working before, see e.g. 56738a1c70e50bf7b6d5fbe02372c5d277a8286f. -initramfs is just like <>, but you also glue the image directly to the kernel image itself. - -So the only argument that QEMU needs is the `-kernel`, no `-drive` not even `-initrd`! Pretty cool. +initramfs is just like <>, but you also glue the image directly to the kernel image itself using the kernel's build system. Try it out with: -.... -./build-buildroot --initramfs -l -./run --initramfs -.... - -The `-l` (ell) should only be used the first time you move to / from a different root filesystem method (ext2 or cpio) to initramfs to overcome: https://stackoverflow.com/questions/49260466/why-when-i-change-br2-linux-kernel-custom-config-file-and-run-make-linux-reconfi - .... ./build-buildroot --initramfs +./build-linux --initramfs ./run --initramfs .... -It is interesting to see how this increases the size of the kernel image if you do a: +Notice how we had to rebuild the Linux kernel this time around as well after Buildroot, since in that build we will be gluing the CPIO to the kernel image. + +Now, once again, if we look at the QEMU run command generated, we see all that QEMU needs is the `-kernel` option, no `-drive` not even `-initrd`! Pretty cool: + +.... +cat "$(./getvar run_dir)/run.sh" +.... + +It is also interesting to observe how this increases the size of the kernel image if you do a: .... ls -lh "$(./getvar linux_image)" @@ -2700,7 +2702,16 @@ ls -lh "$(./getvar linux_image)" before and after using initramfs, since the `.cpio` is now glued to the kernel image. -In the background, it uses `BR2_TARGET_ROOTFS_INITRAMFS`, and this makes the kernel config option `CONFIG_INITRAMFS_SOURCE` point to the CPIO that will be embedded in the kernel image. +Don't forget that to stop using initramfs, you must rebuild the kernel without `--initramfs`: + +.... +./build-linux +./run +.... + +Also consider using <> if you need to switch between initramfs and non initramfs often. + +Setting up initramfs is very easy: our scripts just set `CONFIG_INITRAMFS_SOURCE` to point to the CPIO path. http://nairobi-embedded.org/initramfs_tutorial.html shows a full manual setup. @@ -5415,10 +5426,10 @@ Where the data comes from and how to modify it: In this repo, leaking host information, and to make builds more reproducible, we are setting: -- user and date to dummy values -- hostname to the kernel git commit +- user and date to dummy values with `KBUILD_BUILD_USER` and `KBUILD_BUILD_TIMESTAMP` +- hostname to the kernel git commit with `KBUILD_BUILD_HOST` and `KBUILD_BUILD_VERSION` -So the file contains something like: +A sample result is: .... Linux version 4.19.0-dirty (lkmc@84df9525b0c27f3ebc2ebb1864fa62a97fdedb7d) (gcc version 6.4.0 (Buildroot 2018.05-00002-gbc60382b8f)) #1 SMP Thu Jan 1 00:00:00 UTC 1970 diff --git a/build-buildroot b/build-buildroot index 6ceff31..9cd16b2 100755 --- a/build-buildroot +++ b/build-buildroot @@ -133,7 +133,7 @@ usually extra Buildroot targets. config_fragments = [ os.path.join(self.env['root_dir'], 'buildroot_config', 'default') ] + self.env['config_fragment'] - if self.env['initrd']: + if self.env['initrd'] or self.env['initramfs']: configs.append('BR2_TARGET_ROOTFS_CPIO=y') # TODO Can't get rid of these for now with nice fragments on Buildroot: # http://stackoverflow.com/questions/44078245/is-it-possible-to-use-config-fragments-with-buildroots-config diff --git a/build-linux b/build-linux index 9f56951..766aeb1 100755 --- a/build-linux +++ b/build-linux @@ -64,8 +64,6 @@ Run `make modules_install` after `make`. def build(self): build_dir = self.get_build_dir() - if self.env['initrd'] or self.env['initramfs']: - raise Exception('just trolling, --initrd and --initramfs are broken for now') os.makedirs(build_dir, exist_ok=True) tool = 'gcc' gcc = self.get_toolchain_tool(tool) @@ -105,10 +103,12 @@ Run `make modules_install` after `make`. for i, config_fragment in enumerate(config_fragments): config_fragments[i] = os.path.join(self.env['linux_config_dir'], config_fragment) config_fragments.extend(self.env['config_fragment']) - if self.env['config'] != []: + cli_configs = self.env['config'] + if self.env['initramfs']: + cli_configs.append('CONFIG_INITRAMFS_SOURCE="{}"'.format(self.env['buildroot_cpio'])) + if cli_configs: cli_config_fragment_path = os.path.join(build_dir, 'lkmc_cli_config_fragment') - cli_config_str = '\n'.join(self.env['config']) - self.sh.write_string_to_file(cli_config_fragment_path, cli_config_str) + self.sh.write_configs(cli_config_fragment_path, cli_configs, mode='w') config_fragments.append(cli_config_fragment_path) self.sh.cp( base_config_file, @@ -136,6 +136,7 @@ Run `make modules_install` after `make`. common_make_args + self.sh.add_newlines(self.env['extra_make_args']) ), + # https://github.com/cirosantilli/linux-kernel-module-cheat#proc-version extra_env={ 'KBUILD_BUILD_VERSION': '1', 'KBUILD_BUILD_TIMESTAMP': 'Thu Jan 1 00:00:00 UTC 1970', diff --git a/common.py b/common.py index d686b76..11efe18 100644 --- a/common.py +++ b/common.py @@ -255,14 +255,16 @@ Use the given directory as the Linux source tree. ''' ) self.add_argument( - '--initramfs', default=False, + '--initramfs', + default=False, ) self.add_argument( '--initrd', default=False, help='''\ -Make Buildroot create a CPIO root filessytem, and make QEMU use it instead of -the default ext2. +For Buildroot: create a CPIO root filessytem. +For QEMU use that CPUI root filesystem initrd instead of the default ext2. +See: https://github.com/cirosantilli/linux-kernel-module-cheat#initrd ''' ) @@ -477,6 +479,7 @@ Valid emulators: {} env['buildroot_images_dir'] = join(env['buildroot_build_dir'], 'images') env['buildroot_rootfs_raw_file'] = join(env['buildroot_images_dir'], 'rootfs.ext2') env['buildroot_qcow2_file'] = env['buildroot_rootfs_raw_file'] + '.qcow2' + env['buildroot_cpio'] = join(self.env['buildroot_images_dir'], 'rootfs.cpio') env['staging_dir'] = join(env['out_dir'], 'staging', env['arch']) env['buildroot_staging_dir'] = join(env['buildroot_build_dir'], 'staging') env['target_dir'] = join(env['buildroot_build_dir'], 'target') @@ -601,6 +604,7 @@ Valid emulators: {} else: env['userland_quit_cmd'] = '/poweroff.out' env['quit_init'] = 'init={}'.format(env['userland_quit_cmd']) + self.env['ramfs'] = self.env['initrd'] or self.env['initramfs'] # Kernel modules. env['kernel_modules_build_dir'] = join(env['kernel_modules_build_base_dir'], env['arch']) diff --git a/gem5-bench-dhrystone b/gem5-bench-dhrystone index df3d90b..24d069d 100755 --- a/gem5-bench-dhrystone +++ b/gem5-bench-dhrystone @@ -10,7 +10,7 @@ cmd="./run --arch '$arch' --emulator gem5 --eval-busybox '/gem5.sh'" # These cache sizes roughly match the ARM Cortex A75 # https://en.wikipedia.org/wiki/ARM_Cortex-A75 -restore='-l 1 -- --cpu-type=HPI --restore-with-cpu=HPI --caches --l2cache --l1d_size=64kB --l1i_size=64kB --l2_size=256kB' +restore='--gem5-restore 1 -- --cpu-type=HPI --restore-with-cpu=HPI --caches --l2cache --l1d_size=64kB --l1i_size=64kB --l2_size=256kB' # Generate a checkpoint after Linux boots, using the faster and less detailed CPU. # The boot takes a while, be patient young Padawan. diff --git a/run b/run index 825fd35..cd18014 100755 --- a/run +++ b/run @@ -117,7 +117,7 @@ gem.op5 --debug-flags=Exec fs.py --cpu-type=HPI --caches '--kdb', default=False, ) self.add_argument( - '-l', '--gem5-restore', type=int, + '--gem5-restore', type=int, help='''\ Restore the nth most recently taken gem5 checkpoint according to directory timestamps. @@ -231,12 +231,8 @@ Run QEMU with VNC instead of the default SDL. Connect to it with: vnc = ['-vnc', ':0', LF] else: vnc = [] - if self.env['initrd'] or self.env['initramfs']: - ramfs = True - else: - ramfs = False if self.env['eval'] is not None: - if ramfs: + if self.env['ramfs']: initarg = 'rdinit' else: initarg = 'init' @@ -504,9 +500,9 @@ Run QEMU with VNC instead of the default SDL. Connect to it with: if not qemu_executable_prebuilt: cmd.extend(qemu_user_and_system_options) if self.env['initrd']: - extra_emulator_args.extend(['-initrd', os.path.join(self.env['buildroot_images_dir'], 'rootfs.cpio')]) + extra_emulator_args.extend(['-initrd', self.env['buildroot_cpio'], LF]) rr = self.env['record'] or self.env['replay'] - if ramfs: + if self.env['ramfs']: # TODO why is this needed, and why any string works. root = 'root=/dev/anything' else: diff --git a/shell_helpers.py b/shell_helpers.py index 82345ae..709441c 100644 --- a/shell_helpers.py +++ b/shell_helpers.py @@ -269,9 +269,9 @@ class ShellHelpers: else: os.unlink(path) - def write_configs(self, config_path, configs, config_fragments=None): + def write_configs(self, config_path, configs, config_fragments=None, mode='a'): ''' - Write extra KEY=val configs into the given config file. + Append extra KEY=val configs into the given config file. ''' if config_fragments is None: config_fragments = [] @@ -283,7 +283,7 @@ class ShellHelpers: with open(config_fragment, 'r') as config_fragment_file: for line in config_fragment_file: config_file.write(line) - self.write_string_to_file(config_path, '\n'.join(configs), mode='a') + self.write_string_to_file(config_path, '\n'.join(configs), mode=mode) def write_string_to_file(self, path, string, mode='w'): if mode == 'a': @@ -292,5 +292,5 @@ class ShellHelpers: redirect = '>' self.print_cmd("cat << 'EOF' {} {}\n{}\nEOF".format(redirect, path, string)) if not self.dry_run: - with open(path, 'a') as f: + with open(path, mode) as f: f.write(string)