Pulled from x86/
Probably more work to be done, so many changes in the diff