2013-12-20 14:02:18 +04:00
/*
* linux / drivers / efi / runtime - map . c
* Copyright ( C ) 2013 Red Hat , Inc . , Dave Young < dyoung @ redhat . com >
*
* This file is released under the GPLv2 .
*/
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/efi.h>
# include <linux/slab.h>
# include <asm/setup.h>
struct efi_runtime_map_entry {
efi_memory_desc_t md ;
struct kobject kobj ; /* kobject for each entry */
} ;
static struct efi_runtime_map_entry * * map_entries ;
struct map_attribute {
struct attribute attr ;
ssize_t ( * show ) ( struct efi_runtime_map_entry * entry , char * buf ) ;
} ;
static inline struct map_attribute * to_map_attr ( struct attribute * attr )
{
return container_of ( attr , struct map_attribute , attr ) ;
}
static ssize_t type_show ( struct efi_runtime_map_entry * entry , char * buf )
{
return snprintf ( buf , PAGE_SIZE , " 0x%x \n " , entry - > md . type ) ;
}
# define EFI_RUNTIME_FIELD(var) entry->md.var
# define EFI_RUNTIME_U64_ATTR_SHOW(name) \
static ssize_t name # # _show ( struct efi_runtime_map_entry * entry , char * buf ) \
{ \
return snprintf ( buf , PAGE_SIZE , " 0x%llx \n " , EFI_RUNTIME_FIELD ( name ) ) ; \
}
EFI_RUNTIME_U64_ATTR_SHOW ( phys_addr ) ;
EFI_RUNTIME_U64_ATTR_SHOW ( virt_addr ) ;
EFI_RUNTIME_U64_ATTR_SHOW ( num_pages ) ;
EFI_RUNTIME_U64_ATTR_SHOW ( attribute ) ;
static inline struct efi_runtime_map_entry * to_map_entry ( struct kobject * kobj )
{
return container_of ( kobj , struct efi_runtime_map_entry , kobj ) ;
}
static ssize_t map_attr_show ( struct kobject * kobj , struct attribute * attr ,
char * buf )
{
struct efi_runtime_map_entry * entry = to_map_entry ( kobj ) ;
struct map_attribute * map_attr = to_map_attr ( attr ) ;
return map_attr - > show ( entry , buf ) ;
}
static struct map_attribute map_type_attr = __ATTR_RO ( type ) ;
static struct map_attribute map_phys_addr_attr = __ATTR_RO ( phys_addr ) ;
static struct map_attribute map_virt_addr_attr = __ATTR_RO ( virt_addr ) ;
static struct map_attribute map_num_pages_attr = __ATTR_RO ( num_pages ) ;
static struct map_attribute map_attribute_attr = __ATTR_RO ( attribute ) ;
/*
* These are default attributes that are added for every memmap entry .
*/
static struct attribute * def_attrs [ ] = {
& map_type_attr . attr ,
& map_phys_addr_attr . attr ,
& map_virt_addr_attr . attr ,
& map_num_pages_attr . attr ,
& map_attribute_attr . attr ,
NULL
} ;
static const struct sysfs_ops map_attr_ops = {
. show = map_attr_show ,
} ;
static void map_release ( struct kobject * kobj )
{
struct efi_runtime_map_entry * entry ;
entry = to_map_entry ( kobj ) ;
kfree ( entry ) ;
}
static struct kobj_type __refdata map_ktype = {
. sysfs_ops = & map_attr_ops ,
. default_attrs = def_attrs ,
. release = map_release ,
} ;
static struct kset * map_kset ;
static struct efi_runtime_map_entry *
2016-03-02 02:02:56 +03:00
add_sysfs_runtime_map_entry ( struct kobject * kobj , int nr ,
efi_memory_desc_t * md )
2013-12-20 14:02:18 +04:00
{
int ret ;
struct efi_runtime_map_entry * entry ;
if ( ! map_kset ) {
map_kset = kset_create_and_add ( " runtime-map " , NULL , kobj ) ;
if ( ! map_kset )
return ERR_PTR ( - ENOMEM ) ;
}
entry = kzalloc ( sizeof ( * entry ) , GFP_KERNEL ) ;
if ( ! entry ) {
kset_unregister ( map_kset ) ;
2015-04-21 16:46:28 +03:00
map_kset = NULL ;
return ERR_PTR ( - ENOMEM ) ;
2013-12-20 14:02:18 +04:00
}
2016-03-02 02:02:56 +03:00
memcpy ( & entry - > md , md , sizeof ( efi_memory_desc_t ) ) ;
2013-12-20 14:02:18 +04:00
kobject_init ( & entry - > kobj , & map_ktype ) ;
entry - > kobj . kset = map_kset ;
ret = kobject_add ( & entry - > kobj , NULL , " %d " , nr ) ;
if ( ret ) {
kobject_put ( & entry - > kobj ) ;
kset_unregister ( map_kset ) ;
2015-04-21 16:46:28 +03:00
map_kset = NULL ;
2013-12-20 14:02:18 +04:00
return ERR_PTR ( ret ) ;
}
return entry ;
}
2014-08-09 01:26:11 +04:00
int efi_get_runtime_map_size ( void )
{
2016-03-02 02:02:56 +03:00
return efi . memmap . nr_map * efi . memmap . desc_size ;
2014-08-09 01:26:11 +04:00
}
int efi_get_runtime_map_desc_size ( void )
{
2016-03-02 02:02:56 +03:00
return efi . memmap . desc_size ;
2014-08-09 01:26:11 +04:00
}
int efi_runtime_map_copy ( void * buf , size_t bufsz )
{
size_t sz = efi_get_runtime_map_size ( ) ;
if ( sz > bufsz )
sz = bufsz ;
2016-03-02 02:02:56 +03:00
memcpy ( buf , efi . memmap . map , sz ) ;
2014-08-09 01:26:11 +04:00
return 0 ;
}
2013-12-20 14:02:18 +04:00
int __init efi_runtime_map_init ( struct kobject * efi_kobj )
{
int i , j , ret = 0 ;
struct efi_runtime_map_entry * entry ;
2016-03-02 02:02:56 +03:00
efi_memory_desc_t * md ;
2013-12-20 14:02:18 +04:00
2016-03-02 02:02:56 +03:00
if ( ! efi_enabled ( EFI_MEMMAP ) )
2013-12-20 14:02:18 +04:00
return 0 ;
2016-03-02 02:02:56 +03:00
map_entries = kzalloc ( efi . memmap . nr_map * sizeof ( entry ) , GFP_KERNEL ) ;
2013-12-20 14:02:18 +04:00
if ( ! map_entries ) {
ret = - ENOMEM ;
goto out ;
}
2016-03-02 02:02:56 +03:00
i = 0 ;
for_each_efi_memory_desc ( md ) {
entry = add_sysfs_runtime_map_entry ( efi_kobj , i , md ) ;
2013-12-20 14:02:18 +04:00
if ( IS_ERR ( entry ) ) {
ret = PTR_ERR ( entry ) ;
goto out_add_entry ;
}
2016-03-02 02:02:56 +03:00
* ( map_entries + i + + ) = entry ;
2013-12-20 14:02:18 +04:00
}
return 0 ;
out_add_entry :
2015-01-15 12:21:21 +03:00
for ( j = i - 1 ; j > = 0 ; j - - ) {
2013-12-20 14:02:18 +04:00
entry = * ( map_entries + j ) ;
kobject_put ( & entry - > kobj ) ;
}
out :
return ret ;
}