I worked on the Metal Gear Solid port from PSX to PC, and Konami programmers chose a wild trick to store how the "C4" bomb was planted - either on the wall, or on the ground.
Essentially the pointer pointed to the same physical memory address, but if it was planted on the wall (or on the ground, I forgot) - then it was OR-ing it with 80000000h or was A0000000h - or maybe something else - lol was long time ago.
It was fun porting this on PC, and right now I don't even remember what I did exactly - hahaha
This is also how the memory card bootloader works.
There is a faulty array iterator in the BIOS code that can copy arbitrary data to locations higher up in the memory map than the base pointer. Normally that wouldn't let you overwrite any executable code because the base pointer is very high up (might be a stack pointer?). But because of the memory aliasing, if you set the right value the write "wraps around" and lets you clobber the BIOS.
This means you can boot a custom BIOS, effectively, by just going into the memory card screen. From there you can execute a PSX.EXE without going through the mechacon checks, bypassing copy protection
---
I wouldn't mind learning more about the MGS port. Do you remember much about it?
It uses TCL for most of the scripting, IIRC. In fact I think MGS 1-4 use the same lineage of scripting languages.
MGS2 source code was leaked recently, but my guess would be that was a complete rewrite and shared very little from the PSX codebase.
Usually, that kind of stunt nowadays is done by using the lowest significant bits and masking them off when dereferencing the pointer, trading off for a higher alignment (so 4 bits gives you 16-byte alignment).
The PS1 also happens to have RAM aliasing, because there's not enough RAM to cover the entire decoding window for the RAM. I don't know the details, but I've seen PS1 executables setting their stack pointer to the end of the devkit's 8 MiB of RAM and yet they work on retail units, because it ends up at the end of the retail's 2 MiB of RAM. So theoretically, you could stuff bits in there too (and without messing with different memory regions with different cache behaviors).
You can see this on many consoles, iirc it basically just boils down to some address pins not being connected anywhere, so whatever the pins are set to doesn't matter as they're just out in the air so to say.
This was also done on the original Macintosh. The Motorola 68000 was a 32-bit CPU but only supported a 24-bit address bus, so the top bits were used by the OS as flags.
Then they released a new Mac with a 68020 that supported a 32-bit address bus and there was a multi-year process of making the OS and all the software "32-bit clean" to take advantage of it. There were 68020 Macs where the ROM in the machine itself wasn't even 32-bit clean and needed a software patch on boot.
Then there’s the opposite situation. I knew the guys who ported NBA Jam: TE from arcade to PC (by hand-translating assembly!). Apparently the arcade CPU had bitwise addressing. And, because pretty much all of the data was aligned to bytes, the arcade programmers liked to stuff 3 bits of extra parameter data into the low bits of pointers.
it's not uncommon for runtimes to use always-zero bits from aligned pointers or bits above 48 (unused in most current 64bit CPUs) to store flags today. you don't need special 'bit-addressing' to do it. byte addressing works just fine.
On the PS1 it's actually slightly more complex than that. The CPU does support up to 16 MB of main RAM (development kits and PS1-based arcade systems did come fitted with more than 2 MB) and has a register to configure its geometry, with the CPU automatically generating an exception when attempting to access unmapped memory. However, Sony's BIOS made the mistake of initializing said register to 8 MB (the configuration used by dev boards) even on retail hardware, resulting in the 2 MB region being mirrored four times. Development builds of games typically assumed 8 MB and put the stack at 0x80800000, so the accidental mirroring made that setup work on retail hardware too (at least as long as the stack did not collide with the heap) even if the developer forgot to move the stack down in the final build.
The PSX BIOS code sounds like a disaster. Everything I read about the software part of the stack, makes me amazed the console even boots
The faulty malloc. A bunch of random qsort implementations. Reiji Asakura wrote an account of how the BIOS and kernel were developed, and it sounds so amateurish
Then there's the way the JP console checks for faulty ECCs on sectors 0..15, not as a clever anti piracy check, but because the CDU-920 broke CD-XA authoring...
The commentary section starts with "The retail PlayStation BIOS code is a constellation of bugs and bad design." and it gets worse after that. There are hidden gems inside the source code comments of that simili-reconstruction.
You could do that on PC too, if you mmap() one given block of memory at multiple locations. I think that's how PS1 emulators handle mirroring (it's been a long time since I took a peek at the innards of DuckStation).
ha! I wish I knew this back then, but now I do remember - I think what we did was simply clearing the bit before access, and it was in just dozen or so places. Slap a macro and you are done!
Interesting! Trying to find that particular code in the decompiled code is proving challenging. I wonder if they haven't yet discovered and documented that yet!
Nowadays this stuff is standardized by hardware extensions.
Arm Top Byte Ignore (TBI), Intel Linear-Address Masking (LAM) and its fixed version Linear Address Space Separation (LASS), AMD Upper Address Ignore (UAI) still unsecure from SLAM exploits. Then you have security extensions build on top of this like ARM Memory Tagging Extension (MTE).
...and resulted in some models having a backwards-compatibility mode not too dissimilar to the PC's A20 gate, although for only a short period of time.
Sandboxing is quite easy (user-wise), once you install the sandbox system. By default it allows only a single sandbox, and with small `.wsb` file you can drive what's visible from the host, whether the GPU should be active, etc. - https://learn.microsoft.com/en-us/windows/security/applicati...
It's great for testing, and Sandbox is just the tip of the iceberg of what Windows Containers support
- e.g. maybe someone can come up with "launcher" that goes through it (somehow).
Ummm, yeah, but Windows Containers is windows Pro and Enterprise only (security is an optional, paid extra on windows), and only for these using Hyper-V (meaning Virtual Box users are excluded).
yup - when I started in 2014, coming from long gamedev experience it was nice that "g4" was just "p4" rewritten for piper. (alzo "blaze menu" was cool, but did not show (AFAIR) places in LAX)....
Yep, I made my own! (Xoogler 2017-2023) this is my noogler IDE story, one of my favorite, proudest hacks!
I developed a fork of the IntelliJ IDE on my second week at google out of raw frustration over latency.
At the time I was commuting 2-3hrs/day SF<>MTV on the gBus.
Connectivity on the bus wasn't optimal, and there was high latency. Cider didn't have deep integration, and wasn't able to let me explore and understand the internal APIs effectively. I found it easier to enter a debug session within Intellij then 'vibe' and explore the internal apis via superComplicatedObject.ini<tab>.
Faced with an alien architecture + ADHD-unfriendly flow-crushing remote desktop latency -- and the lack of discoverability, I started hacking at it and without any knowledge of the system and architecture. Just tracing Intellij execution, subprocesses and network calls.
I was able to hack together a prototype in a few days that allowed me to run IntelliJ on my Mac, while the heavy bits ran on my corp desktop. The system would mount the remote filesystem over sshfs, would monitor and patch network connections and setup transparent shim binaries. Half of Intellij was running on the Mac (the front end) and the other half ran on Linux. Intellij didn't "know" that that it was running on a mac. This was initially implemented in a ~250 line shell script that patched everything.
It was called MDProxy[1] and ended getting adopted and supported during COVID as more development went remote. This became a source of many peer bonuses and spot bonuses. circa 2017* remote coding options at the time:
typing | code
latency | integration
--------------------------
cider low | meh
mdproxy low | great
ssh+vi med | meh
rdp+iJ crushing | great
Dude I was there 2019-2022 and mdproxy was a huge win when I realized I could work while traveling. I remember following some incantations on someone’s personal page to get it running. Then covid happened and I was ahead of everyone for a few weeks because I already had been doing real work on my laptop. Thanks!
Yeah, I was working out of the Sydney office. Almost everything was incredibly slow due to that latency, not just chromoting but also just accessing most sites through beyondcorp.
oh wow! that sounds awesome! (I guess I left around the time you were starting)! I was based in LAX (so no G-Buses for us, but I had to visit MTV often - like once twice a month, and enjoyed getting on one of them)). Kudos!
I’m surprised you find ssh+vi having medium typing latency. I have ssh’ed to either my desktop to (later) my cloudtop and latency has always been great. The ssh latency is good enough that I can run X forwarding to launch graphical instances of emacs and gvim. The latency was basically unnoticeable.
Later I rented a vacation home in South Lake Tahoe and worked remotely. It was only then that I realized it had terrible latency.
latency on the gBus was at the time ~250msish but would regularly spike much more on certain sections. Each keystroke would have to roundtrip before appearing on the screen.
Using something like mosh would mitigate it, but there was no UDP tunnel available through beyoundcorp.
Cider and MDProxy were running rendering locally so the keystrokes were nearly instant.
In the past I've used the backup API - https://sqlite.org/backup.html - in order to load in memory a copy of sqlite db, and have another live one. I would do this after certain user action, and then by doing a diff, I would know what changed... I guess poor way of implementing PostgreSQL events... but it worked!
Granted it was small DB (few megabytes), I also wanted to avoid collecting changes one by one, I simply wanted a diff over last time.
I worked on the Metal Gear Solid port from PSX to PC, and Konami programmers chose a wild trick to store how the "C4" bomb was planted - either on the wall, or on the ground.
Essentially the pointer pointed to the same physical memory address, but if it was planted on the wall (or on the ground, I forgot) - then it was OR-ing it with 80000000h or was A0000000h - or maybe something else - lol was long time ago.
It was fun porting this on PC, and right now I don't even remember what I did exactly - hahaha
reply