Я проапгрейдил старый ноутбук двумя модулями памяти 4GB DDR3-1333, но оказалось, что ноутбук совместим максимум с DDR3-1066. Что сделает настоящий мужчина? Конечно, перепрошьёт EEPROM модуля для ребиннинга DDR3 на более медленную модель!
Рабочее место. Справа Thinkpad для проведения перепрошивки, а слева проблемный MacBook Pro
Будьте очень осторожны. Очевидно, что вы можете повредить или навсегда заблокировать запись на свой DIMM. Возможные более тонкие неполадки, в том числе сбой логической схемы батареи, или материнская плата превратится в кирпич.
Как всё началось
У меня 13-дюймовый MacBook Pro середины 2010 года. Его файловая система была повреждена при обычной перезагрузке, и дисковая утилита (из раздела восстановления) ничего не могла с этим поделать. Ну, я давно этого ждал: пришло время поставить SSD и добавить немного оперативной памяти.
Я купил SSD и мне повезло найти в горе электронного мусора пару сломанных ноутбуков с подходящими модулями оперативной памяти. Вставляем SSD и два модуля по 4 ГБ, запускаем Internet Recovery — и через час у нас должна быть рабочая система. Но нет. Загрузка просто зависает. Из-за чего? Наибольшее подозрение вызывают эти модули RAM, в конце концов, они же из мусора. Поэтому делаем то, что сделал бы любой: создаём USB-флэшку с memtest86 и запускаем её на ночь. Отлично, память в порядке. После многих часов с пробами разных методов установки для разных версий macOS наконец приходит открытие, что всё работает отлично, если просто вставить обратно старую память.1
Истинная причина
Понимая проблему, я быстро узнал, что MacBook Pro 2009−2010 годов на самом деле не работают с памятью быстрее, чем PC3-8500, и что проблему можно обойти, изменив метаданные RAM с помощью программы Windows под названием Thaiphoon Burner.
Истинной причиной сбоя является интегрированный графический процессор GeForce 320M, который использует общую память, то есть обычную RAM. Он может работать максимум с PC3-8500 (aka DDR3-1066, то есть с тактовой частотой DRAM 533 МГц), но контроллер системной памяти не знает об этом и повышает максимальную доступную скорость до 667 МГц (т.е. PC3-10600 aka DDR3-1333). У остальных компонентов нет проблем с этим, как и у GPU в режиме VESA (я думаю).
Я не слышал ни о каком другом оборудовании, которое отказывает в работе оперативной памяти, способной к более высоким скоростям, чем оборудование может использовать. Конечно, при покупке модулей памяти на рынке продавцы предупредили бы об этом нюансе. Это всё равно намного лучше, чем припаянная оперативка, как в ноутбуках Apple с 2012 года.
Настройка прошивки
Разобравшись с причиной, я установил один оригинальный модуль PC3-8500 на 2 ГБ и один новый модуль 4 ГБ, и всё заработало. Но ребиннинг DDR3 казался хорошим проектом, поэтому я решил попробовать.
Конечно, я не собираюсь устанавливать Windows только для прошивки EEPROM и не собираюсь покупать причудливое программное обеспечение, если всё можно сделать вручную. Я думал, что задача явно должна выполняться в Linux, возможно, с некоторыми дополнительными инструментами. Я также не хотел устанавливать Linux на макбук только для этого. Поэтому мой старый надёжный Thinkpad X220 с NixOS стал идеальной площадкой для работ. Потребовалось немного времени для его обновления, потому что я не загружал машину год или около того.
Затем наступил черёд выбрать, какой модуль попробовать первым. У Thinkpad уже было два по 4 ГБ, и я нашел четыре модуля 4 ГБ, поэтому мне было из чего выбрать. Я решил начать с самого странного, производства Micron. Все остальные были Samsung. У одного была наклейка Lenovo.
Чтение SPD
Модули памяти поставляются с микросхемой EEPROM, которая содержит метаданные о модуле Serial Presence Detect (SPD). Сам формат простой, а доступ к EEPROM можно организовать через шину SMBus, которая по сути не отличается от I²C.2
К счастью, для взаимодействия с SMBus и даже чтения EEPROM DDR3 есть драйверы ядра и готовое программное обеспечение.
Во-первых, для просмотра устройств на шине нужны i2c-tools
и некоторые модули ядра.
$ nix-shell -p i2c-tools
$ modprobe i2c-dev
$ modprobe i2c-i801
$ i2cdetect -l
i2c-0 unknown i915 gmbus ssc N/A
i2c-1 unknown i915 gmbus vga N/A
i2c-2 unknown i915 gmbus panel N/A
i2c-3 unknown i915 gmbus dpc N/A
i2c-4 unknown i915 gmbus dpb N/A
i2c-5 unknown i915 gmbus dpd N/A
i2c-6 unknown DPDDC-B N/A
i2c-7 unknown DPDDC-C N/A
i2c-8 unknown DPDDC-D N/A
i2c-9 unknown SMBus I801 adapter at efa0 N/A
Здесь представляет интерес адаптер SMBus, в моём случае i2c-9
.
Пакет i2c-tools
поставляется даже с инструментом decode-dimms
для чтения информации о RAM в удобочитаемом формате. Для этого требуется модуль ядра eeprom
.
$ modprobe eeprom
$ decode-dimms
$ modprobe -r eeprom
Вот часть выдачи для одного модуля памяти:
Memory Serial Presence Detect Decoder By Philip Edelbrock, Christian Zuckschwerdt, Burkart Lingner, Jean Delvare, Trent Piepho and others Decoding EEPROM: /sys/bus/i2c/drivers/eeprom/9-0050 Guessing DIMM is in bank 1 ---=== SPD EEPROM Information ===--- EEPROM CRC of bytes 0-116 OK (0xAEA4) # of bytes written to SDRAM EEPROM 176 Total number of bytes in EEPROM 256 Fundamental Memory type DDR3 SDRAM Module Type SO-DIMM ---=== Memory Characteristics ===--- Maximum module speed 1333 MHz (PC3-10600) Size 4096 MB Banks x Rows x Columns x Bits 8 x 15 x 10 x 64 Ranks 2 SDRAM Device Width 8 bits Bus Width Extension 0 bits tCL-tRCD-tRP-tRAS 9-9-9-24 Supported CAS Latencies (tCL) 10T, 9T, 8T, 7T, 6T, 5T ---=== Timings at Standard Speeds ===--- tCL-tRCD-tRP-tRAS as DDR3-1333 9-9-9-24 tCL-tRCD-tRP-tRAS as DDR3-1066 7-7-7-20 tCL-tRCD-tRP-tRAS as DDR3-800 6-6-6-15 ---=== Timing Parameters ===--- Minimum Cycle Time (tCK) 1.500 ns Minimum CAS Latency Time (tAA) 13.125 ns Minimum Write Recovery time (tWR) 15.000 ns Minimum RAS# to CAS# Delay (tRCD) 13.125 ns Minimum Row Active to Row Active Delay (tRRD) 6.000 ns Minimum Row Precharge Delay (tRP) 13.125 ns Minimum Active to Precharge Delay (tRAS) 36.000 ns Minimum Active to Auto-Refresh Delay (tRC) 49.125 ns Minimum Recovery Delay (tRFC) 160.000 ns Minimum Write to Read CMD Delay (tWTR) 7.500 ns Minimum Read to Pre-charge CMD Delay (tRTP) 7.500 ns Minimum Four Activate Window Delay (tFAW) 30.000 ns ---=== Optional Features ===--- Operable voltages 1.5V RZQ/6 supported? No RZQ/7 supported? Yes DLL-Off Mode supported? Yes Operating temperature range 0-95 degrees C Refresh Rate in extended temp range 2X Auto Self-Refresh? Yes On-Die Thermal Sensor readout? No Partial Array Self-Refresh? No Module Thermal Sensor Yes SDRAM Device Type Standard Monolithic ---=== Physical Characteristics ===--- Module Height 30 mm Module Thickness 2 mm front, 2 mm back Module Width 67.6 mm Module Reference Card F revision 0 Rank 1 Mapping Standard ---=== Manufacturer Data ===--- Module Manufacturer Micron Technology DRAM Manufacturer Micron Technology Manufacturing Location Code 0x0F Manufacturing Date 2011-W23 Assembly Serial Number 0xFB5C7F1A Part Number 16JSF51264HZ-1G4D1 Revision Code 0x4431
Довольно много данных. Часть показанной информации вычисляется из данных. Например, тайминги на стандартных скоростях (т.е. отсчёты цикла) вычисляются на основе параметров тайминга в наносекундном разрешении. Даже они сохранены как величины, кратные блоку развёртки (time base unit), установленному в другом месте на EEPROM, но это не относится к теме статьи. Данный модуль RAM выдаёт 7-7-7-20 на DDR3-1066, что соответствует стандарту DDR3-1066F JEDEC. Не спрашивайте меня, что такое JEDEC, но он быстрее, чем самый дешёвый DDR3-1066G.
Я потратил много времени на подтверждение моего вывода: при попытке ребиннинга памяти единственное важное число — это минимальное время цикла (tCK). Здесь это 1,5 нс, т.е. 667 МГц.
Давайте посмотрим на исходные данные.
$ i2cdump 9 0x50 No size specified (using byte-data access) WARNING! This program can confuse your I2C bus, cause data loss and worse! I will probe file /dev/i2c-9, address 0x50, mode byte Continue? [Y/n] 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 92 10 0b 03 03 19 00 09 03 52 01 08 0c 00 7e 00 ??????.??R???.~. 10: 69 78 69 30 69 11 20 89 00 05 3c 3c 00 f0 82 05 ixi0i? ?.?<<.??? 20: 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?............... 30: 00 00 00 00 00 00 00 00 00 00 00 00 0f 11 05 00 ............???. 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 70: 00 00 00 00 00 80 2c 0f 11 23 fb 5c 7f 1a a4 ae .....?,??#????? 80: 31 36 4a 53 46 35 31 32 36 34 48 5a 2d 31 47 34 16JSF51264HZ-1G4 90: 44 31 44 31 80 2c 00 00 00 00 00 00 00 00 00 00 D1D1?,.......... a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
Спецификации говорят, что минимальное время указано по адресу 0x0c. Посмотрим, оно в первой строке (00:
), в колонке c
. Кстати, его значение тоже 0x0c или 12. Это кратно средней временной базе (MTB), которая представляет собой частное от деления значения в 0x0a на значение в 0x0b (в наносекундах). Здесь 1⁄8 нс. Так что 12 MTB соответствует 1,5 нс.
Планирование изменений
Чтобы опуститься до DDR3-1066, нам нужно 533 МГц, что составляет 1,875 нс или 15 MTB, или 0x0f. То есть мы хотим написать 0x0f по адресу 0x0c.
Но подождите, очевидно, есть исправление ошибок. CRC первых 116 байт сохраняется в 0x7e-7f. Я посмотрел туда и увидел a4 ae
, затем пошёл искать калькулятор для расчёта. Мне потребовалось удивительно много времени, чтобы найти работоспособный калькулятор CRC. Я попробовал несколько инструментов командной строки, но всё-таки остановился на онлайн-калькуляторе http://crccalc.com/. Затем узнал, что здесь используется вариант CRC-16/XMODEM, а контрольная сумма на самом деле 0xAEA4. Порядок байтов и всё такое. Следовало заметить её в выдаче decode-dimms
.
Поэтому нужно записать новое минимальное время цикла (0x0f) по адресу 0x0c и новую контрольную сумму в 0x7e как слово.
Запись SPD
Теперь я знал, что писать, и наконец осмелился попробовать. Дрожащими руками я набрал y
, нажал Enter для окончательного подтверждения и…
$ i2cset 9 0x50 0x0c 0x0f WARNING! This program can confuse your I2C bus, cause data loss and worse! DANGEROUS! Writing to a serial EEPROM on a memory DIMM may render your memory USELESS and make your system UNBOOTABLE! I will write to device file /dev/i2c-9, chip address 0x50, data address 0x0c, data 0x0f, mode byte. Continue? [y/N] y Error: Write failed
Ошибка. Погодите, что?
Будучи педантичным парнем, я начал изучать исходники i2cset, а также соответствующих модулей ядра. В какой-то момент я понял, что это может быть вызвано защитой от записи.
Я достал модуль памяти, посмотрел на него и узнал микросхему EEPROM. На ней написано 97B
, 321
и некоторые другие вещи. Погуглив, я узнал, что это чип SE97B. Я просмотрел таблицу данных и несколько раз внимательно прочитал раздел о защите от записи. С помощью программ я предпринял несколько попыток удаления временной защиты от записи, но неудачно. Защита от записи, вероятно, была постоянной, поэтому я просто решил поискать модуль, у которого нет защиты от записи.
Забавный факт, кстати, заключается в том, что постоянная защита от записи включается записью чего-то на определённый адрес. Я не думаю, что i2cdetect
нормально это делает, но запуск i2cget 9 0x30 <any-address>
, вероятно, установит постоянную защиту от записи, которая действительно постоянна. Я не пробовал этого делать.
Я взял следующий модуль, и там не было никакого сообщения об ошибке. EEPROM просто не изменился.
Наконец-то, успех!
С третьим модулем наконец-то операция получилась. Я рассчитал CRC и записал его вместе с временем цикла. После загрузки модуля ядра eeprom
и запуска decode-dimms
модуль выглядел как обычный 4GB PC3-8500. Когда я установил его в MacBook Pro, у меня, наконец, загрузилась система с памятью 8 ГБ.
DDR3 SODIMM после ребиннинга готов к работе в MacBook Pro
До: оригинальный DDR3-1333
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 92 10 0b 03 03 19 00 09 03 52 01 08 0c 00 3e 00 ??????.??R???.>. 10: 69 78 69 30 69 11 20 89 00 05 3c 3c 00 f0 83 01 ixi0i? ?.?<<.??? 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 30: 00 00 00 00 00 00 00 00 00 00 00 00 0f 11 45 00 ............??E. 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 70: 00 00 00 00 00 80 ce 02 11 30 b1 5b 13 a1 0e 59 .....????0?[???Y 80: 4d 34 37 31 42 35 32 37 33 43 48 30 2d 43 48 39 M471B5273CH0-CH9 90: 20 20 00 00 80 ce 00 00 00 53 31 42 4e 30 30 30 ..??...S1BN000 a0: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 03 ?.?............? b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 32 59 00 .............2Y. c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
После: выглядит как DDR3-1066
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 92 10 0b 03 03 19 00 09 03 52 01 08 0f 00 3e 00 ??????.??R???.>. 10: 69 78 69 30 69 11 20 89 00 05 3c 3c 00 f0 83 01 ixi0i? ?.?<<.??? 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 30: 00 00 00 00 00 00 00 00 00 00 00 00 0f 11 45 00 ............??E. 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 70: 00 00 00 00 00 80 ce 02 11 30 b1 5b 13 a1 06 54 .....????0?[???T 80: 4d 34 37 31 42 35 32 37 33 43 48 30 2d 43 48 39 M471B5273CH0-CH9 90: 20 20 00 00 80 ce 00 00 00 53 31 42 4e 30 30 30 ..??...S1BN000 a0: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 03 ?.?............? b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 32 59 00 .............2Y. c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Если сразу не видите разницу, то вы не копались в этих свалках так долго, как я.
Свои мысли
Стоит этим заниматься? Финансово, конечно, нет!
Но это было весело и я многому научился. Понятия не имею, где именно можно применить эти знания, но я чувствую, что в определённый момент они понадобятся. И просто само ощущение, что вы можете правильно решить задачу, действительно приятно и даёт уверенность.
1. Моё предположение, что RAM будет работает на данном оборудовании, если оно проходит memtest86, было очевидно неправильным. Тем не менее, даже оглядываясь назад, предположение не кажется глупым. По опыту, не так уж редко встречается странная комбинация аппаратного обеспечения, из-за которой падает стандартный тест. ↑
2. Я недавно я узнал об использовании I²C в другом проекте. Думаю, что смогу считывать и записывать EEPROM на микроконтроллере Cortex-M с помощью собственной программы, но на практике пайка разъёма будет очень сложной, и написание кода — слишком большая работа, чтобы я этим заинтересовался. Тем не менее, я действительно счастлив, что теоретически способен на такое! ↑
Автор: m1rko