2019-05-29 17:18:01 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-03-28 19:11:27 +03:00
/*
* coreboot_table . c
*
* Module providing coreboot table access .
*
* Copyright 2017 Google Inc .
2018-01-25 04:41:16 +03:00
* Copyright 2017 Samuel Holland < samuel @ sholland . org >
2017-03-28 19:11:27 +03:00
*/
2018-08-15 23:37:06 +03:00
# include <linux/acpi.h>
2018-01-25 04:41:16 +03:00
# include <linux/device.h>
2017-03-28 19:11:27 +03:00
# include <linux/err.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
2018-08-15 23:37:06 +03:00
# include <linux/of.h>
# include <linux/platform_device.h>
2018-01-25 04:41:16 +03:00
# include <linux/slab.h>
2017-03-28 19:11:27 +03:00
# include "coreboot_table.h"
2018-01-25 04:41:16 +03:00
# define CB_DEV(d) container_of(d, struct coreboot_device, dev)
# define CB_DRV(d) container_of(d, struct coreboot_driver, drv)
2017-03-28 19:11:27 +03:00
2018-01-25 04:41:16 +03:00
static int coreboot_bus_match ( struct device * dev , struct device_driver * drv )
{
struct coreboot_device * device = CB_DEV ( dev ) ;
struct coreboot_driver * driver = CB_DRV ( drv ) ;
return device - > entry . tag = = driver - > tag ;
}
static int coreboot_bus_probe ( struct device * dev )
{
int ret = - ENODEV ;
struct coreboot_device * device = CB_DEV ( dev ) ;
struct coreboot_driver * driver = CB_DRV ( dev - > driver ) ;
if ( driver - > probe )
ret = driver - > probe ( device ) ;
return ret ;
}
2021-07-13 22:35:22 +03:00
static void coreboot_bus_remove ( struct device * dev )
2018-01-25 04:41:16 +03:00
{
struct coreboot_device * device = CB_DEV ( dev ) ;
struct coreboot_driver * driver = CB_DRV ( dev - > driver ) ;
if ( driver - > remove )
2021-01-27 00:53:39 +03:00
driver - > remove ( device ) ;
2018-01-25 04:41:16 +03:00
}
static struct bus_type coreboot_bus_type = {
. name = " coreboot " ,
. match = coreboot_bus_match ,
. probe = coreboot_bus_probe ,
. remove = coreboot_bus_remove ,
} ;
static void coreboot_device_release ( struct device * dev )
{
struct coreboot_device * device = CB_DEV ( dev ) ;
kfree ( device ) ;
}
int coreboot_driver_register ( struct coreboot_driver * driver )
{
driver - > drv . bus = & coreboot_bus_type ;
return driver_register ( & driver - > drv ) ;
}
EXPORT_SYMBOL ( coreboot_driver_register ) ;
void coreboot_driver_unregister ( struct coreboot_driver * driver )
{
driver_unregister ( & driver - > drv ) ;
}
EXPORT_SYMBOL ( coreboot_driver_unregister ) ;
2018-08-15 23:37:08 +03:00
static int coreboot_table_populate ( struct device * dev , void * ptr )
2017-03-28 19:11:27 +03:00
{
2018-01-25 04:41:16 +03:00
int i , ret ;
void * ptr_entry ;
struct coreboot_device * device ;
2018-08-15 23:37:07 +03:00
struct coreboot_table_entry * entry ;
2018-08-15 23:37:08 +03:00
struct coreboot_table_header * header = ptr ;
2017-03-28 19:11:27 +03:00
2018-08-15 23:37:08 +03:00
ptr_entry = ptr + header - > header_bytes ;
2018-08-15 23:37:07 +03:00
for ( i = 0 ; i < header - > table_entries ; i + + ) {
entry = ptr_entry ;
2018-01-25 04:41:16 +03:00
2023-01-13 02:03:16 +03:00
if ( entry - > size < sizeof ( * entry ) ) {
dev_warn ( dev , " coreboot table entry too small! \n " ) ;
return - EINVAL ;
}
device = kzalloc ( sizeof ( device - > dev ) + entry - > size , GFP_KERNEL ) ;
2018-08-15 23:37:08 +03:00
if ( ! device )
return - ENOMEM ;
2018-01-25 04:41:16 +03:00
device - > dev . parent = dev ;
device - > dev . bus = & coreboot_bus_type ;
device - > dev . release = coreboot_device_release ;
2023-01-13 02:03:16 +03:00
memcpy ( device - > raw , ptr_entry , entry - > size ) ;
2018-01-25 04:41:16 +03:00
2022-11-04 19:15:28 +03:00
switch ( device - > entry . tag ) {
case LB_TAG_CBMEM_ENTRY :
dev_set_name ( & device - > dev , " cbmem-%08x " ,
device - > cbmem_entry . id ) ;
break ;
default :
dev_set_name ( & device - > dev , " coreboot%d " , i ) ;
break ;
}
2018-01-25 04:41:16 +03:00
ret = device_register ( & device - > dev ) ;
if ( ret ) {
put_device ( & device - > dev ) ;
2018-08-15 23:37:08 +03:00
return ret ;
2018-01-25 04:41:16 +03:00
}
2018-08-15 23:37:07 +03:00
ptr_entry + = entry - > size ;
2018-01-25 04:41:16 +03:00
}
2018-08-15 23:37:05 +03:00
2018-08-15 23:37:08 +03:00
return 0 ;
2017-03-28 19:11:27 +03:00
}
2018-08-15 23:37:06 +03:00
static int coreboot_table_probe ( struct platform_device * pdev )
{
resource_size_t len ;
2018-08-15 23:37:07 +03:00
struct coreboot_table_header * header ;
2018-08-15 23:37:06 +03:00
struct resource * res ;
2018-08-15 23:37:08 +03:00
struct device * dev = & pdev - > dev ;
2018-08-15 23:37:07 +03:00
void * ptr ;
2018-08-15 23:37:08 +03:00
int ret ;
2018-08-15 23:37:06 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
return - EINVAL ;
len = resource_size ( res ) ;
if ( ! res - > start | | ! len )
return - EINVAL ;
2018-08-15 23:37:08 +03:00
/* Check just the header first to make sure things are sane */
2018-08-15 23:37:07 +03:00
header = memremap ( res - > start , sizeof ( * header ) , MEMREMAP_WB ) ;
2018-08-15 23:37:08 +03:00
if ( ! header )
2018-08-15 23:37:06 +03:00
return - ENOMEM ;
2018-08-15 23:37:08 +03:00
len = header - > header_bytes + header - > table_bytes ;
ret = strncmp ( header - > signature , " LBIO " , sizeof ( header - > signature ) ) ;
2018-08-15 23:37:07 +03:00
memunmap ( header ) ;
2018-08-15 23:37:08 +03:00
if ( ret ) {
dev_warn ( dev , " coreboot table missing or corrupt! \n " ) ;
return - ENODEV ;
}
ptr = memremap ( res - > start , len , MEMREMAP_WB ) ;
2018-08-15 23:37:06 +03:00
if ( ! ptr )
return - ENOMEM ;
firmware: coreboot: Register bus in module init
The coreboot_table driver registers a coreboot bus while probing a
"coreboot_table" device representing the coreboot table memory region.
Probing this device (i.e., registering the bus) is a dependency for the
module_init() functions of any driver for this bus (e.g.,
memconsole-coreboot.c / memconsole_driver_init()).
With synchronous probe, this dependency works OK, as the link order in
the Makefile ensures coreboot_table_driver_init() (and thus,
coreboot_table_probe()) completes before a coreboot device driver tries
to add itself to the bus.
With asynchronous probe, however, coreboot_table_probe() may race with
memconsole_driver_init(), and so we're liable to hit one of these two:
1. coreboot_driver_register() eventually hits "[...] the bus was not
initialized.", and the memconsole driver fails to register; or
2. coreboot_driver_register() gets past #1, but still races with
bus_register() and hits some other undefined/crashing behavior (e.g.,
in driver_find() [1])
We can resolve this by registering the bus in our initcall, and only
deferring "device" work (scanning the coreboot memory region and
creating sub-devices) to probe().
[1] Example failure, using 'driver_async_probe=*' kernel command line:
[ 0.114217] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010
...
[ 0.114307] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 6.1.0-rc1 #63
[ 0.114316] Hardware name: Google Scarlet (DT)
...
[ 0.114488] Call trace:
[ 0.114494] _raw_spin_lock+0x34/0x60
[ 0.114502] kset_find_obj+0x28/0x84
[ 0.114511] driver_find+0x30/0x50
[ 0.114520] driver_register+0x64/0x10c
[ 0.114528] coreboot_driver_register+0x30/0x3c
[ 0.114540] memconsole_driver_init+0x24/0x30
[ 0.114550] do_one_initcall+0x154/0x2e0
[ 0.114560] do_initcall_level+0x134/0x160
[ 0.114571] do_initcalls+0x60/0xa0
[ 0.114579] do_basic_setup+0x28/0x34
[ 0.114588] kernel_init_freeable+0xf8/0x150
[ 0.114596] kernel_init+0x2c/0x12c
[ 0.114607] ret_from_fork+0x10/0x20
[ 0.114624] Code: 5280002b 1100054a b900092a f9800011 (885ffc01)
[ 0.114631] ---[ end trace 0000000000000000 ]---
Fixes: b81e3140e412 ("firmware: coreboot: Make bus registration symmetric")
Cc: <stable@vger.kernel.org>
Signed-off-by: Brian Norris <briannorris@chromium.org>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Link: https://lore.kernel.org/r/20221019180934.1.If29e167d8a4771b0bf4a39c89c6946ed764817b9@changeid
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-10-20 04:10:53 +03:00
ret = coreboot_table_populate ( dev , ptr ) ;
2018-08-15 23:37:08 +03:00
memunmap ( ptr ) ;
return ret ;
2018-08-15 23:37:06 +03:00
}
2019-11-18 13:19:29 +03:00
static int __cb_dev_unregister ( struct device * dev , void * dummy )
{
device_unregister ( dev ) ;
return 0 ;
}
2018-08-15 23:37:06 +03:00
static int coreboot_table_remove ( struct platform_device * pdev )
2017-03-28 19:11:27 +03:00
{
2019-11-18 13:19:29 +03:00
bus_for_each_dev ( & coreboot_bus_type , NULL , NULL , __cb_dev_unregister ) ;
2017-03-28 19:11:27 +03:00
return 0 ;
}
2018-08-15 23:37:06 +03:00
# ifdef CONFIG_ACPI
static const struct acpi_device_id cros_coreboot_acpi_match [ ] = {
{ " GOOGCB00 " , 0 } ,
{ " BOOT0000 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , cros_coreboot_acpi_match ) ;
# endif
# ifdef CONFIG_OF
static const struct of_device_id coreboot_of_match [ ] = {
{ . compatible = " coreboot " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , coreboot_of_match ) ;
# endif
static struct platform_driver coreboot_table_driver = {
. probe = coreboot_table_probe ,
. remove = coreboot_table_remove ,
. driver = {
. name = " coreboot_table " ,
. acpi_match_table = ACPI_PTR ( cros_coreboot_acpi_match ) ,
. of_match_table = of_match_ptr ( coreboot_of_match ) ,
} ,
} ;
firmware: coreboot: Register bus in module init
The coreboot_table driver registers a coreboot bus while probing a
"coreboot_table" device representing the coreboot table memory region.
Probing this device (i.e., registering the bus) is a dependency for the
module_init() functions of any driver for this bus (e.g.,
memconsole-coreboot.c / memconsole_driver_init()).
With synchronous probe, this dependency works OK, as the link order in
the Makefile ensures coreboot_table_driver_init() (and thus,
coreboot_table_probe()) completes before a coreboot device driver tries
to add itself to the bus.
With asynchronous probe, however, coreboot_table_probe() may race with
memconsole_driver_init(), and so we're liable to hit one of these two:
1. coreboot_driver_register() eventually hits "[...] the bus was not
initialized.", and the memconsole driver fails to register; or
2. coreboot_driver_register() gets past #1, but still races with
bus_register() and hits some other undefined/crashing behavior (e.g.,
in driver_find() [1])
We can resolve this by registering the bus in our initcall, and only
deferring "device" work (scanning the coreboot memory region and
creating sub-devices) to probe().
[1] Example failure, using 'driver_async_probe=*' kernel command line:
[ 0.114217] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010
...
[ 0.114307] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 6.1.0-rc1 #63
[ 0.114316] Hardware name: Google Scarlet (DT)
...
[ 0.114488] Call trace:
[ 0.114494] _raw_spin_lock+0x34/0x60
[ 0.114502] kset_find_obj+0x28/0x84
[ 0.114511] driver_find+0x30/0x50
[ 0.114520] driver_register+0x64/0x10c
[ 0.114528] coreboot_driver_register+0x30/0x3c
[ 0.114540] memconsole_driver_init+0x24/0x30
[ 0.114550] do_one_initcall+0x154/0x2e0
[ 0.114560] do_initcall_level+0x134/0x160
[ 0.114571] do_initcalls+0x60/0xa0
[ 0.114579] do_basic_setup+0x28/0x34
[ 0.114588] kernel_init_freeable+0xf8/0x150
[ 0.114596] kernel_init+0x2c/0x12c
[ 0.114607] ret_from_fork+0x10/0x20
[ 0.114624] Code: 5280002b 1100054a b900092a f9800011 (885ffc01)
[ 0.114631] ---[ end trace 0000000000000000 ]---
Fixes: b81e3140e412 ("firmware: coreboot: Make bus registration symmetric")
Cc: <stable@vger.kernel.org>
Signed-off-by: Brian Norris <briannorris@chromium.org>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Link: https://lore.kernel.org/r/20221019180934.1.If29e167d8a4771b0bf4a39c89c6946ed764817b9@changeid
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-10-20 04:10:53 +03:00
static int __init coreboot_table_driver_init ( void )
{
int ret ;
ret = bus_register ( & coreboot_bus_type ) ;
if ( ret )
return ret ;
ret = platform_driver_register ( & coreboot_table_driver ) ;
if ( ret ) {
bus_unregister ( & coreboot_bus_type ) ;
return ret ;
}
return 0 ;
}
static void __exit coreboot_table_driver_exit ( void )
{
platform_driver_unregister ( & coreboot_table_driver ) ;
bus_unregister ( & coreboot_bus_type ) ;
}
module_init ( coreboot_table_driver_init ) ;
module_exit ( coreboot_table_driver_exit ) ;
2017-03-28 19:11:27 +03:00
MODULE_AUTHOR ( " Google, Inc. " ) ;
MODULE_LICENSE ( " GPL " ) ;