Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/firmware/efi/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 7 kB image not shown  

Quelle  efi-pstore.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+

#include <linux/efi.h>
#include <linux/module.h>
#include <linux/pstore.h>
#include <linux/slab.h>
#include <linux/ucs2_string.h>

MODULE_IMPORT_NS("EFIVAR");

#define DUMP_NAME_LEN 66

static unsigned int record_size = 1024;
module_param(record_size, uint, 0444);
MODULE_PARM_DESC(record_size, "size of each pstore UEFI var (in bytes, min/default=1024)");

#define PSTORE_EFI_ATTRIBUTES \
 (EFI_VARIABLE_NON_VOLATILE | \
  EFI_VARIABLE_BOOTSERVICE_ACCESS | \
  EFI_VARIABLE_RUNTIME_ACCESS)

static bool pstore_disable = IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);

static int efivars_pstore_init(void);
static void efivars_pstore_exit(void);

static int efi_pstore_disable_set(const char *val, const struct kernel_param *kp)
{
 int err;
 bool old_pstore_disable = pstore_disable;

 err = param_set_bool(val, kp);
 if (err)
  return err;

 if (old_pstore_disable != pstore_disable) {
  if (pstore_disable)
   efivars_pstore_exit();
  else
   efivars_pstore_init();
 }

 return 0;
}

static const struct kernel_param_ops pstore_disable_ops = {
 .set = efi_pstore_disable_set,
 .get = param_get_bool,
};

module_param_cb(pstore_disable, &pstore_disable_ops, &pstore_disable, 0644);
__MODULE_PARM_TYPE(pstore_disable, "bool");

static int efi_pstore_open(struct pstore_info *psi)
{
 int err;

 err = efivar_lock();
 if (err)
  return err;

 psi->data = kzalloc(record_size, GFP_KERNEL);
 if (!psi->data)
  return -ENOMEM;

 return 0;
}

static int efi_pstore_close(struct pstore_info *psi)
{
 efivar_unlock();
 kfree(psi->data);
 return 0;
}

static inline u64 generic_id(u64 timestamp, unsigned int part, int count)
{
 return (timestamp * 100 + part) * 1000 + count;
}

static int efi_pstore_read_func(struct pstore_record *record,
    efi_char16_t *varname)
{
 unsigned long wlen, size = record_size;
 char name[DUMP_NAME_LEN], data_type;
 efi_status_t status;
 int cnt;
 unsigned int part;
 u64 time;

 ucs2_as_utf8(name, varname, DUMP_NAME_LEN);

 if (sscanf(name, "dump-type%u-%u-%d-%llu-%c",
     &record->type, &part, &cnt, &time, &data_type) == 5) {
  record->id = generic_id(time, part, cnt);
  record->part = part;
  record->count = cnt;
  record->time.tv_sec = time;
  record->time.tv_nsec = 0;
  if (data_type == 'C')
   record->compressed = true;
  else
   record->compressed = false;
  record->ecc_notice_size = 0;
 } else if (sscanf(name, "dump-type%u-%u-%d-%llu",
     &record->type, &part, &cnt, &time) == 4) {
  record->id = generic_id(time, part, cnt);
  record->part = part;
  record->count = cnt;
  record->time.tv_sec = time;
  record->time.tv_nsec = 0;
  record->compressed = false;
  record->ecc_notice_size = 0;
 } else if (sscanf(name, "dump-type%u-%u-%llu",
     &record->type, &part, &time) == 3) {
  /*
 * Check if an old format,
 * which doesn't support holding
 * multiple logs, remains.
 */

  record->id = generic_id(time, part, 0);
  record->part = part;
  record->count = 0;
  record->time.tv_sec = time;
  record->time.tv_nsec = 0;
  record->compressed = false;
  record->ecc_notice_size = 0;
 } else
  return 0;

 record->buf = kmalloc(size, GFP_KERNEL);
 if (!record->buf)
  return -ENOMEM;

 status = efivar_get_variable(varname, &LINUX_EFI_CRASH_GUID, NULL,
         &size, record->buf);
 if (status != EFI_SUCCESS) {
  kfree(record->buf);
  return efi_status_to_err(status);
 }

 /*
 * Store the name of the variable in the pstore_record priv field, so
 * we can reuse it later if we need to delete the EFI variable from the
 * variable store.
 */

 wlen = (ucs2_strnlen(varname, DUMP_NAME_LEN) + 1) * sizeof(efi_char16_t);
 record->priv = kmemdup(varname, wlen, GFP_KERNEL);
 if (!record->priv) {
  kfree(record->buf);
  return -ENOMEM;
 }

 return size;
}

static ssize_t efi_pstore_read(struct pstore_record *record)
{
 efi_char16_t *varname = record->psi->data;
 efi_guid_t guid = LINUX_EFI_CRASH_GUID;
 unsigned long varname_size;
 efi_status_t status;

 for (;;) {
  /*
 * A small set of old UEFI implementations reject sizes
 * above a certain threshold, the lowest seen in the wild
 * is 512.
 *
 * TODO: Commonize with the iteration implementation in
 *       fs/efivarfs to keep all the quirks in one place.
 */

  varname_size = 512;

  /*
 * If this is the first read() call in the pstore enumeration,
 * varname will be the empty string, and the GetNextVariable()
 * runtime service call will return the first EFI variable in
 * its own enumeration order, ignoring the guid argument.
 *
 * Subsequent calls to GetNextVariable() must pass the name and
 * guid values returned by the previous call, which is why we
 * store varname in record->psi->data. Given that we only
 * enumerate variables with the efi-pstore GUID, there is no
 * need to record the guid return value.
 */

  status = efivar_get_next_variable(&varname_size, varname, &guid);
  if (status == EFI_NOT_FOUND)
   return 0;

  if (status != EFI_SUCCESS)
   return efi_status_to_err(status);

  /* skip variables that don't concern us */
  if (efi_guidcmp(guid, LINUX_EFI_CRASH_GUID))
   continue;

  return efi_pstore_read_func(record, varname);
 }
}

static int efi_pstore_write(struct pstore_record *record)
{
 char name[DUMP_NAME_LEN];
 efi_char16_t efi_name[DUMP_NAME_LEN];
 efi_status_t status;
 int i;

 record->id = generic_id(record->time.tv_sec, record->part,
    record->count);

 /* Since we copy the entire length of name, make sure it is wiped. */
 memset(name, 0, sizeof(name));

 snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld-%c",
   record->type, record->part, record->count,
   (long long)record->time.tv_sec,
   record->compressed ? 'C' : 'D');

 for (i = 0; i < DUMP_NAME_LEN; i++)
  efi_name[i] = name[i];

 if (efivar_trylock())
  return -EBUSY;
 status = efivar_set_variable_locked(efi_name, &LINUX_EFI_CRASH_GUID,
         PSTORE_EFI_ATTRIBUTES,
         record->size, record->psi->buf,
         true);
 efivar_unlock();
 return efi_status_to_err(status);
};

static int efi_pstore_erase(struct pstore_record *record)
{
 efi_status_t status;

 status = efivar_set_variable(record->priv, &LINUX_EFI_CRASH_GUID,
         PSTORE_EFI_ATTRIBUTES, 0, NULL);

 if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
  return efi_status_to_err(status);
 return 0;
}

static struct pstore_info efi_pstore_info = {
 .owner  = THIS_MODULE,
 .name  = KBUILD_MODNAME,
 .flags  = PSTORE_FLAGS_DMESG,
 .open  = efi_pstore_open,
 .close  = efi_pstore_close,
 .read  = efi_pstore_read,
 .write  = efi_pstore_write,
 .erase  = efi_pstore_erase,
};

static int efivars_pstore_init(void)
{
 if (!efivar_supports_writes())
  return 0;

 if (pstore_disable)
  return 0;

 /*
 * Notice that 1024 is the minimum here to prevent issues with
 * decompression algorithms that were spotted during tests;
 * even in the case of not using compression, smaller values would
 * just pollute more the pstore FS with many small collected files.
 */

 if (record_size < 1024)
  record_size = 1024;

 efi_pstore_info.buf = kmalloc(record_size, GFP_KERNEL);
 if (!efi_pstore_info.buf)
  return -ENOMEM;

 efi_pstore_info.bufsize = record_size;

 if (pstore_register(&efi_pstore_info)) {
  kfree(efi_pstore_info.buf);
  efi_pstore_info.buf = NULL;
  efi_pstore_info.bufsize = 0;
 }

 return 0;
}

static void efivars_pstore_exit(void)
{
 if (!efi_pstore_info.bufsize)
  return;

 pstore_unregister(&efi_pstore_info);
 kfree(efi_pstore_info.buf);
 efi_pstore_info.buf = NULL;
 efi_pstore_info.bufsize = 0;
}

module_init(efivars_pstore_init);
module_exit(efivars_pstore_exit);

MODULE_DESCRIPTION("EFI variable backend for pstore");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:efivars");

Messung V0.5
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.