2019-05-19 13:08:20 +01:00
// SPDX-License-Identifier: GPL-2.0-only
2020-11-09 18:21:45 +00:00
/*
2006-05-14 01:51:54 +01:00
* Copyright ( c ) ? ? ? ? Jochen Schäuble < psionic @ psionic . de >
2008-02-06 01:38:02 -08:00
* Copyright ( c ) 2003 - 2004 Joern Engel < joern @ wh . fh - wedel . de >
2005-04-16 15:20:36 -07:00
*
* Usage :
*
* one commend line parameter per device , each in the form :
2020-12-07 17:55:29 +08:00
* phram = < name > , < start > , < len > [ , < erasesize > ]
2005-04-16 15:20:36 -07:00
* < name > may be up to 63 characters .
2020-12-07 17:55:29 +08:00
* < start > , < len > , and < erasesize > can be octal , decimal or hexadecimal . If followed
2005-04-16 15:20:36 -07:00
* by " ki " , " Mi " or " Gi " , the numbers will be interpreted as kilo , mega or
2020-12-07 17:55:29 +08:00
* gigabytes . < erasesize > is optional and defaults to PAGE_SIZE .
2005-04-16 15:20:36 -07:00
*
* Example :
2020-12-07 17:55:29 +08:00
* phram = swap , 64 Mi , 128 Mi phram = test , 900 Mi , 1 Mi , 64 Ki
2005-04-16 15:20:36 -07:00
*/
2009-06-16 19:20:40 +00:00
2010-10-20 10:39:22 -07:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2009-06-16 19:20:40 +00:00
2014-10-21 20:01:09 +01:00
# include <linux/io.h>
2005-04-16 15:20:36 -07:00
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
2005-10-30 15:03:48 -08:00
# include <linux/slab.h>
2005-04-16 15:20:36 -07:00
# include <linux/mtd/mtd.h>
2020-12-07 17:55:29 +08:00
# include <asm/div64.h>
2022-04-12 15:53:01 +02:00
# include <linux/platform_device.h>
# include <linux/of_address.h>
# include <linux/of.h>
2005-04-16 15:20:36 -07:00
struct phram_mtd_list {
struct mtd_info mtd ;
struct list_head list ;
2022-05-10 17:18:22 +02:00
bool cached ;
2005-04-16 15:20:36 -07:00
} ;
static LIST_HEAD ( phram_list ) ;
static int phram_erase ( struct mtd_info * mtd , struct erase_info * instr )
{
u_char * start = mtd - > priv ;
memset ( start + instr - > addr , 0xff , instr - > len ) ;
return 0 ;
}
static int phram_point ( struct mtd_info * mtd , loff_t from , size_t len ,
2008-04-29 23:26:49 -07:00
size_t * retlen , void * * virt , resource_size_t * phys )
2005-04-16 15:20:36 -07:00
{
2008-04-29 23:26:49 -07:00
* virt = mtd - > priv + from ;
2005-04-16 15:20:36 -07:00
* retlen = len ;
return 0 ;
}
2012-02-03 13:20:43 +02:00
static int phram_unpoint ( struct mtd_info * mtd , loff_t from , size_t len )
2005-04-16 15:20:36 -07:00
{
2012-02-03 13:20:43 +02:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
static int phram_read ( struct mtd_info * mtd , loff_t from , size_t len ,
size_t * retlen , u_char * buf )
{
u_char * start = mtd - > priv ;
memcpy ( buf , start + from , len ) ;
* retlen = len ;
return 0 ;
}
static int phram_write ( struct mtd_info * mtd , loff_t to , size_t len ,
size_t * retlen , const u_char * buf )
{
u_char * start = mtd - > priv ;
memcpy ( start + to , buf , len ) ;
* retlen = len ;
return 0 ;
}
2022-05-10 17:18:22 +02:00
static int phram_map ( struct phram_mtd_list * phram , phys_addr_t start , size_t len )
{
void * addr = NULL ;
if ( phram - > cached )
addr = memremap ( start , len , MEMREMAP_WB ) ;
else
addr = ( void __force * ) ioremap ( start , len ) ;
if ( ! addr )
return - EIO ;
phram - > mtd . priv = addr ;
return 0 ;
}
static void phram_unmap ( struct phram_mtd_list * phram )
{
void * addr = phram - > mtd . priv ;
if ( phram - > cached ) {
memunmap ( addr ) ;
return ;
}
iounmap ( ( void __iomem * ) addr ) ;
}
2005-04-16 15:20:36 -07:00
static void unregister_devices ( void )
{
2005-02-23 19:37:11 +00:00
struct phram_mtd_list * this , * safe ;
2005-04-16 15:20:36 -07:00
2005-02-23 19:37:11 +00:00
list_for_each_entry_safe ( this , safe , & phram_list , list ) {
2011-05-23 10:23:40 +01:00
mtd_device_unregister ( & this - > mtd ) ;
2022-05-10 17:18:22 +02:00
phram_unmap ( this ) ;
2011-01-30 10:31:48 +01:00
kfree ( this - > mtd . name ) ;
2005-04-16 15:20:36 -07:00
kfree ( this ) ;
}
}
2022-04-12 15:53:01 +02:00
static int register_device ( struct platform_device * pdev , const char * name ,
phys_addr_t start , size_t len , uint32_t erasesize )
2005-04-16 15:20:36 -07:00
{
2022-04-12 15:53:01 +02:00
struct device_node * np = pdev ? pdev - > dev . of_node : NULL ;
2022-05-10 17:18:22 +02:00
bool cached = np ? ! of_property_read_bool ( np , " no-map " ) : false ;
2005-04-16 15:20:36 -07:00
struct phram_mtd_list * new ;
int ret = - ENOMEM ;
2006-11-15 21:10:29 +02:00
new = kzalloc ( sizeof ( * new ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! new )
goto out0 ;
2022-05-10 17:18:22 +02:00
new - > cached = cached ;
ret = phram_map ( new , start , len ) ;
if ( ret ) {
2009-06-16 19:20:40 +00:00
pr_err ( " ioremap failed \n " ) ;
2005-04-16 15:20:36 -07:00
goto out1 ;
}
new - > mtd . name = name ;
new - > mtd . size = len ;
2006-04-13 18:54:34 +02:00
new - > mtd . flags = MTD_CAP_RAM ;
2012-01-30 14:58:32 +02:00
new - > mtd . _erase = phram_erase ;
new - > mtd . _point = phram_point ;
new - > mtd . _unpoint = phram_unpoint ;
new - > mtd . _read = phram_read ;
new - > mtd . _write = phram_write ;
2005-04-16 15:20:36 -07:00
new - > mtd . owner = THIS_MODULE ;
2006-06-14 21:39:48 +01:00
new - > mtd . type = MTD_RAM ;
2020-12-07 17:55:29 +08:00
new - > mtd . erasesize = erasesize ;
2006-06-22 18:15:48 +04:00
new - > mtd . writesize = 1 ;
2005-04-16 15:20:36 -07:00
2022-04-12 15:53:01 +02:00
mtd_set_of_node ( & new - > mtd , np ) ;
2005-04-16 15:20:36 -07:00
ret = - EAGAIN ;
2011-05-23 10:23:40 +01:00
if ( mtd_device_register ( & new - > mtd , NULL , 0 ) ) {
2009-06-16 19:20:40 +00:00
pr_err ( " Failed to register new device \n " ) ;
2005-04-16 15:20:36 -07:00
goto out2 ;
}
2022-04-12 15:53:01 +02:00
if ( pdev )
platform_set_drvdata ( pdev , new ) ;
else
list_add_tail ( & new - > list , & phram_list ) ;
2005-11-07 11:15:40 +00:00
return 0 ;
2005-04-16 15:20:36 -07:00
out2 :
2022-05-10 17:18:22 +02:00
phram_unmap ( new ) ;
2005-04-16 15:20:36 -07:00
out1 :
kfree ( new ) ;
out0 :
return ret ;
}
2013-10-02 18:42:29 +02:00
static int parse_num64 ( uint64_t * num64 , char * token )
2005-04-16 15:20:36 -07:00
{
2013-10-02 18:42:29 +02:00
size_t len ;
int shift = 0 ;
int ret ;
len = strlen ( token ) ;
2005-04-16 15:20:36 -07:00
/* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
2013-10-02 18:42:29 +02:00
if ( len > 2 ) {
if ( token [ len - 1 ] = = ' i ' ) {
switch ( token [ len - 2 ] ) {
case ' G ' :
shift + = 10 ;
2020-03-25 22:21:15 +01:00
fallthrough ;
2013-10-02 18:42:29 +02:00
case ' M ' :
shift + = 10 ;
2020-03-25 22:21:15 +01:00
fallthrough ;
2013-10-02 18:42:29 +02:00
case ' k ' :
shift + = 10 ;
token [ len - 2 ] = 0 ;
break ;
default :
return - EINVAL ;
}
}
2005-04-16 15:20:36 -07:00
}
2013-10-02 18:42:29 +02:00
ret = kstrtou64 ( token , 0 , num64 ) ;
* num64 < < = shift ;
2005-04-16 15:20:36 -07:00
2013-10-02 18:42:29 +02:00
return ret ;
2005-04-16 15:20:36 -07:00
}
static int parse_name ( char * * pname , const char * token )
{
size_t len ;
char * name ;
len = strlen ( token ) + 1 ;
if ( len > 64 )
return - ENOSPC ;
2014-05-28 22:31:28 +02:00
name = kstrdup ( token , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! name )
return - ENOMEM ;
* pname = name ;
return 0 ;
}
2005-03-07 21:43:42 +00:00
static inline void kill_final_newline ( char * str )
{
char * newline = strrchr ( str , ' \n ' ) ;
2014-07-13 20:39:01 +01:00
2005-03-07 21:43:42 +00:00
if ( newline & & ! newline [ 1 ] )
* newline = 0 ;
}
2005-04-16 15:20:36 -07:00
# define parse_err(fmt, args...) do { \
2009-06-16 19:20:40 +00:00
pr_err ( fmt , # # args ) ; \
return 1 ; \
2005-04-16 15:20:36 -07:00
} while ( 0 )
2013-10-14 18:52:23 +02:00
# ifndef MODULE
static int phram_init_called ;
2012-03-13 16:07:53 +01:00
/*
* This shall contain the module parameter if any . It is of the form :
2020-12-07 17:55:29 +08:00
* - phram = < device > , < address > , < size > [ , < erasesize > ] for module case
* - phram . phram = < device > , < address > , < size > [ , < erasesize > ] for built - in case
* We leave 64 bytes for the device name , 20 for the address , 20 for the
* size and 20 for the erasesize .
* Example : phram . phram = rootfs , 0xa0000000 , 512 Mi , 65536
2012-03-13 16:07:53 +01:00
*/
2020-12-07 17:55:29 +08:00
static char phram_paramline [ 64 + 20 + 20 + 20 ] ;
2013-10-14 18:52:23 +02:00
# endif
2012-03-13 16:07:53 +01:00
2013-10-14 18:52:23 +02:00
static int phram_setup ( const char * val )
2005-04-16 15:20:36 -07:00
{
2020-12-07 17:55:29 +08:00
char buf [ 64 + 20 + 20 + 20 ] , * str = buf ;
char * token [ 4 ] ;
2005-04-16 15:20:36 -07:00
char * name ;
2013-10-02 18:42:29 +02:00
uint64_t start ;
uint64_t len ;
2020-12-07 17:55:29 +08:00
uint64_t erasesize = PAGE_SIZE ;
2021-01-25 20:49:36 +08:00
uint32_t rem ;
2005-04-16 15:20:36 -07:00
int i , ret ;
if ( strnlen ( val , sizeof ( buf ) ) > = sizeof ( buf ) )
parse_err ( " parameter too long \n " ) ;
strcpy ( str , val ) ;
2005-03-07 21:43:42 +00:00
kill_final_newline ( str ) ;
2005-04-16 15:20:36 -07:00
2020-12-07 17:55:29 +08:00
for ( i = 0 ; i < 4 ; i + + )
2005-04-16 15:20:36 -07:00
token [ i ] = strsep ( & str , " , " ) ;
if ( str )
parse_err ( " too many arguments \n " ) ;
if ( ! token [ 2 ] )
parse_err ( " not enough arguments \n " ) ;
ret = parse_name ( & name , token [ 0 ] ) ;
if ( ret )
2009-06-16 19:20:40 +00:00
return ret ;
2005-04-16 15:20:36 -07:00
2013-10-02 18:42:29 +02:00
ret = parse_num64 ( & start , token [ 1 ] ) ;
2006-05-14 01:07:18 +02:00
if ( ret ) {
2005-04-16 15:20:36 -07:00
parse_err ( " illegal start address \n " ) ;
2020-03-18 23:31:56 +08:00
goto error ;
2006-05-14 01:07:18 +02:00
}
2005-04-16 15:20:36 -07:00
2013-10-02 18:42:29 +02:00
ret = parse_num64 ( & len , token [ 2 ] ) ;
2006-05-14 01:07:18 +02:00
if ( ret ) {
2005-04-16 15:20:36 -07:00
parse_err ( " illegal device length \n " ) ;
2020-03-18 23:31:56 +08:00
goto error ;
2006-05-14 01:07:18 +02:00
}
2005-04-16 15:20:36 -07:00
2020-12-07 17:55:29 +08:00
if ( token [ 3 ] ) {
ret = parse_num64 ( & erasesize , token [ 3 ] ) ;
if ( ret ) {
parse_err ( " illegal erasesize \n " ) ;
goto error ;
}
}
if ( len = = 0 | | erasesize = = 0 | | erasesize > len
2022-01-21 14:55:05 +03:00
| | erasesize > UINT_MAX ) {
2020-12-07 17:55:29 +08:00
parse_err ( " illegal erasesize or len \n " ) ;
2021-04-08 21:38:12 +08:00
ret = - EINVAL ;
2020-12-07 17:55:29 +08:00
goto error ;
}
2022-01-21 14:55:05 +03:00
div_u64_rem ( len , ( uint32_t ) erasesize , & rem ) ;
if ( rem ) {
parse_err ( " len is not multiple of erasesize \n " ) ;
ret = - EINVAL ;
goto error ;
}
2022-04-12 15:53:01 +02:00
ret = register_device ( NULL , name , start , len , ( uint32_t ) erasesize ) ;
2020-03-18 23:31:56 +08:00
if ( ret )
goto error ;
2020-12-07 17:55:29 +08:00
pr_info ( " %s device: %#llx at %#llx for erasesize %#llx \n " , name , len , start , erasesize ) ;
2020-03-18 23:31:56 +08:00
return 0 ;
2005-04-16 15:20:36 -07:00
2020-03-18 23:31:56 +08:00
error :
kfree ( name ) ;
2009-06-16 19:20:40 +00:00
return ret ;
2005-04-16 15:20:36 -07:00
}
treewide: Fix function prototypes for module_param_call()
Several function prototypes for the set/get functions defined by
module_param_call() have a slightly wrong argument types. This fixes
those in an effort to clean up the calls when running under type-enforced
compiler instrumentation for CFI. This is the result of running the
following semantic patch:
@match_module_param_call_function@
declarer name module_param_call;
identifier _name, _set_func, _get_func;
expression _arg, _mode;
@@
module_param_call(_name, _set_func, _get_func, _arg, _mode);
@fix_set_prototype
depends on match_module_param_call_function@
identifier match_module_param_call_function._set_func;
identifier _val, _param;
type _val_type, _param_type;
@@
int _set_func(
-_val_type _val
+const char * _val
,
-_param_type _param
+const struct kernel_param * _param
) { ... }
@fix_get_prototype
depends on match_module_param_call_function@
identifier match_module_param_call_function._get_func;
identifier _val, _param;
type _val_type, _param_type;
@@
int _get_func(
-_val_type _val
+char * _val
,
-_param_type _param
+const struct kernel_param * _param
) { ... }
Two additional by-hand changes are included for places where the above
Coccinelle script didn't notice them:
drivers/platform/x86/thinkpad_acpi.c
fs/lockd/svc.c
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Jessica Yu <jeyu@kernel.org>
2017-10-17 19:04:42 -07:00
static int phram_param_call ( const char * val , const struct kernel_param * kp )
2012-03-13 16:07:53 +01:00
{
2013-10-14 18:52:23 +02:00
# ifdef MODULE
return phram_setup ( val ) ;
# else
2012-03-13 16:07:53 +01:00
/*
2013-10-14 18:52:23 +02:00
* If more parameters are later passed in via
* / sys / module / phram / parameters / phram
* and init_phram ( ) has already been called ,
* we can parse the argument now .
2012-03-13 16:07:53 +01:00
*/
2013-10-14 18:52:23 +02:00
if ( phram_init_called )
return phram_setup ( val ) ;
/*
* During early boot stage , we only save the parameters
* here . We must parse them later : if the param passed
* from kernel boot command line , phram_param_call ( ) is
* called so early that it is not possible to resolve
* the device ( even kmalloc ( ) fails ) . Defer that work to
* phram_setup ( ) .
*/
2012-03-13 16:07:53 +01:00
if ( strlen ( val ) > = sizeof ( phram_paramline ) )
return - ENOSPC ;
strcpy ( phram_paramline , val ) ;
return 0 ;
2013-10-14 18:52:23 +02:00
# endif
2012-03-13 16:07:53 +01:00
}
2019-07-14 11:57:18 +08:00
module_param_call ( phram , phram_param_call , NULL , NULL , 0200 ) ;
2020-12-07 17:55:29 +08:00
MODULE_PARM_DESC ( phram , " Memory region to map. \" phram=<name>,<start>,<length>[,<erasesize>] \" " ) ;
2005-04-16 15:20:36 -07:00
2022-04-12 15:53:01 +02:00
# ifdef CONFIG_OF
static const struct of_device_id phram_of_match [ ] = {
{ . compatible = " phram " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , phram_of_match ) ;
# endif
static int phram_probe ( struct platform_device * pdev )
{
struct resource * res ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
return - ENOMEM ;
/* mtd_set_of_node() reads name from "label" */
return register_device ( pdev , NULL , res - > start , resource_size ( res ) ,
PAGE_SIZE ) ;
}
2023-10-08 22:01:28 +02:00
static void phram_remove ( struct platform_device * pdev )
2022-04-12 15:53:01 +02:00
{
struct phram_mtd_list * phram = platform_get_drvdata ( pdev ) ;
mtd_device_unregister ( & phram - > mtd ) ;
2022-05-10 17:18:22 +02:00
phram_unmap ( phram ) ;
2022-04-12 15:53:01 +02:00
kfree ( phram ) ;
}
static struct platform_driver phram_driver = {
. probe = phram_probe ,
2023-10-08 22:01:28 +02:00
. remove_new = phram_remove ,
2022-04-12 15:53:01 +02:00
. driver = {
. name = " phram " ,
. of_match_table = of_match_ptr ( phram_of_match ) ,
} ,
} ;
2005-04-16 15:20:36 -07:00
static int __init init_phram ( void )
{
2022-04-12 15:53:01 +02:00
int ret ;
ret = platform_driver_register ( & phram_driver ) ;
if ( ret )
return ret ;
2013-10-14 18:52:23 +02:00
# ifndef MODULE
2012-03-13 16:07:53 +01:00
if ( phram_paramline [ 0 ] )
2013-10-14 18:52:23 +02:00
ret = phram_setup ( phram_paramline ) ;
phram_init_called = 1 ;
# endif
2012-03-13 16:07:53 +01:00
2022-04-12 15:53:01 +02:00
if ( ret )
platform_driver_unregister ( & phram_driver ) ;
2013-10-14 18:52:23 +02:00
return ret ;
2005-04-16 15:20:36 -07:00
}
static void __exit cleanup_phram ( void )
{
unregister_devices ( ) ;
2022-04-12 15:53:01 +02:00
platform_driver_unregister ( & phram_driver ) ;
2005-04-16 15:20:36 -07:00
}
module_init ( init_phram ) ;
module_exit ( cleanup_phram ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-02-06 01:38:02 -08:00
MODULE_AUTHOR ( " Joern Engel <joern@wh.fh-wedel.de> " ) ;
2005-04-16 15:20:36 -07:00
MODULE_DESCRIPTION ( " MTD driver for physical RAM " ) ;