From e042a1b2adbb440ae18ec567559ef4b25c7e73a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciro=20Santilli=20=E5=85=AD=E5=9B=9B=E4=BA=8B=E4=BB=B6=20?= =?UTF-8?q?=E6=B3=95=E8=BD=AE=E5=8A=9F?= Date: Wed, 31 Oct 2018 22:00:02 +0000 Subject: [PATCH] console: make awesome --- README.adoc | 64 ++++++++++++++++++++++++++++++++++--------- common.py | 3 ++ download-dependencies | 1 + run | 31 +++++++++++++-------- 4 files changed, 74 insertions(+), 25 deletions(-) diff --git a/README.adoc b/README.adoc index 038b10a..d17066c 100644 --- a/README.adoc +++ b/README.adoc @@ -1832,34 +1832,68 @@ It is useless with QEMU since we already have full system visibility with `-gdb` Cheaper than JTAG (free) and easier to setup (all you need is serial), but with less visibility as it depends on the kernel working, so e.g.: dies on panic, does not see boot sequence. -Usage: +First run the kernel with: .... ./run --kgdb -./run-gdb --kgdb .... -In GDB: +this passes the following options on the kernel CLI: .... -c +kgdbwait kgdboc=ttyS1,115200 .... -In QEMU: +`kgdbwait` tells the kernel to wait for KGDB to connect. + +So the kernel sets things up enough for KGDB to start working, and then boot pauses waiting for connection: + +.... +<6>[ 4.866050] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled +<6>[ 4.893205] 00:05: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A +<6>[ 4.916271] 00:06: ttyS1 at I/O 0x2f8 (irq = 3, base_baud = 115200) is a 16550A +<6>[ 4.987771] KGDB: Registered I/O driver kgdboc +<2>[ 4.996053] KGDB: Waiting for connection from remote gdb... + +Entering kdb (current=0x(____ptrval____), pid 1) on processor 0 due to Keyboard Entry +[0]kdb> +.... + +KGDB expects the connection at `ttyS1`, our second serial port after `ttyS0` which contains the terminal. + +So now we can connect to the serial port with GDB: + +.... +./run-gdb --kgdb --no-continue +.... + +Once GDB connects, it is left inside the function `kgdb_breakpoint`. + +So now we can set breakpoints and continue as usual. + +For example, in GDB: + +.... +continue +.... + +Then in QEMU: .... /count.sh & /kgdb.sh .... -In GDB: +link:rootfs_overlay:kgdb.sh[] pauses the kernel for KGDB, and gives control back to GDB. + +And now in GDB we do the usual: .... -b __x64_sys_write -c -c -c -c +break __x64_sys_write +continue +continue +continue +continue .... And now you can count from GDB! @@ -1873,9 +1907,11 @@ See also: === KGDB ARM -GDB not connecting to KGDB in ARM. Possibly linked to `-serial stdio`. See also: https://stackoverflow.com/questions/14155577/how-to-use-kgdb-on-arm +GDB not connecting to KGDB in `arm` and `aarch64`. -Main shell just falls on: +Main question: https://stackoverflow.com/questions/14155577/how-to-use-kgdb-on-arm + +The main console just hangs on: .... Entering kdb (current=0xf8ce07d3, pid 1) due to Keyboard Entry @@ -1893,6 +1929,8 @@ Ignoring packet error, continuing... Remote replied unexpectedly to 'vMustReplyEmpty': timeout .... +I wanted to try to and run run KGDB on a second serial to see if it makes a difference, but QEMU `-M virt` does not seem to support it: https://stackoverflow.com/questions/53080745/can-qemu-m-virt-on-arm-aarch64-have-multiple-serial-ttys-like-such-as-pl011-t + === KGDB kernel modules In QEMU: diff --git a/common.py b/common.py index 214215c..51285bd 100644 --- a/common.py +++ b/common.py @@ -670,6 +670,7 @@ def setup(parser): args.gem5_build_id = args.gem5_worktree this_module.machine = args.machine this_module.setup_dry_run_arguments(args) + this_module.is_arm = False if args.arch == 'arm': this_module.armv = 7 this_module.gem5_arch = 'ARM' @@ -683,6 +684,7 @@ def setup(parser): else: if this_module.machine is None: this_module.machine = 'virt' + this_module.is_arm = True elif args.arch == 'aarch64': this_module.armv = 8 this_module.gem5_arch = 'ARM' @@ -696,6 +698,7 @@ def setup(parser): else: if this_module.machine is None: this_module.machine = 'virt' + this_module.is_arm = True elif args.arch == 'x86_64': this_module.crosstool_ng_toolchain_prefix = 'x86_64-unknown-elf' this_module.gem5_arch = 'X86' diff --git a/download-dependencies b/download-dependencies index d9561d0..f13f125 100755 --- a/download-dependencies +++ b/download-dependencies @@ -117,6 +117,7 @@ scons \ if "$baremetal"; then pkgs="${pkgs} \ docbook2x \ +libtool-bin \ " fi command -v apt-get >/dev/null 2>&1 || { diff --git a/run b/run index ad8a652..76cad7b 100755 --- a/run +++ b/run @@ -81,11 +81,22 @@ def main(args, extra_args=None): kernel_cli += ' {}=/eval_base64.sh'.format(initarg) kernel_cli_after_dash += ' lkmc_eval="{}"'.format(common.base64_encode(args.eval)) if not args.graphic: - if args.arch == 'x86_64': - kernel_cli += ' console=ttyS0' - else: - kernel_cli += ' console=ttyAMA0' extra_qemu_args.append('-nographic') + console = None + console_type = None + console_count = 0 + if args.arch == 'x86_64': + console_type = 'ttyS' + elif common.is_arm: + console_type = 'ttyAMA' + console = '{}{}'.format(console_type, console_count) + if not (args.arch == 'x86_64' and args.graphic): + console_count += 1 + kernel_cli += ' console={}'.format(console) + extra_console = '{}{}'.format(console_type, console_count) + console_count += 1 + if args.kgdb: + kernel_cli += ' kgdboc={},115200'.format(console) if kernel_cli_after_dash: kernel_cli += " -{}".format(kernel_cli_after_dash) extra_env = {} @@ -161,12 +172,12 @@ def main(args, extra_args=None): if args.arch == 'x86_64': if args.kvm: cmd.extend(['--cpu-type', 'X86KvmCPU']) - cmd.extend(['--command-line', 'earlyprintk=ttyS0 lpj=7999923 root=/dev/sda {}'.format(kernel_cli)]) - elif args.arch == 'arm' or args.arch == 'aarch64': + cmd.extend(['--command-line', 'earlyprintk={} lpj=7999923 root=/dev/sda {}'.format(console, kernel_cli)]) + elif common.is_arm: # TODO why is it mandatory to pass mem= here? Not true for QEMU. # Anything smaller than physical blows up as expected, but why can't it auto-detect the right value? cmd.extend([ - '--command-line', 'earlyprintk=pl011,0x1c090000 console=ttyAMA0 lpj=19988480 rw loglevel=8 mem={} root=/dev/sda {}'.format(memory, kernel_cli), + '--command-line', 'earlyprintk=pl011,0x1c090000 lpj=19988480 rw loglevel=8 mem={} root=/dev/sda {}'.format(memory, kernel_cli), '--dtb-filename', os.path.join(common.gem5_system_dir, 'arm', 'dt', 'armv{}_gem5_v1_{}cpu.dtb'.format(common.armv, args.cpus)), '--machine-type', common.machine, '--param', 'system.panic_on_panic = True', @@ -295,17 +306,13 @@ def main(args, extra_args=None): else: virtio_gpu_pci = ['-device', 'virtio-gpu-pci'] if args.arch == 'x86_64': - if args.kgdb: - kernel_cli += ' kgdboc=ttyS1,115200' append = ['-append', '{} nopat {}'.format(root, kernel_cli)] cmd.extend([ '-M', common.machine, '-device', 'edu', ]) - elif args.arch == 'arm' or args.arch == 'aarch64': + elif common.is_arm: extra_emulator_args.append('-semihosting') - if args.kgdb: - kernel_cli += ' kgdboc=ttyAMA0,115200' if args.arch == 'arm': cpu = 'cortex-a15' else: