If you don't have access to atomic primitives like CAS, you're going to have to depend on voluntary synchronization between the two halves. This means side A cannot proceed until side B has acknowledged that side A took the mutex.
Since we know nothing about the shared memory, we cannot assume that write to two seperate regions will be seen in order (some caches will change the order that writes present). We will have to assume that there is some atomic thing, like an int32. We're also going to have to assume that when you say atomic read and write, you never see tearing on the integer, and it's monotonic (if I numbered A's writes, and I've observed #13, I will never again see the #12 value that had been written).
If you do this, then just take one bit (say, the MSB) and use that as an ownership token over the communication used to handle locks. If it's a 1, it means A gets to write. If it's a 0, B gets to write. Whenever A sets it to a new value, the MSB is always 0, and when B sets it to a new value, the MSB is always 1. Now, with nothing but normal reads and writes, we can tell who has the "rights" to the communication channel.
Now the communication channel consists of the lower 31 bits. You can send anything you please across this, including requests to acquire or release a "mutex." If you want to acquire it, you simply have to wait for it to be your turn to read, send a "request mutex" message, and wait for the reply to say "mutex OK"
EDIT: From our chat discussion, it appears what is really needed is a lottery process to select a master thread, who then takes over the job of being the "kernel" that manages the mutual exclusions. All it needs is a way to detect when the master thread died, and elect a new master. This lets us split the problem up into a slow part, which is very robust, and a fast part that works as long as a master is present.