logoalt Hacker News

NobodyNadayesterday at 6:09 PM1 replyview on HN

Open bus quite literally means that the data bus lines are an open circuit -- the CPU has placed an unmapped or write-only address on the address bus, and no hardware on the bus has responded, so the bus lines aren't being driven and are just floating. Thus, nominally, this is a case of undefined behavior at the hardware level.

In order to understand what actually happens, we need to look a little closer at the physical structure of a data bus -- you have long conductors carrying the signals around the motherboard and to the cartridge, separated from the ground plane by a thin layer of insulating substrate. This looks a lot like a capacitor, and in fact this is described and modeled as "parasitic capacitance" by engineers who try to minimize it, since this effect limits the maximum speed of data transmission over the bus. But this effect means that, whenever the bus is not being driven, it tends to stay at whatever voltage it was last driving to -- just like a little DRAM cell, producing the "open-bus reads return the last value transferred across the bus" effect described in the article.

It's not uncommon for games to accidentally rely on open-bus effects, like DKC2. On the NES, the serial port registers for connecting to a controller only drive the low-order bits and the high bits are open-bus; there are a few games that read the controller input with the instruction LDA $4016 and expect to see the value $40 or $41 (with the 4 sticking around because of open-bus).

There's also speedrun strategies that rely on open-bus behavior as part of memory-corruption or arbitrary-code-execution exploits, such as the Super Mario World credits warp, which sends the program counter on a trip through unmapped memory before eventually landing in RAM and executing a payload crafted by carefully manipulating enemy positions [1].

But there's some exceptions to the usual predictable open bus behavior. Nonstandard cartridges could return a default value for unmapped memory, or include pull-up or pull-down resistors that impact the behavior of open bus. There's also an interesting interactions with DMA; the SNES supports a feature called HDMA which allows applications to schedule DMA transfers to transfer data from the CPU to the graphics hardware with precise timing in order to upload data or change settings mid-frame [2]. This DMA transfer temporarily pauses the CPU in order to use the bus to perform the transfer, which can change the behavior of an open-bus read if a DMA transfer happens to occur in the middle of an instruction (between reading the target address & performing the actual open-bus read).

This very niche edge case has a significant impact on a Super Metroid speedrun exploit [3] which causes an out-of-bounds memcpy, which attempts to transfer a large block of data from open-bus to RAM. The open-bus read almost always returns zero (because the last byte of the relevant load instruction is zero), but when performed in certain rooms with HDMA-heavy graphical effects, there's a good chance that a DMA transfer will affect one of the reads, causing a non-zero byte to sneaks in somewhere important and causing the exploit to crash instead of working normally. This has created a mild controversy in the community, where some routes and strategies are only reliable on emulators and nonstandard firmwares; a player using original hardware or a very accurate emulator has a high chance of experiencing a crash, whereas most emulators (including all of Nintendo's official re-releases of the game) do not emulate this niche edge case of a mid-instruction HDMA transfer changing the value of an open-bus read.

Also, the current fastest TAS completion of Super Metroid [4] relies on this HDMA interaction. We found a crash that attempted to execute open bus, but wasn't normally controllable in a useful way; by manipulating enemies in the room to influence CPU timing, we were able to use HDMA to put useful instructions on the bus at the right timing, eventually getting the console to execute controller inputs as code and achieve full arbitrary code execution.

[1]: https://youtu.be/vAHXK2wut_I

[2]: https://youtu.be/K7gWmdgXPgk

[3]: https://youtu.be/CnThmKhtfOs

[4]: https://tasvideos.org/8214S


Replies

russellbeattieyesterday at 8:54 PM

> ... we need to look a little closer at the physical structure of a data bus

Once again, I have to give a shout out to Ben Eater, whose video series on making a breadboard computer with the 6502 is why I actually understand what the article is about and what you're referring to when describing the hardware issues. (Obviously, extrapolating from his basic bus example to a commercial machine.) I'd be pretty clueless otherwise.

https://eater.net