Harden legacy bounds

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Joey Yakimowich-Payne 2026-08-11 12:51:36 +09:00
commit e2a7635f2f
3 changed files with 228 additions and 49 deletions

View file

@ -1,4 +1,5 @@
#include "switch_pro_driver.h"
#include "switch_pro_bounds.h"
#include <algorithm>
#include <cstring>
@ -178,9 +179,14 @@ static const uint8_t user_calibration_data[0x3F] = {
static const SwitchFactoryConfig* factory_config = reinterpret_cast<const SwitchFactoryConfig*>(factory_config_data);
static const SwitchUserCalibration* user_calibration [[maybe_unused]] = reinterpret_cast<const SwitchUserCalibration*>(user_calibration_data);
static std::map<uint32_t, const uint8_t*> spi_flash_data = {
{0x6000, factory_config_data},
{0x8000, user_calibration_data}
struct SpiFlashRegion {
const uint8_t* data;
std::size_t size;
};
static const std::map<uint32_t, SpiFlashRegion> spi_flash_data = {
{0x6000, {factory_config_data, sizeof(factory_config_data)}},
{0x8000, {user_calibration_data, sizeof(user_calibration_data)}}
};
static inline uint16_t scale16To12(uint16_t pos) { return pos >> 4; }
@ -235,16 +241,32 @@ static bool send_report(uint8_t reportID, const void* reportData, uint16_t repor
return result;
}
static void read_spi_flash(uint8_t* dest, uint32_t address, uint8_t size) {
static void read_spi_flash(
uint8_t* destination,
std::size_t destination_capacity,
uint32_t address,
uint8_t size) {
uint32_t addressBank = address & 0xFFFFFF00;
uint32_t addressOffset = address & 0x000000FF;
auto it = spi_flash_data.find(addressBank);
if (it != spi_flash_data.end()) {
const uint8_t* data = it->second;
memcpy(dest, data + addressOffset, size);
const SpiFlashRegion& region = it->second;
switch_pro_fill_flash_read(
destination,
destination_capacity,
region.data,
region.size,
addressOffset,
size);
} else {
memset(dest, 0xFF, size);
switch_pro_fill_flash_read(
destination,
destination_capacity,
nullptr,
0,
0,
size);
}
}
@ -371,7 +393,11 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
report_buffer[17] = reportData[13];
report_buffer[18] = reportData[14];
report_buffer[19] = reportData[15];
read_spi_flash(&report_buffer[20], spiReadAddress, spiReadSize);
read_spi_flash(
&report_buffer[20],
sizeof(report_buffer) - 20,
spiReadAddress,
spiReadSize);
canSend = true;
LOG_PRINTF("[HID] FEATURE SPI_READ addr=0x%08lx size=%u\n", (unsigned long)spiReadAddress, spiReadSize);
break;
@ -642,6 +668,52 @@ bool switch_pro_is_ready() {
return is_ready;
}
static void dispatch_output_report(
uint8_t instance,
uint8_t report_id,
const uint8_t* buffer,
uint16_t length) {
if (instance != 0) {
return;
}
const SwitchProOutputReportKind kind =
switch_pro_classify_output_report(buffer, length);
if (kind == SwitchProOutputReportKind::Ignore) {
return;
}
if (kind == SwitchProOutputReportKind::Feature &&
buffer[10] == SPI_READ &&
!switch_pro_spi_read_size_fits(buffer[15])) {
return;
}
memset(report_buffer, 0x00, sizeof(report_buffer));
const uint8_t switchReportID = buffer[0];
const uint8_t switchReportSubID = buffer[1];
LOG_PRINTF("[HID] output_report id=%u switchRID=0x%02x sub=0x%02x len=%u\n",
report_id, switchReportID, switchReportSubID, length);
switch (kind) {
case SwitchProOutputReportKind::Noop:
return;
case SwitchProOutputReportKind::Rumble:
forward_rumble_to_host(buffer, length);
return;
case SwitchProOutputReportKind::Feature:
queued_report_id = report_id;
handle_feature_report(switchReportID, switchReportSubID, buffer, length);
return;
case SwitchProOutputReportKind::Configuration:
queued_report_id = report_id;
handle_config_report(switchReportID, switchReportSubID, buffer, length);
return;
case SwitchProOutputReportKind::Ignore:
return;
}
}
// HID callbacks
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
(void)instance;
@ -656,51 +728,12 @@ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_t
}
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
(void)instance;
if (report_type != HID_REPORT_TYPE_OUTPUT) return;
memset(report_buffer, 0x00, bufsize);
uint8_t switchReportID = buffer[0];
uint8_t switchReportSubID = buffer[1];
LOG_PRINTF("[HID] set_report type=%d id=%u switchRID=0x%02x sub=0x%02x len=%u\n",
report_type, report_id, switchReportID, switchReportSubID, bufsize);
if (switchReportID == REPORT_OUTPUT_10 || switchReportID == REPORT_OUTPUT_21) {
forward_rumble_to_host(buffer, bufsize);
}
if (switchReportID == REPORT_OUTPUT_00) {
// No-op, just acknowledge to clear any stalls.
return;
} else if (switchReportID == REPORT_FEATURE) {
queued_report_id = report_id;
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
} else if (switchReportID == REPORT_CONFIGURATION) {
queued_report_id = report_id;
handle_config_report(switchReportID, switchReportSubID, buffer, bufsize);
} else {
}
dispatch_output_report(instance, report_id, buffer, bufsize);
}
void tud_hid_report_received_cb(uint8_t instance, uint8_t report_id, uint8_t const* buffer, uint16_t bufsize) {
(void)instance;
// Host sent data on interrupt OUT; mirror the control path handling.
memset(report_buffer, 0x00, bufsize);
uint8_t switchReportID = buffer[0];
uint8_t switchReportSubID = buffer[1];
LOG_PRINTF("[HID] report_received id=%u switchRID=0x%02x sub=0x%02x len=%u\n",
report_id, switchReportID, switchReportSubID, bufsize);
if (switchReportID == REPORT_OUTPUT_10 || switchReportID == REPORT_OUTPUT_21) {
forward_rumble_to_host(buffer, bufsize);
}
if (switchReportID == REPORT_OUTPUT_00) {
return;
} else if (switchReportID == REPORT_FEATURE) {
queued_report_id = report_id;
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
} else if (switchReportID == REPORT_CONFIGURATION) {
queued_report_id = report_id;
handle_config_report(switchReportID, switchReportSubID, buffer, bufsize);
}
dispatch_output_report(instance, report_id, buffer, bufsize);
}
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) {