Чиним пропавшую память в ноутбуках lenovo

от
Железо   bios, lenovo, uefi

Мало кто знает, но ноутбуки от Lenovo, имеющие поддержку одновременно и BIOS и UEFI режима, постепенно куда-то прячут вашу ОЗУ. Давайте разберемся, куда она прячется и как ее вернуть!

Завязка

Имеется ноутбук Lenovo e530, работает в режиме BIOS, есть дуалбут Windows 7 и Archlinux. Установлено 8ГБ ОЗУ. В какой то момент нужно было запустить виртуальную машину (основное действие ведется из-под linux) , выделив под нее 4ГБ ОЗУ. Дело привычное, всегда 4 и выделяю, но в этот раз, перед сохранением настроек, замечаю что VBox ругается что "выделено больше, чем половина ОЗУ". Думаю ну как так, 4=8/2, почему же меньше! Открываю консоль, ввожу free -m и вижу, что total ram - 5679 mb (мебибайт)! Хотя раньше было около 7804. Грешу на последнее обновление арча, перезагружаюсь в Windows. Диспетчер устройств показывает 5875 мегабайт. После продолжительного гуглинга, понимаю что пропавшая оперативка ушла в "зарезервировано оборудованием". Точно знаю, что встройка (видеокарта) не берет больше 256МБ, да и не было раньше такого эффекта. Гугл выдавал что-то вроде "уберите вон там галочку/возможно ОЗУ умерла" и прочий бред. Мемтест от биоса и memtest86+ выдавал "работает, все норм!". Кроме того, заметил, что если загрузить какую нибудь систему из-под UEFI (выключив/уменьшив приоритет legacy) то такой проблемы с памятью нет, и free выдает 7804МБ!

Спустя 100500 вариантов запроса гугла, был найден вот этот топик на форумах леново (а еще записи этого человека были найдены вот тут. У создателя топика (далее - mihi) была почти такая же проблема - 1.4ГБ ОЗУ улетело вникуда, под UEFI баг не наблюдается. На последей (второй :кек2:) странице темы mihi объяснил, что из-за криворукости разработчиков uefi, каждый раз, когда uefi не может загрузиться (нет устройства, битый .efi файл), то значение кол-ва страниц памяти, которое uefi зарезервирует, увеличивается на 25%. То есть каждый фейл загрузки uefi приближает ваш ноут к моменту, когда увеличивать будет некуда, и ваш ноут станет кирпичом. Само значение записано в efi-переменную MemoryTypeInformation (далее - MTI). При каждой перезаписи при фейле загрузки, старое значение записывается в MemoryTypeInformationBackup (далее - MTI Backup). А затем, в последнем посте, mihi радостно сообщает что все решил, починил в hex редакторе переменную (восстановив значение из бэкапа) и все у него работает. Вот только...

Как именно это делать, mihi нам не рассказал. Об этом и пойдет речь в этой статье.
Отдельно хочу сказать спасибо mrEDitor за помощь.

Напомню, что нам нужно поменять значение в MTI. Кстати, забавно, что ОЗУ урезается в legacy, хотя значение указывается в efivars (из-под legacy в ОС они недоступны).
Было предпринято множество попыток сделать это через EFI Shell, или используя утилиту efivar (однако к ней оказалась ужасная документация), но Эдуард помог найти лучшее решение - слить дамп переменной в файл, поменять его в hex редакторе, и залить обратно. Итак, поехали

Что и где менять
Загружаем линукс в режиме uefi. Либо какой-нибудь live, либо берем флешку, пишем на нее efi'шный grub, и запускаем линукс. Как - посмотрите в /boot/grub/grub.cfg пункт с загрузкой вашей ОС, и сделайте так же. Если граб запущен в uefi, то и линукс запустится в нем.
Далее посмотрим список переменных командой efivar -l:
 экрана от 2020-04-07 01-07-20.png
Где-то ниже располагается 4c19049f-4137-4dd3-9c10-8b97a83ffdfa-MemoryTypeInformationBackup. Для просмотра их значений, введем команду efivar -pn [название переменной]:
efivars1.png
Hex дампы ваших переменных должны совпадать, и если они совпадают, то все у вас хорошо, но лучше всего вам сделать бэкап текущего значения MTI. А вот если они не совпадают (т.е. MTI перезаписывалась биосом из-за ошибки загрузки), то они будут отличаться 4мя байтами (см. картинку выше).
Мы знаем, что в MTI Backup значение всегда меньше, чем в MTI, и оно раньше когда-то точно было в MTI, поэтому самым безопасным вариантом будет взять бэкап и записать его в MTI:
  1. # по умолчанию эти файлы являются immutable, поэтому уберем этот флаг:
  2. chattr -i /sys/firmware/efi/efivars/MemoryTypeInformation-4c19049f-4137-4dd3-9c10-8b97a83ffdfa
  3. dd if=/sys/firmware/efi/efivars/MemoryTypeInformationBackup-4c19049f-4137-4dd3-9c10-8b97a83ffdfa of=mti-backup
  4. dd if=mti-backup of=/sys/firmware/efi/efivars/MemoryTypeInformation-4c19049f-4137-4dd3-9c10-8b97a83ffdfa
Перезагружаетесь в систему, работающую в legacy, и радостно смотрите на вернувшуюся ОЗУ. И вроде, победа...
Но если uefi фейлилось несколько раз, а не один, то значение из бэкапа не вернет вам всю ОЗУ.
Поэтому будем менять его сами. Главное, не забывайте, что мы меняем только те байты, которые отличались в MTI и MTI Backup. Для редактирования дампов использовал gHex - простая и несложная утилитка. Открываем наш дамп, сделанный в предыдущем шаге, в gHex и видим, что первые 5 байт выглядят так: 07 00 00 00 00. Далее уже идут байты нашей переменной, которые мы видели в efivar -pn. Точно не могу сказать, что означают байты 2-4, но 7 означает, что переменная - non-volatile(1)+Boot Service Access(2)+Runtime Access(4). Это так же можно посмотреть в efivars. Кстати, если бы она не имела Runtime Access, то мы бы не могли из под ОС с ней что-либо делать!
Напомню, что 4 байта, которые мы редактируем, содержат количество страниц ОЗУ, которые uefi будет резервировать. Обычно на ноутах леново размер страницы равен 4К, но на всякий случай проверьте (команда getconf PAGE_SIZE). Я понижал значение до 200мб (правда в результате все равно не вернул всю память. Экспериментируйте на свой страх и риск, и если кто-то ну ОЧЕНЬ рисковый, попробуйте туда 0 вписать). Итак, конвертируем мегабайты в страницы с учетом размера страницы (можно тут). Далее конвертируем количество страниц в hex, и записываем в эти 4 байта (справа налево, т.к. порядок байт - little endian). Сохраняем файл, проверяем его (hexdump -C file) и закидываем в uefi способом выше. Сохраните ваш файл, чтобы прошивать его, если MTI опять поменяется. В MTI Backup его, кстати, тоже можете залить
Если вы сидите в основном на uefi, советую перезагружаться иногда в legacy и проверять, а не съело ли у вас память.
И еще. если есть экспериментаторы, пишите в комменты, до скольки снижали значение в MTI, можно ли там указать 0 (если верить посту mihi, то uefi также увеличит ее на 25% если она слишком низкая). На этом все. Нескучного вам карантина, и живых ноутов :)
+8   8   0
499