- Mac Classic II hampir menulis ke alamat yang salah akibat bug lompatan keluar rentang di ROM, tetapi CPU Motorola MC68030 asli menjalankan instruksi yang tidak terdokumentasi dan mengubah register A1 sehingga crash terhindari
- Masalah ini terungkap di emulasi Classic II pada MAME saat pengalamatan 32-bit diaktifkan: Sad Mac dan Chimes of Death muncul, sementara pada pengalamatan 24-bit sistem tampak boot normal
- Jalur
InstallSoundIntHandler di ROM menerapkan BoxFlag 17 milik Classic II ke tabel cabang berisi 16 entri, lalu melompat ke 0x40A43B94; lokasi ini sebenarnya berada di tengah instruksi MOVEA.L
- Rangkaian byte
0C EC 08 A9 00 04 mirip dengan CAS D1,D2,$0004(A4), tetapi merupakan instruksi keluarga CAS yang tidak valid dengan bit cadangan yang disetel; pada 68030 asli, instruksi ini mengubah A1 dari FFFF8FBA menjadi 40A4BBB2
- Verifikasi dengan memasang tiga ROM kustom pada Classic II asli menunjukkan bahwa jika instruksi ini dihapus menjadi NOP, perangkat keras juga gagal dengan Sad Mac; hingga perilaku persisnya diketahui, MAME mem-bypass boot dengan patch ROM
Kegagalan boot Classic II yang terungkap di MAME
- MAME dikenal sebagai emulator game arcade, tetapi juga mendukung emulasi model Mac berbasis 68000
- Saat memperbaiki fitur di MAME yang memanggil debugger dengan kombinasi tombol command+power, ditemukan perilaku aneh pada Classic II
- Classic II memiliki tombol interupsi fisik, serta mikrokontroler 68HC05 “Egret” yang menangani keyboard, mouse, dan lainnya
- MacsBug memiliki kode yang mengirim perintah untuk mengaktifkan kombinasi tombol command+power
- Classic II boot normal pada pengalamatan 24-bit, tetapi ketika pengalamatan 32-bit yang dibutuhkan untuk memuat MacsBug diaktifkan, Sad Mac dan Chimes of Death muncul
- Berdasarkan dokumen Apple Tech Info Library, kode Sad Mac
0000000F berarti exception, dan 00000001 berarti bus error
- Pada Mac 68k, bus error biasanya berarti akses ke alamat yang salah, seperti akses ke kartu ekspansi yang tidak ada
Penelusuran ROM: jalur inisialisasi interupsi suara
- Di debugger MAME, breakpoint dipasang pada alamat handler bus error
0x40A026F0, lalu jalur pemanggilan ditelusuri menggunakan peta simbol ROM
- Alamat ini ditandai sebagai
GenExcps pada peta ROM
- Rutin penanganan kesalahan umum ditandai dengan nama
ToDeepShit
- Instruksi yang menyebabkan bus error adalah kode berikut di
0x40A43B9C
move.b #$90, ($1c00,A1)
- Kode ini berada di dalam rutin yang ditandai sebagai
InstallSoundIntHandler pada peta ROM, dan terkait dengan inisialisasi interupsi suara Classic II
- Classic II secara arsitektur lebih mirip keluarga Macintosh LC daripada Macintosh Classic asli, dan menggunakan gate array EAGLE yang mirip dengan chip V8 pada LC
- Inilah alasan nama seperti
V8SndIntPatch1 muncul di dalam kode ROM
- EAGLE mencakup fungsi yang setara dengan versi ringkas Apple Sound Chip (ASC)
Tabel cabang yang salah dan masalah register A1
V8SndIntPatch1 menggunakan selector gestaltHardwareAttr pada Gestalt trap, yaitu 'hdwr', untuk memeriksa atribut perangkat keras
- Jika bit
gestaltHasASC tidak ada, rutin akan kembali
- Pada Classic II,
gestaltHasASC disetel
- Setelah itu, kode membaca nilai
BoxFlag dari 0xCB3 di RAM dan memasukkannya ke D0
- Nilai
BoxFlag pada Classic II adalah 0x11, yaitu 17
- Kode cabang bermasalah menggandakan D0, lalu menggunakannya sebagai offset lompatan relatif terhadap PC
add.w d0,d0
jmp loc_40A43B72(pc,d0.w)
- Karena setiap instruksi
BRA.S berukuran 2 byte, strukturnya menggandakan nilai BoxFlag untuk dipakai sebagai indeks tabel cabang
- Namun tabel sebenarnya hanya memiliki 16 entri untuk BoxFlag 0–15, sehingga nilai 17 milik Classic II keluar dari rentang
- Target lompatan yang dihitung adalah
0x40A43B72 + 0x22 = 0x40A43B94
- Lokasi ini bukan awal instruksi yang dimaksud, melainkan berada di tengah instruksi
MOVEA.L
- Seharusnya
MOVEA.L asli memuat alamat yang benar ke A1, tetapi karena lompatan masuk ke tengah instruksi, A1 mempertahankan nilai 0xFFFF8FBA yang sebelumnya dipakai dalam perhitungan lompatan relatif
- Jika kemudian
move.b #$90, ($1c00,A1) dijalankan, alamat tulis menjadi 0xFFFF8FBA + 0x1C00 = 0xFFFFABBA, yang merupakan alamat tidak valid pada Classic II
Perilaku 68030 yang tidak terdokumentasi
- Rangkaian byte yang dicapai oleh lompatan keluar rentang adalah sebagai berikut
0C EC 08 A9 00 04
- IDA dan GNU objdump tidak dapat men-disassemble instruksi di lokasi ini secara normal
- Saat rangkaian byte yang sama dijalankan di MacsBug pada Macintosh IIci, ia ditampilkan seperti
CAS.W D1,D2,$0004(A4), tetapi setelah dieksekusi nilai A1 berubah
- A1 berubah dari
0xFFFF8FBA menjadi nilai yang tampak seperti alamat RAM
- Nilai A1 yang baru diamati bergantung pada A1, A7, dan program counter asli
- Berdasarkan Motorola M68000 Family Programmer’s Reference Manual, word pertama tampak seperti instruksi CAS, tetapi pada word kedua ada 3 bit yang seharusnya 0 namun disetel menjadi 1
- Jadi instruksi ini bukan CAS terdokumentasi yang valid, melainkan instruksi tidak valid dengan bit cadangan menyala
- 68030 asli tidak memperlakukan instruksi ini sebagai exception illegal instruction, melainkan menjalankan siklus bus read-modify-write terhadap A4+4
- Jika A4 disetel ke alamat yang salah, MacsBug menampilkan bus error saat read-modify-write di A4+4
- A1, yang tidak semestinya berubah pada CAS normal, juga ikut berubah
Verifikasi pada perangkat keras Classic II asli
- Untuk memverifikasi hipotesis, sebuah Classic II produksi tahun 1991 dibeli dan diperbaiki, lalu ROM diganti dengan EEPROM SST29EE010 yang dapat diprogram
- Kapasitor surface-mount pada Mac lama dapat mengalami kebocoran korosif, sehingga dilepas dan diperbaiki sebelum perangkat dinyalakan
- Logic board dijalankan terpisah tanpa CRT dan analog board, lalu tampilan dicek menggunakan konverter VGA berbasis Raspberry Pi Pico
- Kode assembly 68030 untuk menampilkan nilai A1 di layar dimasukkan ke ruang kosong ROM, lalu tiga ROM kustom dibuat
- Custom ROM 1: Mengganti
MOVE.B di 0x40A43B9C yang menyebabkan Sad Mac di MAME dengan kode penampil A1
- Custom ROM 2: Mengganti instruksi mirip CAS di
0x40A43B94, target lompatan keluar rentang, dengan kode penampil A1
- Custom ROM 3: Mengganti instruksi mirip CAS di
0x40A43B94 dengan NOP
- Custom ROM 1 menunjukkan bahwa kode tersebut juga benar-benar dijalankan di perangkat keras asli, dan A1 pada titik crash di MAME adalah
0x40A4BBB2
- Nilai ini adalah alamat ROM sehingga tidak cocok sebagai target tulis, tetapi upaya menulis ke sana tidak memicu bus error
- Custom ROM 2 menunjukkan bahwa tepat sebelum lompatan keluar rentang, A1 bernilai
0xFFFF8FBA, sama seperti yang terlihat di MAME
- Lompatan keluar rentang benar-benar terjadi
- Ini sesuai dengan hipotesis bahwa setelah itu instruksi mirip CAS mengubah A1
- Custom ROM 3 menunjukkan bahwa jika instruksi mirip CAS dihapus, Classic II asli juga gagal dengan Sad Mac
- Dalam pengujian ini, perangkat keras menampilkan Sad Mac yang sama bahkan dalam mode 24-bit
- Fakta bahwa MAME tidak menghasilkan bus error untuk penulisan yang salah dalam mode 24-bit berarti perilakunya lebih permisif daripada perangkat keras asli
Masalah yang tersisa untuk MAME dan emulasi
- Perilaku yang ditemukan adalah contoh instruksi MC68030 yang tidak terdokumentasi yang menjalankan siklus bus read-modify-write dan bahkan mengubah register A1
- Bug pada ROM Classic II tersembunyi berkat perilaku ini, sehingga perangkat asli dapat beroperasi normal
- Potongan kode yang sama juga ditemukan di ROM Macintosh IIvx yang lebih baru, tetapi pada ROM tersebut ukuran tabel lompatan telah diperbesar dan kasus Classic II langsung melompat ke RTS
- Karena perilaku ini, kemungkinan besar saat ini belum ada emulator atau implementasi replika Motorola MC68030 yang 100% sempurna
- Dengan menjalankan instruksi ini dan memeriksa hasil A1, seseorang dapat membuat potongan kode kecil yang membedakan 68030 fisik dari emulator
- Hingga perilaku instruksi yang tepat diketahui, MAME memungkinkan boot dengan menambal bug ROM Classic II
- Secara terpisah, kombinasi tombol command+power berfungsi pada Classic II asli saat MacsBug terpasang, tetapi di MAME masih belum berfungsi
1 komentar
Komentar Hacker News
Perilaku MC68030 yang ditemukan mungkin bukan instruksi “nyata” yang sengaja dibuat oleh perancang CPU, melainkan hasil logika internal CPU yang kebetulan berjalan dengan input don’t-care untuk instruksi ilegal
Biasanya CPU seharusnya mendeteksi instruksi ilegal dan memunculkan exception, tetapi dalam beberapa kasus tampaknya tidak begitu
Di halaman 8-9 https://www.nxp.com/docs/en/reference-manual/MC68030UM.pdf disebutkan bahwa instruksi ilegal didefinisikan berdasarkan pola bit pada “word pertama”
Instruksi kali ini terdiri dari 3 word, word pertamanya valid, dan bit yang aneh ada di word kedua, jadi besar kemungkinan 68030 tidak memvalidasi word kedua dan langsung melanjutkan dengan logika implementasi instruksi CAS
Kode instruksi yang “valid” hanyalah kombinasi yang cukup berguna untuk didokumentasikan, sedangkan kombinasi yang “tidak valid” adalah kombinasi yang tidak berguna atau tidak bermakna
Dilihat seperti ini, opcode ilegal/misterius bukan pengecualian yang mengejutkan, melainkan hampir tak terhindarkan
Biasanya kita akan berharap bit 0 yang tidak bermakna menurut dokumentasi diabaikan sepenuhnya
Namun pada 68030, bit-bit itu mungkin memang harus 0, dan seperti opcode ilegal 6502, jika bit tersebut menyala, logika hardwired untuk instruksi lain bisa ikut aktif
CAS selalu merepotkan, dan mungkin instruksi inilah yang paling banyak mendapat laporan bug emulasi
Di King of Fighters lama juga ada bug yang “keliru” memeriksa carry flag dari instruksi SBCD, lalu dipakai untuk mengurangi timer ronde dan mengakhiri ronde
Walaupun itu perilaku yang tidak terdokumentasi, jika flag status aritmetika pada operasi binary-coded decimal tidak diemulasikan, timer ronde KOF akan terus berputar dari 00 ke 99 dan tidak pernah selesai
SNK benar-benar dewa chip 68000
Benar-benar perjalanan panjang
Sekarang saya tidak punya kesabaran untuk masuk sedalam itu ke lubang kelinci seperti penulisnya, tetapi saya sangat paham rasa pencapaian yang muncul dari perbedaan antara merasa tahu sesuatu dan benar-benar mengetahuinya
Meski memakan banyak waktu, kalau dituntaskan rasanya benar-benar sepadan
Bahkan setelah lebih dari 30 tahun, saya selalu kagum betapa efektifnya UI debugger Mac pada resolusi layar sekecil itu
Benar-benar terasa seperti hasil keahlian seorang pengrajin
Hampir semua CPU memiliki instruksi yang tidak terdokumentasi, dan 68k bukan pengecualian
Hanya saja pada masa itu sebagian besar orang yang punya cukup minat dan pengetahuan level rendah berfokus pada x86/PC, dan x86/PC bisa dibilang arsitektur yang jauh lebih terbuka dan stabil dibanding sisi Apple
Mikrokode 8088 dan 8086 telah didisassemble beberapa tahun lalu dan banyak diteliti, dan setahu saya pernah ada juga upaya simulasi pada level transistor
Struktur ruang opcode x86 juga telah dieksplorasi secara rinci dalam dokumen seperti berikut
http://ref.x86asm.net/geek.html
https://gist.github.com/seanjensengrey/f971c20d05d4d0efc0781...
Belum diketahui persis apa yang dilakukan instruksi ini
Dari pengujian terbatas, nilai hasil A1 tampaknya berubah bergantung pada nilai awal A1, nilai A7, dan program counter, tetapi belum pasti
Jika seseorang membuat program yang mencoba berbagai nilai register dan isi memori untuk menyimpulkan perilakunya secara tepat, emulasinya juga bisa menjadi lebih akurat
Saat ini, sampai ada yang menganggapnya layak digali, MAME mem-patch bug di ROM ini agar Classic II bisa boot
Secara pribadi, menurut saya ini cukup layak diungkap demi emulasi yang akurat
Saya tidak akrab dengan 68k, tetapi bit-bit instruksinya memberi petunjuk. Hipotesisnya, bit 5:3 pada word kedua tampak seperti field mode lain; alih-alih memilih register Dn dengan mode 000, 101 kembali memilih (d16, An), dan field Dc yang berisi 001 tampaknya ditafsirkan sebagai A1
68030 adalah CPU serbaguna yang cukup bagus pada masanya, dan juga digunakan di Amiga 3000, Atari Falcon, Sun 3, NeXT Cube, dan lainnya
Demoscene masih bertahan dengan komputer rumahan 8-bit, sementara orang-orang yang memakai sistem rumahan 16-bit berfokus pada Atari dan Amiga
PC dan x86 baru benar-benar naik di rumah setelah VGA dan sound card masuk ke konfigurasi PC standar
Saat kecil saya punya Amiga 2000 dengan prosesor 68000
Saya sangat bersemangat saat mendengar kabar tentang 68020 atau 68030, lalu kemudian arsitektur RISC juga
Saat Amiga dibuat mengucapkan kalimat seperti “Hello, how are you?” dengan suara robot, teman-teman saya takjub seolah baru pulang dari bulan
Saya tidak pernah membayangkan, dalam waktu kurang dari 40 tahun, kita akan berbicara dengan komputer dalam bahasa alami lewat LLM, dan dengan Python, VS Code, serta LLM sebagai alat, bisa mengotomatisasi hampir apa pun yang diinginkan
Ini benar-benar zaman yang gila
Saya merindukan keluarga 68000
Chip-chip itu benar-benar hebat
Jelas dan logis, sebagaimana seharusnya rekayasa yang baik, sehingga hanya dengan melihat sekilas kita bisa langsung memahami apa yang terjadi
Sebaliknya, assembly x86 kebanyakan terasa seperti tumpukan barang rongsokan murni yang tampak seperti trik cerdik hasil begadang buruk
Mengurangi register dengan dirinya sendiri demi mendapatkan 0 itu benar-benar keterlaluan
Saya penasaran apakah ini proteksi salin agar tidak bisa berjalan di sistem tertentu, atau fenomena yang terjadi pada semua 68030
Entri untuk mesin tersebut tidak ada di jump table yang terkait, dan sepertinya para pengelola ROM lupa menambahkan entri baru, tetapi murni karena kebetulan semuanya tetap berjalan tanpa entri tabel itu
Pada Mac masa kini, hal seperti ini tampaknya mustahil terjadi ke depannya
Dokumentasi teknis Apple saat ini buruk sekali
Tidak lagi mengekspos bus sistem lewat konektor seperti dulu, saat pengguna bisa memasang kartu dan pengembang pihak ketiga harus berinteraksi langsung dengan hardware
Di Mac modern ada USB dan Thunderbolt yang bisa ditangani dari program di ruang pengguna
Tentu saya tidak menyangkal bahwa sebagian dokumentasi API macOS terbaru sangat buruk
Kalau sampai ke halaman lama dengan gradasi biru di header dan tulisan “Apple documentation archive”, Anda tahu Anda sudah menyentuh sesuatu yang keren
Ruang alamat jauh lebih besar dan sebagian besar alamat tidak dipetakan, jadi operasi memori pada alamat sampah biasanya akan gagal, dan instruksi tidak valid pun kemungkinan besar akan gagal
Bug membaca jump table dengan indeks di luar batas itu sendiri masih bisa terjadi di software modern, tetapi prosesnya lebih mungkin mati daripada terus berjalan seperti di sini
Sebagai catatan, WebAssembly memiliki satu ruang alamat linear dan semua alamat bisa dibaca serta ditulis, sehingga bug jenis ini lebih mungkin terjadi
Jika alamat sampah masih berada dalam rentang, program bisa saja melakukan read, write, atau CAS yang keliru lalu tetap lanjut
Namun instruksi tidak valid seperti di artikel utama akan menyebabkan kegagalan pemuatan modul WASM, jadi tidak persis 1:1 dengan masalah pada ROM Mac ini
Saya penasaran apakah 040/060 juga mendukung “instruksi tak terdokumentasi” ini
A1 sama sekali tidak disentuh, dan meski saya belum mengujinya lebih jauh, bisa saja ini hanya diproses sebagai CAS normal
Saat saya pertama kali mengeksekusi instruksi ini langkah demi langkah di MacsBug pada LC 475, terjadi error sistem, tetapi setelah itu baik-baik saja
Ini hanya hasil pengujian sangat cepat terhadap word instruksi persis itu