2 poin oleh GN⁺ 2025-01-27 | 1 komentar | Bagikan ke WhatsApp
  • 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

 
GN⁺ 2025-01-27
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

    • CPU palsu yang dipelajari di kelas arsitektur komputer saat kuliah membagi kode instruksi menjadi beberapa field bit, dan bit tertentu menyalakan operasi primitif seperti adder
      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
    • Saya bukan ahli 68k, tetapi tampaknya word pertama saja yang dianggap sebagai kode instruksi, sedangkan word kedua digunakan untuk memilih register D yang dipakai CAS
      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

    • Sebagai penggemar arcade retro dan 68k, saya ingin mendengar lebih banyak tentang bagaimana SNK memaksimalkan 68K hingga batasnya
  • 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

    • Sebagai penulisnya, kalau menemukan hal seperti ini saya cenderung terseret ke analisis mendalam yang cukup besar
      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

    • Koreksi kecil, tetapi 68k tentu saja bukan arsitektur milik Apple
      68030 adalah CPU serbaguna yang cukup bagus pada masanya, dan juga digunakan di Amiga 3000, Atari Falcon, Sun 3, NeXT Cube, dan lainnya
    • Pada masa ketika Mac Classic masih berarti, PC belum begitu hebat di komputasi rumahan, dan belum banyak juga orang di sisi x86/PC yang menggali hal seperti ini
      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

    • Saya merindukan assembly 68000
      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

    • Dari isi tulisannya, saya rasa ini bukan proteksi salin
      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
    • Apple sudah mulai sedikit demi sedikit mencoba planned obsolescence
  • Pada Mac masa kini, hal seperti ini tampaknya mustahil terjadi ke depannya
    Dokumentasi teknis Apple saat ini buruk sekali

    • Menurut saya alasan Apple tidak menyediakan dokumentasi hardware setingkat ini adalah karena Mac modern tidak memiliki kemampuan ekspansi yang setara
      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
    • Dalam lingkungan modern, menurut saya bug seperti ini jauh lebih kecil kemungkinannya masuk ke firmware atau software yang dirilis
      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

    • Pada 040, tampaknya ia benar-benar melakukan sesuatu yang melibatkan D1
      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
    • Saya cek di Amiga dengan 060, dan instruksi ini sepertinya tidak mengubah register A mana pun
      Ini hanya hasil pengujian sangat cepat terhadap word instruksi persis itu