___           ___           ___           ___           ___           ___     
     /\  \         /\__\         /\  \         /\__\         /\  \         /\  \    
    /::\  \       /:/  /        /::\  \       /:/  /        /::\  \       /::\  \   
   /:/\:\  \     /:/  /        /:/\:\  \     /:/__/        /:/\:\  \     /:/\:\  \  
  /::\~\:\  \   /:/  /  ___   /:/  \:\  \   /::\__\____   /::\~\:\  \   /::\~\:\  \ 
 /:/\:\ \:\__\ /:/__/  /\__\ /:/__/ \:\__\ /:/\:::::\__\ /:/\:\ \:\__\ /:/\:\ \:\__\
 \/_|::\/:/  / \:\  \ /:/  / \:\  \  \/__/ \/_|:|~~|~    \:\~\:\ \/__/ \/_|::\/:/  /
    |:|::/  /   \:\  /:/  /   \:\  \          |:|  |      \:\ \:\__\      |:|::/  / 
    |:|\/__/     \:\/:/  /     \:\  \         |:|  |       \:\ \/__/      |:|\/__/  
    |:|  |        \::/  /       \:\__\        |:|  |        \:\__\        |:|  |    
     \|__|         \/__/         \/__/         \|__|         \/__/         \|__|    
       

Основы EFI, NVRAM Переменные

Оглавление

Объяснение NVRAM Переменных

NVRAM это энергонезависимая RAM которая используется в EFI для сохранения переменных которые нужно оставлять между загрузками. Много из NVRAM переменных определены архитектурно, и установка недопустимых параметров в NVRAM может привести к невозможности работы машины.

В процессе запуска некоторые драйвера и приложения могут полагаться на значения NVRAM чтобы выполнять свою работу. Ниже приведена диаграмма из спецификации UEFI 2.56 которая это показывает.

1

По причине того что загрузчик и другие драйвера сконфигурированны для загрузки информации из NVRAM, если мы можем переписывать некоторые из этих NVRAM переменных то мы будем иметь контроль над некоторыми частями процесса загрузки системы.

NVRAM переменные это комбинация GUID владельца переменной, имени и значения. Пример некоторых из этих значений, показаных с помощью коммандного шелла UEFI dmpstore, ниже:

Переменная NV+RT+BS 'Efi:Boot0080' DataSize = 68
  00000000: 01 00 00 00 50 00 4D 00-61 00 63 00 20 00 4F 00  *....P.M.a.c. .O.*
  00000010: 53 00 20 00 58 00 00 00-02 01 0C 00 D0 41 03 0A  *S. .X........A..*
  00000020: 00 00 00 00 01 01 06 00-05 1C 01 01 06 00 00 00  *................*
  00000030: 03 12 0A 00 00 00 00 00-00 00 04 01 2A 00 03 00  *............*...*
  00000040: 00 00 B8 A0 0C 0E 00 00-00 00 20 5F 13 00 00 00  *.......... _....*
  00000050: 00 00 65 5A 48 A0 E7 20-4D 4A B3 DE DB 1C 77 3D  *..eZH.. MJ....w=*
  00000060: 81 87 02 02 7F FF 04 00-                         *........*
Переменная NV+RT+BS '7C436110-AB2A-4BBB-A880-FE41995C9F82:efi-boot-device-data' DataSize = 50
  00000000: 02 01 0C 00 D0 41 03 0A-00 00 00 00 01 01 06 00  *.....A..........*
  00000010: 05 1C 01 01 06 00 00 00-03 12 0A 00 00 00 00 00  *................*
  00000020: 00 00 04 01 2A 00 03 00-00 00 B8 A0 0C 0E 00 00  *....*...........*
  00000030: 00 00 20 5F 13 00 00 00-00 00 65 5A 48 A0 E7 20  *.. _......eZH.. *
  00000040: 4D 4A B3 DE DB 1C 77 3D-81 87 02 02 7F FF 04 00  *MJ....w=........*

Важные NVRAM переменные и GUID

Ниже представленны некоторые важные NVRAM переменные о которых нужно знать. Технически, нет никакой гарантии что эти переменные будут присутствовать на любой машине, они либо определены в спецификации, либо известны для использования определенными поставщиками.

Этот лист не полный и будет обновляться.

GUID 	Переменная 		Имя 	

Общее описание
8BE4DF61-93CA-11D2-AA0D-00E098032B8C (Efi) 	BootOrder 	

Массив 16-разрядных целых чисел, которые ссылаются на параметры загрузки. Система

попытается загрузиться с каждого из загрузочных (Boot####) устройств в том порядке, в котором они

перечислены в этой переменной. После успешной загрузки одного из параметров система не пытается

загрузить любые последующие параметры.


8BE4DF61-93CA-11D2-AA0D-00E098032B8C (Efi) 	Boot#### 	

Одно конкретное устройство которое можно загрузить. #### это четыре цифры hex числа.

Эта переменная имеет тип EFI_LOAD_OPTION, найдено в секции 3.1.3 спецификации

UEFI 2.5.


8BE4DF61-93CA-11D2-AA0D-00E098032B8C (Efi) 	DriverOrder 	

 Массив 16-битных целых чисел драйверов для загрузки. Похоже на BootOrder,

эта переменная перечисляет драйвера, которые должны быть загружены при загрузке по порядку. 
Однако в отличие от BootOrder, будут загружены все драйверы, а не только первый успешный.


8BE4DF61-93CA-11D2-AA0D-00E098032B8C (Efi) 	Driver#### 	

Драйвер который должен быть загружен при, собственно, загрузке, если выбран в DriverOrder.

#### это четыре цифры hex числа. Эта переменная имеет тип EFI_LOAD_OPTION,

найдено в секции 3.1.3 спецификации UEFI 2.5.


4D1ED05-38C7-4A6A-9CC6-4BCCA8B38C14 	EnableDriverOrder 	

Специфичный для Apple, заставляет загрузчик использовать DriverOrder и Driver#### переменные.

Расходуется после использования. Использует DriverOrder если EnableDriverOrder==0x31



7C436110-AB2A-4BBB-A880-FE41995C9F82 	csr-active-config 	

Специфичный для Apple, конфигурациия для SIP которые принадлежит El Capitan.

Значение 0x10 означает что он включен, 0x77 что полностью отключен.

Установка NVRAM Переменных из OS X

Можно установить (некоторые) переменные из терминала OS X, если есть root. Команда для использования - nvram, manpage которого приведен ниже.

nvram(8)                                                              nvram(8)
NAME
       nvram - manipulate firmware NVRAM variables
SYNOPSIS
       nvram  [ -p ] [ -f filename ] [ -d name ] [ -c ] [ name [= value ]] ...
DESCRIPTION
       The nvram command allows manipulation of firmware NVRAM variables.   It
       can be used to get or set a variable.  It can also be used to print all
       of the variables or set a list of variables from a  file.   Changes  to
       NVRAM variables are only saved by clean restart or shutdown.
       In  principle,  name  can  be any string.  In practice, not all strings
       will be accepted.  New World  machines  can  create  new  variables  as
       desired.  Some variables require administrator privilege to get or set.
       The given value must match the data type  required  for  name.   Binary
       data  can  be  set using the %xx notation, where xx is the hex value of
       the byte.  The type for new variables is always binary data.
OPTIONS
       -d name
              Deletes the named firmware variable.
       -f filename
              Set firmware variables from a text file.  The  file  must  be  a
              list  of  "name value" statements.  The first space on each line
              is taken to be the separator between "name" and "value".  If the
              last  character  of  a  line is \, the value extends to the next
              line.
       -x     Use XML format for reading and writing variables.   This  option
              must  be  used  before the -p or -f options, since arguments are
              processed in order.
       -c     Delete all of the firmware variables.
       -p     Print all of the firmware variables.
EXAMPLES
              example% nvram boot-args="-s rd=*hd:10"
       Set the boot-args variable to "-s rd=*hd:10".  This would specify  sin-
       gle user mode with the root device in hard drive partition 10.

              example% nvram my-variable="String One%00String Two%00%00"
       Create  a new variable, my-variable, containing a list of two C-strings
       that is terminated by a NUL.

              example% nvram -d my-variable
       Deletes the variable named my-variable.
                               October 28, 2003                       nvram(8)

Тем не менее, справочная страница не говорит вам все что нужно знать о nvram. Хотя nvram -p утверждает что печатает все переменные прошивки, он не печатает ни одной из переменных которые принадлежат Efi GUID.

Точно так же по умолчанию любая переменная NVRAM, которую вы устанавливаете с помощью этого инструмента, будет иметь Apple GUID, используемый csr-active-config (в таблице в предыдущем разделе.) Однако, если попытаться установить значения как в DriverOrder, им нужно иметь правильный GUID, иначе EFI не будет обрабатывать его так, как вы этого хотите.

К счастью, вы можете установить переменные, такие как DriverOrder, используя nvram при условии что был указан GUID. Пример этого, который устанавливает порядок драйверов для загрузки Driver5000 (endian-ness важен) и другую команду для установки EnableDriverOrder, приведена ниже:

$ sudo nvram 8BE4DF61-93CA-11D2-AA0D-00E098032B8C:DriverOrder=%00%50
$ sudo nvram 4D1ED05-38C7-4A6A-9CC6-4BCCA8B38C14:EnableDriverOrder=1

Проблемы, созданные SIP (без рута) в OS X 10.11

Внедрив Системную защиту целостности в OS X 10.11 (El Capitan), Apple заблокировала некоторые вещи, которые вы можете сделать с помощью команды nvram.

В частности, вы больше не можете устанавливать переменные, которые принадлежат Efi GUID, как например BootOrder. Точно так же вы не можете изменять переменную NVRAM, в которой хранится конфигурация SIP, тоесть csr-active-config.

Однако, как минимум на 10.11.0 (10/2/2015), все еще можно установить EnableDriverOrder переменную.

Установка NVRAM Переменных из EFI Приложения/Драйвера

Если ты работаешь из контекста EFI, можно установить переменные NVRAM напрямую. Находясь на странице 241 спецификации UEFI 2.5, команда для установки переменной NVRAM выглядит следующим образом:

EFI_RUNTIME_SERVICES->SetVariable(
CHAR16* VariableName,
EFI_GUID *VendorGuid,
UINT32 Attributes,
UINTN DataSize,
VOID *Data
);

Поле VendorGuid можно установить вручную (указав GUID в заголовочном файле) или используя некоторые GUID, встроенные в EDK.

Для Windows или Linux, EFI GUID (используется для BootOrder. Driver#### и т. Д.) был включен в состав основного пакета сборки MdePkg. Если ваш INF-файл включает в себя MdePkg/MdePkg.dec (в поле Packages), вы можете ссылаться на него, как показано ниже:

#include  <Guid/GlobalVariable.h>
...
[other code]
...
Status = gRT->SetVariable(
BOOT_ORDER_NAME,
&gEfiGlobalVariableGuid,	//This is where the GUID is referenced, name defined in GlobalVariable.h from MdePkg.
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
BOOT_ORDER_LEN,
&BOOT_ORDER_DATA
);