Commit Graph

10 Commits

Author SHA1 Message Date
John Garry a6dd255bdd bus: hisi_lpc: Fixup IO ports addresses to avoid use-after-free in host removal
Some released ACPI FW for Huawei boards describes incorrect the port IO
address range for child devices, in that it tells us the IO port max range
is 0x3fff for each child device, which is not correct. The address range
should be [e4:e8) or similar. With this incorrect upper range, the child
device IO port resources overlap.

As such, the kernel thinks that the LPC host serial device is a child of
the IPMI device:

root@(none)$ more /proc/ioports
[...]
00ffc0e3-00ffffff : hisi-lpc-ipmi.0.auto
  00ffc0e3-00ffc0e3 : ipmi_si
  00ffc0e4-00ffc0e4 : ipmi_si
  00ffc0e5-00ffc0e5 : ipmi_si
  00ffc2f7-00ffffff : serial8250.1.auto
    00ffc2f7-00ffc2fe : serial
root@(none)$

They should both be siblings. Note that these are logical PIO addresses,
which have a direct mapping from the FW IO port ranges.

This shows up as a real issue when we enable CONFIG_KASAN and
CONFIG_DEBUG_TEST_DRIVER_REMOVE - we see use-after-free warnings in the
host removal path:

==================================================================
BUG: KASAN: use-after-free in release_resource+0x38/0xc8
Read of size 8 at addr ffff0026accdbc38 by task swapper/0/1

CPU: 2 PID: 1 Comm: swapper/0 Not tainted 5.5.0-rc6-00001-g68e186e77b5c-dirty #1593
Hardware name: Huawei Taishan 2180 /D03, BIOS Hisilicon D03 IT20 Nemo 2.0 RC0 03/30/2018
Call trace:
dump_backtrace+0x0/0x290
show_stack+0x14/0x20
dump_stack+0xf0/0x14c
print_address_description.isra.9+0x6c/0x3b8
__kasan_report+0x12c/0x23c
kasan_report+0xc/0x18
__asan_load8+0x94/0xb8
release_resource+0x38/0xc8
platform_device_del.part.10+0x80/0xe0
platform_device_unregister+0x20/0x38
hisi_lpc_acpi_remove_subdev+0x10/0x20
device_for_each_child+0xc8/0x128
hisi_lpc_acpi_remove+0x4c/0xa8
hisi_lpc_remove+0xbc/0xc0
platform_drv_remove+0x3c/0x68
really_probe+0x174/0x548
driver_probe_device+0x7c/0x148
device_driver_attach+0x94/0xa0
__driver_attach+0xa4/0x110
bus_for_each_dev+0xe8/0x158
driver_attach+0x30/0x40
bus_add_driver+0x234/0x2f0
driver_register+0xbc/0x1d0
__platform_driver_register+0x7c/0x88
hisi_lpc_driver_init+0x18/0x20
do_one_initcall+0xb4/0x258
kernel_init_freeable+0x248/0x2c0
kernel_init+0x10/0x118
ret_from_fork+0x10/0x1c

...

The issue here is that the kernel created an incorrect parent-child
resource dependency between two devices, and references the false parent
node when deleting the second child device, when it had been deleted
already.

Fix up the child device resources from FW to create proper IO port
resource relationships for broken FW.

With this, the IO port layout looks more healthy:

root@(none)$ more /proc/ioports
[...]
00ffc0e3-00ffc0e7 : hisi-lpc-ipmi.0.auto
  00ffc0e3-00ffc0e3 : ipmi_si
  00ffc0e4-00ffc0e4 : ipmi_si
  00ffc0e5-00ffc0e5 : ipmi_si
00ffc2f7-00ffc2ff : serial8250.1.auto
  00ffc2f7-00ffc2fe : serial

Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
2020-02-28 17:30:49 +08:00
John Garry 663accf187 bus: hisi_lpc: Clean some types
Sparse complains of these:
drivers/bus/hisi_lpc.c:82:38: warning: incorrect type in argument 1 (different address spaces)
drivers/bus/hisi_lpc.c:82:38:    expected void const volatile [noderef] <asn:2>*addr
drivers/bus/hisi_lpc.c:82:38:    got unsigned char *
drivers/bus/hisi_lpc.c:131:35: warning: incorrect type in argument 1 (different address spaces)
drivers/bus/hisi_lpc.c:131:35:    expected unsigned char *mbase
drivers/bus/hisi_lpc.c:131:35:    got void [noderef] <asn:2>*membase
drivers/bus/hisi_lpc.c:186:35: warning: incorrect type in argument 1 (different address spaces)
drivers/bus/hisi_lpc.c:186:35:    expected unsigned char *mbase
drivers/bus/hisi_lpc.c:186:35:    got void [noderef] <asn:2>*membase
drivers/bus/hisi_lpc.c:228:16: warning: cast to restricted __le32
drivers/bus/hisi_lpc.c:251:13: warning: incorrect type in assignment (different base types)
drivers/bus/hisi_lpc.c:251:13:    expected unsigned int [unsigned] [usertype] val
drivers/bus/hisi_lpc.c:251:13:    got restricted __le32 [usertype] <noident>

Clean them up.

Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
2019-11-05 08:47:21 +08:00
John Garry 10e62b4797 bus: hisi_lpc: Add .remove method to avoid driver unbind crash
The original driver author seemed to be under the impression that a driver
cannot be removed if it does not have a .remove method. Or maybe if it is
a built-in platform driver.

This is not true. This crash can be created:

root@ubuntu:/sys/bus/platform/drivers/hisi-lpc# echo HISI0191\:00 > unbind
root@ubuntu:/sys/bus/platform/drivers/hisi-lpc# ipmitool raw 6 1
 Unable to handle kernel paging request at virtual address ffff000010035010
 Mem abort info:
   ESR = 0x96000047
   Exception class = DABT (current EL), IL = 32 bits
   SET = 0, FnV = 0
   EA = 0, S1PTW = 0
 Data abort info:
   ISV = 0, ISS = 0x00000047
   CM = 0, WnR = 1
 swapper pgtable: 4k pages, 48-bit VAs, pgdp=000000000118b000
 [ffff000010035010] pgd=0000041ffbfff003, pud=0000041ffbffe003, pmd=0000041ffbffd003, pte=0000000000000000
 Internal error: Oops: 96000047 [#1] PREEMPT SMP
 Modules linked in:
 CPU: 17 PID: 1473 Comm: ipmitool Not tainted 5.2.0-rc5-00003-gf68c53b414a3-dirty #198
 Hardware name: Huawei Taishan 2280 /D05, BIOS Hisilicon D05 IT21 Nemo 2.0 RC0 04/18/2018
 pstate: 20000085 (nzCv daIf -PAN -UAO)
 pc : hisi_lpc_target_in+0x7c/0x120
 lr : hisi_lpc_target_in+0x70/0x120
 sp : ffff00001efe3930
 x29: ffff00001efe3930 x28: ffff841f9f599200
 x27: 0000000000000002 x26: 0000000000000000
 x25: 0000000000000080 x24: 00000000000000e4
 x23: 0000000000000000 x22: 0000000000000064
 x21: ffff801fb667d280 x20: 0000000000000001
 x19: ffff00001efe39ac x18: 0000000000000000
 x17: 0000000000000000 x16: 0000000000000000
 x15: 0000000000000000 x14: 0000000000000000
 x13: 0000000000000000 x12: 0000000000000000
 x11: 0000000000000000 x10: 0000000000000000
 x9 : 0000000000000000 x8 : ffff841febe60340
 x7 : ffff801fb55c52e8 x6 : 0000000000000000
 x5 : 0000000000ffc0e3 x4 : 0000000000000001
 x3 : ffff801fb667d280 x2 : 0000000000000001
 x1 : ffff000010035010 x0 : ffff000010035000
 Call trace:
  hisi_lpc_target_in+0x7c/0x120
  hisi_lpc_comm_in+0x88/0x98
  logic_inb+0x5c/0xb8
  port_inb+0x18/0x20
  bt_event+0x38/0x808
  smi_event_handler+0x4c/0x5a0
  check_start_timer_thread.part.4+0x40/0x58
  sender+0x78/0x88
  smi_send.isra.6+0x94/0x108
  i_ipmi_request+0x2c4/0x8f8
  ipmi_request_settime+0x124/0x160
  handle_send_req+0x19c/0x208
  ipmi_ioctl+0x2c0/0x990
  do_vfs_ioctl+0xb8/0x8f8
  ksys_ioctl+0x80/0xb8
  __arm64_sys_ioctl+0x1c/0x28
  el0_svc_common.constprop.0+0x64/0x160
  el0_svc_handler+0x28/0x78
  el0_svc+0x8/0xc
 Code: 941d1511 aa0003f9 f94006a0 91004001 (b9000034)
 ---[ end trace aa842b86af7069e4 ]---

The problem here is that the host goes away but the associated logical PIO
region remains registered, as do the children devices.

Fix by adding a .remove method to tidy-up by removing the child devices
and unregistering the logical PIO region.

Cc: stable@vger.kernel.org
Fixes: adf38bb0b5 ("HISI LPC: Support the LPC host on Hip06/Hip07 with DT bindings")
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
2019-08-13 14:54:34 +08:00
John Garry 1b15a5632a bus: hisi_lpc: Unregister logical PIO range to avoid potential use-after-free
If, after registering a logical PIO range, the driver probe later fails,
the logical PIO range memory will be released automatically.

This causes an issue, in that the logical PIO range is not unregistered
and the released range memory may be later referenced.

Fix by unregistering the logical PIO range.

And since we now unregister the logical PIO range for probe failure, avoid
the special ordering of setting logical PIO range ops, which was the
previous (poor) attempt at a safeguard against this.

Cc: stable@vger.kernel.org
Fixes: adf38bb0b5 ("HISI LPC: Support the LPC host on Hip06/Hip07 with DT bindings")
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
2019-08-13 14:54:28 +08:00
John Garry 705c0ee8d4 bus: hisi_lpc: Don't fail probe for unrecognised child devices
Currently for ACPI-based FW we fail the probe for an unrecognised child
HID.

However, there is FW in the field with LPC child devices having fake HIDs,
namely "IPI0002", which was an IPMI device invented to support the
initial out-of-tree LPC host driver, different from the final mainline
version.

To provide compatibility support for these dodgy FWs, just discard the
unrecognised HIDs instead of failing the probe altogether.

Tested-by: Zengruan Ye <yezengruan@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
2019-02-08 09:18:53 +00:00
John Garry adf3457b4c HISI LPC: Add ACPI UART support
On the Huawei D03 development board the system UART is
the UART connected on the LPC bus.

The profile for the device driver required for this HW
is as follows:
 - platform driver
 - 16550
 - ACPI support
 - polling mode support
 - IO space support

In principle we should use the PNP driver (8250_dw.c) for
8250-devices with ACPI FW. However since this driver does
not support PNP devices, and modifying the PNP core code
to support it is not worth the effort, use the generic
8250 isa driver.

For this, we setup the pdev platform data for the serial
8250 port.

Signed-off-by: John Garry <john.garry@huawei.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
2018-05-10 17:45:52 +01:00
John Garry 99c0228d6f HISI LPC: Re-Add ACPI child enumeration support
Since we no longer use the MFD APIs to enumerate the
child devices on the bus, use the platform driver APIs
directly.

In this patch we iterate of the children devices for the
host, and create a platform device directly per child.

For the iterating, we match the child ACPI HID against a
known list of supported child devices and their respective
ACPIs HID, to find the device name and any other
supplementary data.

Signed-off-by: John Garry <john.garry@huawei.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
2018-05-10 17:35:46 +01:00
John Garry 332f632ec3 HISI LPC: Stop using MFD APIs
The MFD APIs should only be used by drivers in
drivers/mfd. It is not worth splitting the driver to have
separate parts in drivers/bus and drivers/mfd, so just
drop MFD API usage.

As a solution, we will use the platform device APIs directly
to achieve the same as we had when using MFD APIs.

Signed-off-by: John Garry <john.garry@huawei.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
2018-05-10 17:30:06 +01:00
John Garry e0aa1563f8 HISI LPC: Add ACPI support
Based on the previous patches, this patch supports the LPC host on
Hip06/Hip07 for ACPI FW.

It is the responsibility of the LPC host driver to enumerate the child
devices, as the ACPI scan code will not enumerate children of "indirect IO"
hosts.

The ACPI table for the LPC host controller and the child devices is in the
following format:

  Device (LPC0) {
    Name (_HID, "HISI0191")  // HiSi LPC
    Name (_CRS, ResourceTemplate () {
      Memory32Fixed (ReadWrite, 0xa01b0000, 0x1000)
    })
  }

  Device (LPC0.IPMI) {
    Name (_HID, "IPI0001")
    Name (LORS, ResourceTemplate() {
      QWordIO (
        ResourceConsumer,
        MinNotFixed,     // _MIF
        MaxNotFixed,     // _MAF
        PosDecode,
        EntireRange,
        0x0,             // _GRA
        0xe4,            // _MIN
        0x3fff,          // _MAX
        0x0,             // _TRA
        0x04,            // _LEN
        , ,
        BTIO
      )
    })

Since the IO resources of the child devices need to be translated from LPC
bus addresses to logical PIO addresses, and we shouldn't modify the
resources of the devices generated in the FW scan, a per-child MFD is
created as a substitute.  The MFD IO resources will be the translated bus
addresses of the ACPI child.

Tested-by: dann frazier <dann.frazier@canonical.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Zhichang Yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
2018-04-04 08:42:51 -05:00
Zhichang Yuan adf38bb0b5 HISI LPC: Support the LPC host on Hip06/Hip07 with DT bindings
The low-pin-count (LPC) interface of Hip06/Hip07 accesses I/O port space of
peripherals.

Implement the LPC host controller driver which performs the I/O operations
on the underlying hardware.  We don't want to touch existing drivers such
as ipmi-bt, so this driver applies the indirect-IO introduced in the
previous patch after registering an indirect-IO node to the indirect-IO
devices list which will be searched by the I/O accessors to retrieve the
host-local I/O port.

The driver config is set as a bool instead of a tristate.  The reason here
is that, by the very nature of the driver providing a logical PIO range, it
does not make sense to have this driver as a loadable module.  Another more
specific reason is that the Huawei D03 board which includes Hip06 SoC
requires the LPC bus for UART console, so should be built in.

Tested-by: dann frazier <dann.frazier@canonical.com>
Signed-off-by: Zou Rongrong <zourongrong@huawei.com>
Signed-off-by: Zhichang Yuan <yuanzhichang@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>	# dts part
2018-04-04 08:42:48 -05:00