diff --git a/README.adoc b/README.adoc index e932cc7..4067d26 100644 --- a/README.adoc +++ b/README.adoc @@ -1589,7 +1589,9 @@ See also: https://github.com/cirosantilli/linux-kernel-module-cheat/issues/19 The implementation is described at: https://stackoverflow.com/questions/46415059/how-to-observe-aarch64-system-registers-in-qemu/53043044#53043044 -=== GDB step debug multicore +=== GDB step debug multicore userland + +For a more minimal baremetal multicore setup, see: <>. We can set and get which cores the Linux kernel allows a program to run on with `sched_getaffinity` and `sched_setaffinity`: @@ -10510,13 +10512,13 @@ output: ==== ARM multicore -TODO get working: CPU1 not waking up: +TODO get working: CPU 1 not waking up: .... -./run --arch aarch64 --baremetal arch/aarch64/no_bootloader/multicore +./run --arch aarch64 --baremetal arch/aarch64/multicore --cpus 2 .... -Source: link:baremetal/arch/aarch64/no_bootloader/multicore.S[] +Source: link:baremetal/arch/aarch64/multicore.S[] CPU 0 of this program enters a spinlock loop: it repeatedly checks if a given memory address is `1`. diff --git a/baremetal/arch/aarch64/no_bootloader/multicore.S b/baremetal/arch/aarch64/multicore.S similarity index 70% rename from baremetal/arch/aarch64/no_bootloader/multicore.S rename to baremetal/arch/aarch64/multicore.S index 4494e6c..bfa2f0c 100644 --- a/baremetal/arch/aarch64/no_bootloader/multicore.S +++ b/baremetal/arch/aarch64/multicore.S @@ -1,7 +1,7 @@ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-multicore */ -.global mystart -mystart: +.global main +main: /* Reset spinlock. */ mov x0, #0 ldr x1, =spinlock @@ -21,15 +21,7 @@ mystart: ldr x0, spinlock cbz x0, 1b - /* Semihost exit. */ - mov x1, #0x26 - movk x1, #2, lsl #16 - str x1, [sp,#0] - mov x0, #0 - str x0, [sp,#8] - mov x1, sp - mov w0, #0x18 - hlt 0xf000 + ret spinlock: .skip 8 diff --git a/build-baremetal b/build-baremetal index b8e1294..16594bb 100755 --- a/build-baremetal +++ b/build-baremetal @@ -44,29 +44,32 @@ class BaremetalComponent(common.Component): uart_address = 0x09000000 os.makedirs(build_dir, exist_ok=True) os.makedirs(common.baremetal_build_lib_dir, exist_ok=True) - common.run_cmd( - [gcc, common.Newline] + - cflags + - [ - '-c', common.Newline, - '-o', bootloader_obj, common.Newline, - os.path.join(common.baremetal_src_lib_dir, '{}{}'.format(args.arch, common.asm_ext)), common.Newline, - ] - ) - for src, obj in [ - (common_src, common_obj), - (syscalls_src, syscalls_obj), - ]: + src = os.path.join(common.baremetal_src_lib_dir, '{}{}'.format(args.arch, common.asm_ext)) + if common.need_rebuild([src], bootloader_obj): common.run_cmd( [gcc, common.Newline] + cflags + [ '-c', common.Newline, - '-D', 'UART0_ADDR={:#x}'.format(uart_address), common.Newline, - '-o', obj, common.Newline, + '-o', bootloader_obj, common.Newline, src, common.Newline, ] ) + for src, obj in [ + (common_src, common_obj), + (syscalls_src, syscalls_obj), + ]: + if common.need_rebuild([src], obj): + common.run_cmd( + [gcc, common.Newline] + + cflags + + [ + '-c', common.Newline, + '-D', 'UART0_ADDR={:#x}'.format(uart_address), common.Newline, + '-o', obj, common.Newline, + src, common.Newline, + ] + ) self._build_dir( '', gcc=gcc, @@ -137,38 +140,39 @@ Build the baremetal examples with crosstool-NG. in_dir = os.path.join(common.baremetal_src_dir, subpath) out_dir = os.path.join(common.baremetal_build_dir, subpath) os.makedirs(out_dir, exist_ok=True) + common_objs = common_objs.copy() if bootloader: - bootloader_cmd = [bootloader_obj, common.Newline] - else: - bootloader_cmd = [] + common_objs.append(bootloader_obj) for in_basename in os.listdir(in_dir): in_path = os.path.join(in_dir, in_basename) if os.path.isfile(in_path) and os.path.splitext(in_basename)[1] in (common.c_ext, common.asm_ext): in_name = os.path.splitext(in_basename)[0] main_obj = os.path.join(common.baremetal_build_dir, subpath, '{}{}'.format(in_name, common.obj_ext)) - common.run_cmd( - [gcc, common.Newline] + - cflags + - [ - '-c', common.Newline, - '-o', main_obj, common.Newline, - os.path.join(common.baremetal_src_dir, in_path), common.Newline, - ] - ) - common.run_cmd( - [gcc, common.Newline] + - cflags + - [ - '-Wl,--section-start=.text={:#x}'.format(entry_address), common.Newline, - '-o', os.path.join(common.baremetal_build_dir, subpath, in_name + common.baremetal_build_ext), common.Newline, - '-T', os.path.join(common.baremetal_src_dir, 'link.ld'), common.Newline, - ] + - bootloader_cmd + - common.add_newlines(common_objs) + - [ - main_obj, common.Newline, - ] - ) + src = os.path.join(common.baremetal_src_dir, in_path) + if common.need_rebuild([src], main_obj): + common.run_cmd( + [gcc, common.Newline] + + cflags + + [ + '-c', common.Newline, + '-o', main_obj, common.Newline, + src, common.Newline, + ] + ) + objs = common_objs + [main_obj] + out = os.path.join(common.baremetal_build_dir, subpath, in_name + common.baremetal_build_ext) + link_script = os.path.join(common.baremetal_src_dir, 'link.ld') + if common.need_rebuild(objs + [link_script], out): + common.run_cmd( + [gcc, common.Newline] + + cflags + + [ + '-Wl,--section-start=.text={:#x}'.format(entry_address), common.Newline, + '-o', out, common.Newline, + '-T', link_script, common.Newline, + ] + + common.add_newlines(objs) + ) if __name__ == '__main__': BaremetalComponent().build() diff --git a/common.py b/common.py index a591b89..5cf552a 100644 --- a/common.py +++ b/common.py @@ -193,6 +193,39 @@ def write_string_to_file(path, string, mode='w'): with open(path, 'a') as f: f.write(string) +def cmd_to_string(cmd, cwd=None, extra_env=None, extra_paths=None): + ''' + Format a command given as a list of strings so that it can + be viewed nicely and executed by bash directly and print it to stdout. + ''' + last_newline = ' \\\n' + newline_separator = last_newline + ' ' + out = [] + if extra_env is None: + extra_env = {} + if cwd is not None: + out.append('cd {} &&'.format(shlex.quote(cwd))) + if extra_paths is not None: + out.append('PATH="{}:${{PATH}}"'.format(':'.join(extra_paths))) + for key in extra_env: + out.append('{}={}'.format(shlex.quote(key), shlex.quote(extra_env[key]))) + cmd_quote = [] + newline_count = 0 + for arg in cmd: + if arg == common.Newline: + cmd_quote.append(arg) + newline_count += 1 + else: + cmd_quote.append(shlex.quote(arg)) + if newline_count > 0: + cmd_quote = [' '.join(list(y)) for x, y in itertools.groupby(cmd_quote, lambda z: z == common.Newline) if not x] + out.extend(cmd_quote) + if newline_count == 1 and cmd[-1] == common.Newline: + ending = '' + else: + ending = last_newline + ';' + return newline_separator.join(out) + ending + def copy_dir_if_update_non_recursive(srcdir, destdir, filter_ext=None): # TODO print rsync equivalent. os.makedirs(destdir, exist_ok=True) @@ -207,6 +240,11 @@ def copy_dir_if_update_non_recursive(srcdir, destdir, filter_ext=None): update=1, ) +def cp(src, dest): + print_cmd(['cp', src, dest]) + if not common.dry_run: + shutil.copy2(src, dest) + def gem_list_checkpoint_dirs(): ''' List checkpoint directory, oldest first. @@ -475,38 +513,13 @@ def make_run_dirs(): os.makedirs(common.p9_dir, exist_ok=True) os.makedirs(common.qemu_run_dir, exist_ok=True) -def cmd_to_string(cmd, cwd=None, extra_env=None, extra_paths=None): - ''' - Format a command given as a list of strings so that it can - be viewed nicely and executed by bash directly and print it to stdout. - ''' - last_newline = ' \\\n' - newline_separator = last_newline + ' ' - out = [] - if extra_env is None: - extra_env = {} - if cwd is not None: - out.append('cd {} &&'.format(shlex.quote(cwd))) - if extra_paths is not None: - out.append('PATH="{}:${{PATH}}"'.format(':'.join(extra_paths))) - for key in extra_env: - out.append('{}={}'.format(shlex.quote(key), shlex.quote(extra_env[key]))) - cmd_quote = [] - newline_count = 0 - for arg in cmd: - if arg == common.Newline: - cmd_quote.append(arg) - newline_count += 1 - else: - cmd_quote.append(shlex.quote(arg)) - if newline_count > 0: - cmd_quote = [' '.join(list(y)) for x, y in itertools.groupby(cmd_quote, lambda z: z == common.Newline) if not x] - out.extend(cmd_quote) - if newline_count == 1 and cmd[-1] == common.Newline: - ending = '' - else: - ending = last_newline + ';' - return newline_separator.join(out) + ending +def need_rebuild(srcs, dst): + if not os.path.exists(dst): + return True + for src in srcs: + if os.path.getmtime(src) > os.path.getmtime(dst): + return True + return False def print_cmd(cmd, cwd=None, cmd_file=None, extra_env=None, extra_paths=None): ''' @@ -576,11 +589,6 @@ def resolve_args(defaults, args, extra_args): argcopy.__dict__ = dict(list(defaults.items()) + list(argcopy.__dict__.items()) + list(extra_args.items())) return argcopy -def cp(src, dest): - print_cmd(['cp', src, dest]) - if not common.dry_run: - shutil.copy2(src, dest) - def rmrf(path): print_cmd(['rm', '-r', '-f', path]) if not common.dry_run and os.path.exists(path):