Skip to content

ROM Analysis in Basilisk II Emulation

Ricky Zhang edited this page Aug 25, 2017 · 22 revisions

Table of Contents

Assumptions

The analysis below is based on the study of the Performa old world 32bit clean ROM (with MD5 hash af343f3f1362bf29cefd630687efaa25). I found that this Performa 630 ROM works great for System 7 and Mac OS 8.1.

Disassemble original 68k Mac ROM

Assuming you get a Mac ROM binary file for BII from somewhere, the next step is to poke around it. A ROM file is a collection of data and M68K machine code which performs hardware test at boot time, provides low level common routines such A-Trap and etc.

For emulation purposes, BII patches the original ROM so that it can handle hardware interrupts, A-Trap and etc with emulated devices. I will demonstrate disassembling this Mac ROM with cxmon and radare2.

Disassemble with cxmon

Build cxmon

$ cd macemu/cxmon
$ ./bootstrap
$ ./configure
$ make
$ sudo make install

Use cxmon

The command below disassemble ROM file and dump the text into an external file.

cxmon -m ‘[ 0 “PERFORMA.ROM”’ ‘d68 0 fffff’ > PERFORMA.ROM.DISAM

You can also run cxmon in standalone interactive mode or even enable --with-mon option in BII build to debug at runtime. Please refer to cxmon help

NOTE: After reading the disassemble code, cxmon didn't disassemble correctly in some cases. This is due to the fact that ROM mixed with data and code. For example, read ROM starting from 0x2a offset. The machine code 0x46fc2700 should be at address $0000008c. The correct assembly should be move #?2700, sr, instead of ori.b #$fc,d0 and move.l d0,-(a3).

    11 000000000000002a: 4efa 0060             jmp ($0000008c,pc)
...
    37 000000000000008a: 0000 46fc             ori.b   #$fc,d0
    38 000000000000008e: 2700                  move.l  d0,-(a3)
    39 0000000000000090: 4dfa 000a             lea ($0000009c,pc),a6

Disassemble with radare2

Build radare2

Build radare2 from git repo. You also need to build acr.

Use radare2

The documentation of radare2 is long. TLDR; Here is an example of using it:

[Ricky@xps ROM.Disas]$ radare2 PERFORMA.ROM 
 -- Switch between print modes using the 'p' and 'P' keys in visual mode
[0x00000000]> e asm.arch=m68k
[0x00000000]> pd 10 arch=m68k
            0x00000000      066842140000   addi.w 0x4214, 0x0(a0)
            0x00000006      002a067c4efa   ori.b 0x7c, 0x4efa(a2)
        |   0x0000000c      00804efa007c   ori.l 0x4efa007c, d0
        |   0x00000012      32f10100       move.w (a1, d0.w), (a1)+
        |   0x00000016      00000044       ori.b 0x44, d0
        |   0x0000001a      0007ec10       ori.b 0x10, d7
        |   0x0000001e      4efa1220       jmp 0x1220(pc)
        |   0x00000022      000d2da0       invalid
        |   0x00000026      4efa22e8       jmp 0x22e8(pc)
        |   0x0000002a      4efa0060       jmp 0x60(pc)

NOTE: radare2 has the same issue as cxmon. This is the dead end.

Mac ROM in real Macintosh hardware

In Apple Mac IIci and Mac Quadra 900 Developer Note, it specified ROM in a fixed address space. In fact, ROM machine code is written as position independent code. In reality, its location in memory is relocatable. That’s why BII can load ROM to whatever memory address in guest OS without breaking its logic.

So far I haven’t found an automatic way to disassemble Performa ROM without human tagging code segment. I can’t easily get a full picture of what Performa ROM contains. But reading BII ROM patches, Macintosh ToolBox trap and Macintosh OS trap, I think I need to have basic understanding of using illegal instruction exception technique to extend Macintosh OS.

Illegal Instructions Exception in M68k CPU

M68k CPU suspend execution instruction flow if it encounter an illegal instruction. An illegal instruction is an instruction that contains any bit pattern in its first word that does not correspond to the bit pattern of the first word of a valid M68k instruction or is a MOVEC instruction with an undefined register specification field in the first extension word.

When illegal instruction exception happens, there are four steps in processing exception [1]:

  1. The processor makes an internal copy of the status register. Then the processor sets the S bit, changing to the supervisor privilege level. Next, the processor inhibits tracing of the exception handler by clearing the T1 and T0 bits.
  2. The processor determines the vector number of the exception. In this case, it is 4.
  3. The processor save the current processor context and creates an exception stack frame on the active supervisor stack and fills it with context information appropriate for the type of exception.
  4. The processor multiple the vector number of the exception by 4 to get the offset of vector table. Add the offset with Vector Base Register VBR to get the address of exception handler routine. Then, load Program Counter PC with the look-up address and resume execution.

Macintosh OS reserves the first word 1010 (0xA) unimplemented instruction to implement so called A-Trap to provide ToolBox and OS API.

Basilisk II also uses illegal instruction exception MOVEC to patch Mac ROM and implement its emulated drivers. We will discuss this in next section.

Mac ROM in Basilisk II emulation

Initialization

TODO add more

Patching

After BII loads the ROM from file into memory, it patches the ROM in PatchRom() function from the file src/rom_patches.cpp.

TODO add more

Execution

Emulation starts at relative address 0x2a i.e (MacROMBaseMac + 0x2a) in the patched ROM. TODO add more

Bibliography

1.MC68030 Datasheet