Приключения с Xbox 360: долгий путь к RGH3

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Всем привет из Positive Labs! Мы исследуем и разрабатываем различные интересные железки. Как обычно бывает, NDA накладывает ограничения на самое вкусное. И все же очень хочется познакомить вас с тем самым исследовательским духом. К счастью, рабочий процесс очень похож на то, чем я занимался в свободное время (и что вечно откладывал из-за нехватки оного), а значит, пришло время продолжить цикл статей по Xbox 360! Да-да, сегодня речь пойдет о том, как появился самый популярный метод модификации «X-коробки» в наши дни — RGH3.

Предыстория

Несколько лет назад я подумал, что эра Xbox 360 прошла, исследования забиыты, и потихоньку начал избавляться от наследия студенческих времен: приставки продал, запчасти раздал, на форумы залезать перестал. Но у вселенной были совершенно другие планы, стоившие мне нескольких месяцев бессонных ночей. Началось все с известной онлайн-барахолки. Друг попросил подобрать что-нибудь для игр: ПК слабоват, денег нет, а поиграть хочется. Первая мысля — самое время для Xbox 360. Совсем недорого и тянет даже GTA V!

Если долго копаться на барахолке, можно найти всё
Если долго копаться на барахолке, можно найти всё

Приставку мы купили, прошили, дело сделано. Все? Как бы не так. Во-первых, накатила ностальгия по прошивкам. Во-вторых, барахолка продолжила мне подсовывать рекомендовать объявления с приставками и запчастями по интересной цене, как будто дразня.

А потом произошло вот это.

Зарождение Жмых Индастриз
Зарождение Жмых Индастриз

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

Дальше все пошло вообще не по плану: в дискорд-чате по Xbox 360 кто-то выложил купленные на eBay схемы плат для всех ревизий консоли. На этих схемах Josh Davidson (Octal450) неожиданно для всех обнаружил вывод CPU_PLL_BYPASS в Slim-версиях Xbox 360:

Кто вообще додумался продавать такое на eBay?!
Кто вообще додумался продавать такое на eBay?!

Несмотря на то что контактов для этой сигнальной линии на плате нет, разработчики оставили переходное отверстие, к которому после зашкуривания можно припаяться:

Возможно, так процессорный пад лучше держится на плате
Возможно, так процессорный пад лучше держится на плате

Всю важность этой находки можно понять, погрузившись глубже в историю разработки Reset Glitch Hack (RGH). Детально с особенностями RGH можно ознакомиться в третьей части этого цикла статей, а я же кратко введу вас в курс дела.

RGH: историческая справка

RGH, как и другие глитч-атаки, использует факт некорректной работы процессора в определенных условиях. Это может быть слишком высокое или слишком низкое напряжение питания, помехи на опорной частоте процессора или, как в нашем случае, очень короткий импульс низкого уровня на линии сброса (CPU_RESET) процессора.

При обычной установке низкого уровня на этой линии процессор должен перезагрузиться, сбросить свое состояние и начать выполнять код с самого начала, с ROM. Но из-за очень короткой длительности сигнала этого не происходит: процессор продолжает выполнять текущую программу, немного глюкнув при этом, например пропустив выполнение команды или «забыв» записать регистр.

Для такого контролируемого глюка мало подать очень короткий импульс, нужно еще и подать его в нужный момент времени. Чтобы повысить точность попадания и шансы на успех, процессор замедляют. В первом варианте RGH для ревизий Fat замедление происходило через подачу высокого уровня на ту самую линию CPU_PLL_BYPASS, после чего процессор начинал работать в 128 раз медленнее. В этом замедленном режиме тем самым импульсом можно было обойти проверку цифровой подписи:

Проверка контрольной суммы в загрузчике приставки
Проверка контрольной суммы в загрузчике приставки

До недавнего времени считалось, что у Slim-версий приставок нет CPU_PLL_BYPASS, и замедление приходилось выполнять через уменьшение опорной частоты CPU конфигурацией по шине I2C. Но таким образом получалось замедлить процессор всего лишь в 3–4 раза (метод RGH2). К сожалению, после очередного обновления системы Microsoft перевели Fat-приставки на «двойной» режим загрузки, как у Slim-версий, после чего для них тоже пришлось использовать этот метод, так как в режиме 128-кратного замедления время ожидания нужного POST-кода стало непозволительно велико.

Код почти такой же, а вот этап загрузки уже другой
Код почти такой же, а вот этап загрузки уже другой

RGH2 остался единственным методом для Fat-приставок на долгие шесть лет. Работал он нестабильно, запуска приставки можно было ждать несколько минут (а то и не дождаться вовсе). Были попытки увеличить точность отправки глитч-импульса — чипы CR3 Pro (и его клон x360ace) использовали внешний генератор 150 МГц (против 48 МГц в первых решениях), и даже это не всегда спасало:

Нашел фото только на Slim-плате
Нашел фото только на Slim-плате

Но не подумайте, что сцена пустовала, — были и интересные проекты. В чипах R-JTAG и CR4 XL от тех же Team Xecuter был реализован другой, революционный подход — глитч проверки фьюзов для запуска старого загрузчика, из которого уже работал проверенный SMC JTAG Hack (про который можно почитать в первой части серии). И если R-JTAG использовал замедление по опорной частоте, то в CR4 XL применили тот самый CPU_PLL_BYPASS, что снова вернуло стабильность Fat-приставкам. Но чипы были дорогие, в ограниченном количестве, и широкого распространения не получили.

Задумка «все в одном» была неплохая, но китайские x360ace и x360run банально дешевле
Задумка «все в одном» была неплохая, но китайские x360ace и x360run банально дешевле

В конце концов примерно одновременно произошло два события: у меня появилось свободное время (дипломная пора), а DrSchottky решил сделать свой аналог для CR4 XL. За месяц-другой вечерних посиделок были разработаны методы RGH 1.2 и R-JTOP (конкуренция мотивирует). R-JTOP повторял идею CR4 XL — запуск JTAG Hack с помощью глитча проверки фьюзов и CPU_PLL_BYPASS. А вот RGH 1.2 объединил плюсы RGH1 и RGH2, запуская «двойную» загрузку одновременно с использованием CPU_PLL_BYPASS, снова давая идеальную стабильность и в то же время совместимость с RGH2-софтом.

Как это было реализовано? Основной вопрос, заинтересовавший меня тогда, — почему CPU_PLL_BYPASS перестали использовать? Информации про это нигде не было, может, его заблокировали на аппаратном уровне? Быстрая проверка на логическом анализаторе показала, что нет, все еще замедляет в 128 раз. Почему бы тогда не использовать его? Да, на таком замедлении ожидание этапа подсчета контрольной суммы займет очень много времени. Но зачем включать замедление так рано? Нам ведь главное «покрыть» замедлением только момент проверки цифровой подписи (и начало POST-кода перед ним для референса). Поэтому можно немного отложить включение CPU_PLL_BYPASS, чтобы оно произошло как раз перед проверкой, и получить следующий алгоритм глитча приставки:

  • ожидание POST-кода 0xD9 (или 0xD8, если смотреть по линии POST_1);

  • ожидание некоторого числа миллисекунд;

  • включение PLL_BYPASS;

  • ожидание POST-кода 0xDA;

  • ожидание другого некоторого числа миллисекунд;

  • глитч-импульс на RST.

Правильный подбор значений длился несколько дней, но все получилось.

Как сказал один из ревьюверов статьи: «Зачетный ковер»
Как сказал один из ревьюверов статьи: «Зачетный ковер»

Проект я с тех пор подзабросил, а исходники передал тому самом Джошу aka Octal450, который продолжил работу и сделал:

  • обновленную версию RGH 1.2 для других модчипов;

  • версию с CPU_EXT_CLK (замедляет примерно в 10,7 раза, а не в 128) для Fat-ревизий Xenon и Zephyr, где использование CPU_PLL_BYPASS приводит к зависанию;

  • расширенный набор функций для утилиты J-Runner (до сих пор поддерживает и добавляет фичи).

И вот теперь в его руки попадает тот самый даташит с расположением CPU_PLL_BYPASS для Slim-приставок. Теперь понимаете грандиозность момента? Конечно же, он сразу пошел портировать наработки и подбирать параметры замедления (глитча) уже для Slim-версии. В отличие от Fat-ревизий, использование CPU_PLL_BYPASS на Slim давало замедление не в 128 раз, а в целых 640. Из-за этого подбор параметров затянулся.

Здесь уже и я подключился к исследованию. Чтобы ускорить подбор параметров, я собрал особый загрузчик, который повторял код в бесконечном цикле, и уже на это непотребство натравил чип. С таким стендом параметры довольно быстро удалось определить, после чего я передал их Джошу для доработки.

Один из чипов — для анализа POST шины, второй — для глитча
Один из чипов — для анализа POST шины, второй — для глитча

И тут у меня возникла безумная идея. Если есть настолько крутое замедление, можно ли обойтись совсем без чипа с его высокой точностью? В приставке есть System Management Controller (SMC) — независимый микроконтроллер на ядре Intel 8051, работающий на частоте 48 МГц. На его основе делали JTAG SMC Hack, да еще и линия CPU_RESET на него идет...

Где-то на этом моменте я накупил различных материнок от Xbox 360, обложился логическими анализаторами и с головой ушел в очередное исследование внутренностей приставки…

Что в SMC тебе моём?

Как и во многих других системах, помимо основного CPU, в Xbox 360 имеется дополнительный чип SMC, который выполняет вспомогательные задачи:

  • реакция на кнопки (питания, извлечения диска);

  • подача питания на компоненты приставки;

  • согласование вывода изображения (AV или HDMI);

  • контроль температуры и кулеров.

В ноутбуках такая штука зовется Embedded Controller (EC), но идеи схожи. SMC всегда включен, потребляет немного тока и у него есть своя прошивка!

Забавно выходит. Копетти ссылается на мои статьи, а я — на его
Забавно выходит. Копетти ссылается на мои статьи, а я — на его

Конечно, прошивка эта зашифрована и имеет контроль целостности, но алгоритм давно известен, а никакой проверки цифровой подписи сюда не завезли:

def decrypt_smc(data):
    key = [0x42, 0x75, 0x4e, 0x79]
    res = bytearray()
    for i in range(len(data)):
        j = data[i]
        mod = j * 0xFB
        res.append(j ^ (key[i & 3] & 0xFF))
        key[(i + 1) & 3] += mod
        key[(i + 2) & 3] += mod >> 8
    return bytes(res)

Интересно, что алгоритм есть и в коде гипервизора Xbox 360.

Вероятно, система так проверяет корректность SMC при обновлении
Вероятно, система так проверяет корректность SMC при обновлении

Читать или писать прошивку тоже не проблема — интерфейс SPI + два дополнительных контакта.

Широко известный лет 10 назад Super NAND Flasher
Широко известный лет 10 назад Super NAND Flasher

Один из контактов — Reset-линия SMC, а другой — DBG_EN.

И снова схема помогает найти детали
И снова схема помогает найти детали

При перезагрузке с удержанием DBG-линии SMC входит в специальный режим, когда по SPI можно читать и писать NAND приставки. Кстати, это нашли благодаря изучению Sidecar от девелоперской версии Xbox 360 (XDK).

Всё самое интересное — в этой нашлепке
Всё самое интересное — в этой нашлепке

Как раз к ней подключены те самые разъемы на плате, куда паяют программатор. Такая архитектура помогает разработчику восстановить приставку, даже если NAND целиком стерт.

Вид на нашлепку изнутри приставки
Вид на нашлепку изнутри приставки

К этому еще вернемся в самом конце, а пока что — дизасм и раскрытие секретов!

Привет из SMC

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

Прошивка 8051 явно не так должна начинаться
Прошивка 8051 явно не так должна начинаться

На самом деле, для дополнительной защиты от анализа первые 4 байта SMC — случайные, чтобы код в каждой приставке был зашифрован уникальным образом. «Настоящие» 4 начальных байта находятся в самом конце прошивки.

Почему-то все утилиты по работе с SMC не переносят эти 4 байта при расшифровке
Почему-то все утилиты по работе с SMC не переносят эти 4 байта при расшифровке

Если их поместить в начало, получим гораздо более осмысленный код с прыжками на различные обработчики прерываний.

Уже больше похоже на начало прошивки 8051
Уже больше похоже на начало прошивки 8051

Одна тайна разгадана, осталось много. Как встроиться в прошивку? Как управлять периферией? Как вообще написать что-то под этот чип?!

Часть информации можно почерпнуть из двух других проектов — SMC JTAG Hack и CR4 XL (пропатченные прошивки для SMC с их кодом можно найти в комплекте с утилитой J-Runner). Известно, что код в первом проекте использует GPIO для конфигурации GPU по JTAG:

Именовал функции сам, может отличаться от задумки автора
Именовал функции сам, может отличаться от задумки автора

А код CR4 XL, в свою очередь, следит за состоянием GPIO и отправляет по I2C соответствующие команды.

Здесь кода было поменьше, зато сам код понятнее
Здесь кода было поменьше, зато сам код понятнее

Если сопоставить номера битов в аппаратных регистрах со схемой приставки, то можно заметить, что они соответствуют портам GPIO, к которым подключены соответствующие линии.

Как же удобно иметь схематик под рукой
Как же удобно иметь схематик под рукой

Копаясь тем же образом в коде дальше, можно найти все регистры, отвечающие за GPIO:

  • SFR_80,90,A0,C0,C8 = GPIO_P0..P4 — значения на выводах GPIO

  • SFR_A2..A6 = GPIO_P0..P4_DIR — режим пина (input или output)

  • SFR_9D..9F,A1,A7 = GPIO_P0..P4_OD — настройка open-drain-режима

Теперь можно шевелить пинами и выводить что-то осмысленное на логический анализатор! Но для этого сначала нужно скомпилировать код. Поскольку придется встраиваться в существующую прошивку, писать нужно прямо на ассемблере. К примеру, ниже — код простейшей функции, которая на короткое время взведет один из неиспользуемых пинов SMC в единицу. Функция будет размещена по смещению 0x31E0 — это первый неиспользуемый адрес в оригинальной прошивке SMC для ревизии Corona.

DBG_PIN equ 080h.5

org 031E0h
    setb DBG_PIN
    clr  DBG_PIN
    ret
end

Минималистично? А то! После сборки получилось всего 5 байт.

Теперь его нужно каким-то образом засунуть в оригинальную прошивку. Удобнее всего это сделать, если встроиться в основной цикл исполнения. В микроконтроллерах вся логика обычно реализуется через finite-state machine (FSM, конечные автоматы). И все эти автоматы по очереди выполняются в главном цикле.

Ну ладно, в двух главных циклах
Ну ладно, в двух главных циклах

Малый цикл содержит задачи, требующие немедленной реакции (например, обработка I2C). В большом же расположены задачи, которые требуется запускать с определенным интервалом, так они отсчитывают время до тайм-аута (например, обработка кнопок, переключение состояний питания, моргание светодиодом).

Думаю, ничего страшного не случится, если заменить задачу моргания диода (которого на магазинной плате, кстати, не бывает) на вызов нашей процедуры:

import struct

def patch(data, offset, new):
    return data[:offset] + new + data[offset + len(new):]

def lcall(offset):
    return b"\x12" + struct.pack(">H", offset)

CODE_START = 0x31E0

smc = open("smc_corona.bin", "rb").read()
code = open("build.bin", "rb").read()[CODE_START:]
smc = patch(smc, CODE_START, code)
smc = patch(smc, 0x829, lcall(CODE_START))
smc = patch(smc, 0x256B, b'\x90') # P0.5 OUT dir

open("new_smc.bin", "wb").write(smc)

В результате на паде DB3R4, который соответствует порту 80h.5, можно видеть сигнал с периодом 20 мс.

Заодно и период определили, с которым выполняется «большой» цикл
Заодно и период определили, с которым выполняется «большой» цикл

Теперь хоть какой-то, но дебаг имеется. Неплохо было бы иметь дебаг получше, например, UART. И — бинго — на схеме платы он есть:

А еще чуть выше есть системный UART от CPU
А еще чуть выше есть системный UART от CPU

Обычно UART соответствует некоторый аппаратный регистр, запись в который приводит к посылке данных. И чтобы найти этот самый нужный регистр, я, конечно же, писал во все регистры подряд и смотрел, что происходит на аппаратной линии (так, конечно, лучше не делать: за время брутфорса я успел повключать регуляторы питания, наткнуться на регистр watchdog и пару других вещей). И таки нашел. Запись данных в регистр E7 приводит к импульсам на линии.

UART, ты ли это?
UART, ты ли это?

Похоже на UART, но нет, картина всегда одинаковая, что бы я в регистр ни писал.

Дальнейшие эксперименты с брутфорсом соседних регистров принесли результаты. Оказывается, нужно дополнительно включить UART (SFR_E8 = 0xC0) и настроить его скорость (SFR_E9 = 0xFF, максимальная скорость — 1 500 000 бод). После этого уже получаем нормальный вывод UART.

Вот теперь точно UART
Вот теперь точно UART

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

put_uart:
    mov     0E7h, A
    mov     A, #09h
loop_uart:
    djnz    0E0h, loop_uart
    ret

Благодаря этому в UART уже можно писать более осмысленные вещи:

Да, почему-то аппаратно нет завершающего бита, но это не мешает работе
Да, почему-то аппаратно нет завершающего бита, но это не мешает работе

I2C

Одного лишь CPU_PLL_BYPASS для стабильного глитч-хака из SMC, по моим предположениям, было недостаточно. Даже с замедлением в 640 раз длина импульса, который порождается кодом ниже, была слишком велика (по сравнению с импульсом в RGH1):

    clr     080h.6
    setb    080h.6

Значит, помимо активации CPU_PLL_BYPASS, нужно дополнительно замедлять процессор по I2C, как это делали в RGH2, снизив опорную частоту 100 МГц, которую выдает HANA.

Схема от Xenon. В более новых ревизиях вместо ANA используется HANA (HDMI ANA)
Схема от Xenon. В более новых ревизиях вместо ANA используется HANA (HDMI ANA)

Увы, в открытом доступе нет информации, как именно в RGH2 происходит замедление. С помощью логического анализатора удалось достать только несколько значений, которые использовались в модчипах и проекте CR4 XL:

  • [CF] = 0x40’44’AC’C0 — Corona, 100 МГц, обычный режим;

  • [CF] = 0x08’44’40’40 — Corona, 33,3 МГц, замедленный режим (CR3 Pro / CR4);

  • [CF] = 0x08’54’54’30 — Corona, 25 МГц, замедленный режим (RGH2);

  • [CD] = 0x02’0C’80’4E — Falcon, Jasper, Trinity, 100 МГц, обычный режим;

  • [CD] = 0x03’80’08’4E — Falcon, Jasper, Trinity, 31,5 МГц, замедленный режим.

Почему значения именно такие? Какие другие частоты можно задать? В обсуждениях упоминалась информация, что на совсем низких частотах процессор работает нестабильно, — правда ли это? Давайте узнаем!

Для этого нужно проверить частоту опорного сигнала, поступающего от HANA к процессору. Логично было бы сделать это с помощью осциллографа, и таковой у меня имелся — DSCope U2P20.

Купил на AliExpress вместе с анализатором DSLogic. Пригодился впервые.
Купил на AliExpress вместе с анализатором DSLogic. Пригодился впервые.

Одна загвоздка: на процессор поступает 100 МГц, сигнал дифференциальный и низковольтажный, а осциллограф работает только с частотами до 50 МГц, и то — если повезет. Чтобы производить замер частоты, нужно либо более крутое оборудование (это сейчас в Positive Labs у меня появилась огромная лаборатория под боком, а тогда приходилось довольствоваться имеющимся), либо каким-то образом поделить частоту, допустим, раз в 10, а затем измерить осциллографом, что я и сделал.

Чем же можно поделить частоту? Под рукой было несколько модчипов для Xbox 360 на базе CPLD Xilinx CoolRunner II, как на рисунке ниже.

Как вы уже догадались, использовать я их буду не совсем по назначению
Как вы уже догадались, использовать я их буду не совсем по назначению

Обратите внимание, что на фотографии на чипе нет маркировки. И нет, она не затерта. Изначально эти модчипы делались на именно таких 44-ногих чипах, XC2C64A-VQ44. Народ привык, покупал именно эти, но вот незадача: они закончились. Зато остались те же самые XC2C64A в других корпусах.

Корпуса QFN-48, BGA-56, QFP-100 одного и того же CPLD
Корпуса QFN-48, BGA-56, QFP-100 одного и того же CPLD

Увы, люди берут то, к чему привыкли, и, несмотря на почти полную идентичность (у них был другой ID и не весь софт их поддерживал), популярностью эти модчипы не пользовались. И китайцы придумали решение … Они подумали: «我們只需要在板子前面裝上塑膠誘餌,然後把真正的晶片藏在背面就可以了 Давайте спереди на плате будет просто пластиковая обманка, а настоящий чип спрячем сзади!»

Чип стыдливо прикрывается толстым двусторонним скотчем со специальным вырезом
Чип стыдливо прикрывается толстым двусторонним скотчем со специальным вырезом

Вот на таком модчипе я и соорудил «делитель частоты» (болванку отпаял, чтоб не мешалась).

Слева — линейный регулятор для VCCIO, настроенный примерно на 1,3 В
Слева — линейный регулятор для VCCIO, настроенный примерно на 1,3 В

Несмотря на то что в этом CPLD нет поддержки дифференциальных линий, благодаря тому, что в Xbox 360 диффпары HANA формируются двумя линиями push-pull, работающими в противофазе, получилось корректно снимать уровни относительно GND. Правда, пришлось понизить напряжение I/O Bank до 1,3 В. Вот такой VHDL-проект с уровнями LVCMOS12 отлично делит частоту на 10:

process(PIN_B) is
  begin
    if PIN_B'event then
	     divcnt <= divcnt + 1;
		  if divcnt = 9 then
				temp <= not temp;
				divcnt <= 0;
		  end if;
		  PIN_D <= temp;
    end if;
  end process;
Интерфейс DSCope прост как топор
Интерфейс DSCope прост как топор

Ну, почти отлично: при 100 МГц на выходе получается неравномерная колбасня, оцениваемая осциллографом на 9,31 МГц, но на чуть меньших частотах все в порядке.

Вот такие прямоугольные сигналы мне предстояло наблюдать следующие пару дней
Вот такие прямоугольные сигналы мне предстояло наблюдать следующие пару дней

Zephyr, Falcon, Jasper, Trinity

На большей части ревизий Xbox 360 (Zephyr, Falcon, Jasper, Trinity) механизм опорной частоты работает одинаково, поэтому разумно начать анализ именно с них. В RGH2 для замедления нужно сконфигурировать регистр 0xCD. Для этого я начал с некоторого значения, а затем менял каждый из битов регистра и фиксировал получаемую с помощью осциллографа частоту. Для работы с I2C я воспользовался открытым проектом pyFTDI.

Радиаторов без кулеров хватает минут на 6–7 до перегрева
Радиаторов без кулеров хватает минут на 6–7 до перегрева
from pyftdi.i2c import I2cController
import struct

i2c = I2cController()

i2c.configure('ftdi://ftdi:2232h/1')
slave = i2c.get_port(0x70)

def read_cd():
    (_, result) = struct.unpack("<BI", slave.exchange([0xCD], 5))
    return result

def write_cd(val):
    slave.write_to(0xCD, struct.pack("<BI", 4, val))

Тщательно замерив результаты для комбинаций битов, я получил вот такую табличку:

# xxxxxx 010 000110 00000100001001110 - 12.0 MHz
# xxxxxx 100 000110 00000100001001110 - 7.17 MHz
# xxxxxx 111 000110 00000100001001110 - 4.48 MHz
# xxxxxx 110 100110 00000100001001110 - 0.92 MHz
# xxxxxx 110 010110 00000100001001110 - 1.56 MHz
# xxxxxx 110 001110 00000100001001110 - 2.40 MHz
# xxxxxx 110 000010 00000100001001110 - 12.0 MHz
# xxxxxx 110 000100 00000100001001110 - 7.17 MHz
# xxxxxx 110 000111 00000100001001110 - 4.48 MHz
# xxxxxx 110 000110 10000100001001110 - ???  MHz
# xxxxxx 110 000110 01000100001001110 - 75.6 MHz
# xxxxxx 110 000110 001001000 01001110 - 40.4 MHz
# xxxxxx 110 000110 000101000 01001110 - 28.8 MHz
# xxxxxx 110 000110 000011000 01001110 - 13.9 MHz
# xxxxxx 110 000110 000000000 01001110 - ??? MHz
# xxxxxx 110 000110 000001100 01001110 - 7.33 MHz
# xxxxxx 110 000110 000001010 01001110 - 6.22 MHz
# xxxxxx 110 000110 000001001 01001110 - 5.67 MHz
# xxxxxx 110 000110 000001000 11001110 - 5.40 MHz
# xxxxxx 110 000110 000001000 00001110 - 4.98 MHz
# xxxxxx 110 000110 000001000 01101110 - 5.19 MHz
# xxxxxx 110 000110 000001000 01011110 - 5.16 MHz
# xxxxxx 110 000110 000001000 01011010 - 5.10 MHz
# xxxxxx 110 000110 000001000 01001100 - 5.12 MHz
# xxxxxx 110 000110 000001000 01001111 - 5.12 MHz

Итого получается:

  • первые 6 бит не влияют на частоту;

  • следующие 3 бита — делитель № 1 (минус единица);

  • следующие 6 бит — делитель № 2 (минус единица);

  • следующие 9 бит — множитель (минус единица);

  • последние 8 бит — коррекция.

Например, если взять конфигурацию по умолчанию (0x20C804E), то можно получить:

  • 0x20C804E = 100  000110  010000000  01001110

  • D1 = 4 + 1

  • D2 = 6 + 1

  • B = 128 + 1

  • O = 78

Тогда итоговая частота равна N × 129 / 5 / 7 + 78 × D, где

  • N — частота системного кварца (27 МГц)

  • D — множитель коррекции (~0,00214 МГц)

Занимательный факт: по формуле выходит, что опорная частота Xbox 360 этих ревизий равна около 99,68 МГц.

В ходе экспериментов с различными частотами выяснилось, что менять коэффициенты PLL «на ходу» затея не очень хорошая: при очень низких значениях частота не меняется либо меняется неправильно, при очень высоких — частота перестает генерироваться совсем. Но самое нехорошее — что при одних и тех же параметрах и самых идеальных условиях частота может совсем незначительно, но отличаться!

Напомню, что для высокой точности глитч-хака обязательно нужно попадать в один и тот же момент. А здесь он «плавает». Теперь становится понятно, почему результаты RGH2 были такие рандомные. Чтобы исправить этот недочет, я начал искать, каким же регистром можно перезагрузить PLL: обычно в оборудовании смена конфигурации требует выключения и последующего включения аппаратного модуля — вдруг поможет.

Для этого я начал менять биты соседних регистров и одновременно смотреть на вывод осциллографа. И такой брутфорс принес результаты! Правда, нашел совсем не то, что искал, но вышло даже лучше. Старшие 8 бит регистра 0xCE управляют источником опорной частоты CPU:

  • 0x08E84014 — стандартный режим, PLL;

  • 0x28E84014 — Bypass EXT (27 МГц) — частота напрямую с внешнего кварца;

  • 0x48E84014 — смена режима регистра 0xCD, делители и множители работают как-то странно (не изучал, возможно, это PLL_INT);

  • 0x88E84014 — Bypass INT (предположительно, от 3 до10 МГц) — вероятно, частота напрямую с внутреннего генератора, сильно плавает;

  • 0xC8E84014 — None (нет генерации).

И режим Bypass EXT отлично подходит для глитча: частота всегда стабильна, включается и выключается одной командой без каких-либо последствий, в отличие от перенастройки PLL.

Corona

В ревизии Corona чип HANA отсутствует — его функциональность теперь находится в южном мосте. Регистры генератора частот тоже поменяли свое назначение.

Первая строчка обозначает поколение южного моста. XSB (Xenon), PSB (Panda), KSB (Koala)
Первая строчка обозначает поколение южного моста. XSB (Xenon), PSB (Panda), KSB (Koala)

С помощью аналогичного перебора и экспериментов с регистром 0xCF была получена следующая табличка:

#0x100 - 132 MHz
#0x0C0 - 100 MHz
#0x040 - 33 MHz
#0x030 - 25 MHz
#0x020 - 16.6 MHz
#0x021 - 8.3 MHz
#0x022 - ?
#0x023 - 5.55 MHz
#0x024 - 18.7 MHz
#0x025 - 9.3 MHz
#0x026 - 4.68 MHz
#0x027 - ?
#0x028 - 20.8 MHz
#0x029 - 10.4 MHz
#0x02a - 5.2 MHz
#0x02b - 6.9 MHz
#0x02c - 22.9 MHz
#0x02d - 11.4 MHz
#0x02E - 5.7 MHz
#0x02F - 7.6 MHz
#0x116 - 36 MHz
#0x319 - 180 MHz
#0x219 - 140 MHz

Из этого выходит, что последние 3 бита отвечают за делитель, но несколько необычным образом:

  • 00 — x1

  • 01 — x2

  • 10 — x4

  • 11 — x3

А следующие за ними 8 бит — множитель. И формула для конечной частоты имеет вид M / D × 100/48, где

  • M — множитель,

  • D — соответствующий делитель.

Наименьшая стабильная частота, которую удалось выставить,— 3,6 МГц, что очень даже неплохо. Увы, ускоряется и замедляется вообще все: GPU, CPU и даже SMC (это легко заметить по изменившейся частоте работы UART). А раз SMC замедляется, замедлится и код, который выполняется внутри и реализует глитч-хак, поэтому замедление через HANA PLL, увы, не годится.

Интересно

При таком замедлении вращающийся кулер начинает издавать специфический звук, причем тон звука зависит от заданной частоты. Device Orchestra, ловите идею!

К счастью, как и на предыдущих ревизиях, брутфорсом регистров HANA был обнаружен режим Bypass и для ревизии Corona. Для этого достаточно в регистре 0xDB установить 3 бит:

  • 0x01F001F8 — Bypass EXT (25 МГц),

  • 0x01F001F0 — стандартный режим, PLL.

После этого на CPU вместо частоты 100 МГц начинает поступать 25 МГц напрямую с системного кварца, чего вполне достаточно для замедления.

В процессе перебора также был обнаружен аналогичный Bypass для GPU (регистр 0xDB, 0x01F801F0) и для pixel_clk (регистр 0xDC, 0x000001F8).

Проблемные Fat’ки

Как я писал выше, на старых Fat-ревизиях отключение PLL замедляет процессор всего в 128 раз — в 5 раз меньше, чем на Slim-версии. К сожалению, такая величина замедления оказалась все еще недостаточной и глитч зачастую не срабатывает из-за тормознутости SMC. То в нужный момент не попадает, то импульс недостаточно короткий. Вариантов решения тут два: либо использовать конфигурируемое замедление через I2C (чревато нестабильностью из-за особенностей HANA PLL), либо… разогнать южный мост!

Изначально он работает на частоте 48 МГц, но ведь эта опорная частота тоже генерируется HANA и может быть изменена! В итоге снова был выполнен брутфорс регистров и было определено, что за частоту южного моста отвечает регистр 0xD4. Требуемый уровень разгона был с легкостью достигнут через изменение младших битов:

  • 0x990e00e — изначальное значение (48 МГц);

  • 0x990e001e — двукратный разгон (96 МГц);

  • 0x990e026 — максимальное значение, которое смог осилить мой HANA (120 МГц).

Определить полный расклад регистра по битам (делитель, Bypass, множитель) можете самостоятельно на досуге

Источник: https://habr.com/ru/companies/pt/articles/874160/


Интересные статьи

Интересные статьи

Методология тестирования на проникновение предполагает разделение поиска уязвимостей на несколько этапов. Один из первых этапов заключается в поиске легаси с известными уязвимостями, популярных мискон...
Я расскажу вам, какие три звоночка заставили меня навсегда (по крайней мере, это до сих пор так) принять факт бесполезности собственной разработки, и решили судьбу вообще всех моих дальнейших стараний...
Несколько недель назад в блоге «.NET Blog« появилась статья «Что такое .NET, и почему вы должны выбрать его?« В нем был представлен высокоуровневый обзор платформы, кратко описаны различные компоненты...
Приветствую вас (лично вас, а не всех кто это читает)! Сегодня мы: Создадим приложение (навык) Алисы с использованием нового (октябрь 2019) сервиса Yandex Cloud Functions. Настроим н...
Эта статья для тех, кто собирается открыть интернет-магазин, но еще рассматривает варианты и думает по какому пути пойти, заказать разработку магазина в студии, у фрилансера или выбрать облачный серви...