https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=299089

            Bug ID: 299089
           Summary: uart: hw.uart.console with an mm: address faults on
                    riscv and arm (NULL bus space tag)
           Product: Base System
           Version: 15.1-RELEASE
          Hardware: riscv
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: [email protected]
          Reporter: [email protected]

Created attachment 275336
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=275336&action=edit
[PATCH] uart: Set the bus space tag before parsing hw.uart.console

DESCRIPTION

On riscv and arm the console is found by uart_cpu_getdev() in
uart_cpu_fdt.c.  It calls uart_getenv() first, so that hw.uart.console can
override the FDT.  For an "mm:" address uart_getenv() maps the UART with
uart_bus_space_mem, but uart_cpu_fdt.c only assigns that variable at the
end of uart_cpu_getdev(), after the FDT probe.  On the override path it is
still NULL and bus_space_map() dereferences it (uart_subr.c:324).  This
happens while the console is being set up, so the kernel hangs with no
output.

arm64 doesn't have this problem because uart_cpu_arm64.c initialises
uart_bus_space_mem to &memmap_bus.

On 15.x riscv this is hit without any user setting when booting through
loader.efi on firmware that provides an ACPI SPCR table:
check_acpi_spcr() in the loader turns the SPCR into hw.uart.console.

The attached patch sets uart_bus_space_mem to fdtbus_bs_tag before calling
uart_getenv().  fdtbus_bs_tag is defined on both riscv and arm, but no
riscv header declares it, so the patch adds a file-scope extern, the way
riscv's ofw_machdep.c and nexus.c declare memmap_bus.  (b1c2e02c10 removed
an earlier extern of fdtbus_bs_tag from this file when it stopped being
used.)


AFFECTED VERSIONS

main, stable/15, releng/15.1, stable/14 and releng/14.4.  On 14.x the
loader doesn't set hw.uart.console from SPCR, so it only happens when the
variable is set by hand.


HOW TO REPEAT

On a riscv system, set hw.uart.console to the console UART's address at
the loader prompt and boot.  For example, on a QEMU virt machine:

  OK set hw.uart.console=mm:0x10000000,rs:0,rw:1,br:115200
  OK boot

or boot QEMU's riscv virt machine through its bundled EDK2 firmware
(edk2-riscv64-code.fd) with ACPI enabled, which provides an SPCR table.


TESTED

15.1-RELEASE-p3, riscv64 GENERIC, booted through loader.efi:

  kernel             result
  15.1-RELEASE-p3    hangs at the console probe (NULL tag)
  with patch         maps the UART from hw.uart.console

With hw.uart.console="mm:0x10000000,rs:0,rw:1,br:115200,xo:0" set at the
loader prompt, the patched kernel boots to multi-user with uart0 as
console.  Not tested on arm or on riscv hardware.

Booting all the way from SPCR alone also needs the SPCR to describe the
UART correctly.  QEMU's riscv virt table currently gives a 32-bit register
stride for a byte-spaced UART; that is being reported to QEMU.  A related
loader bug, where hw.uart.console from loader.conf is overwritten by the
SPCR value, is filed separately.


ATTACHMENTS

0001-uart-Set-the-bus-space-tag-before-parsing-hw.uart.co.patch
  against main ff2efe65a89a

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to