- SerenityOS selama ini berjalan baik terutama di QEMU, tetapi di laptop nyata hambatan muncul satu per satu mulai dari booting, debugging, hingga akses penyimpanan, sehingga celah dukungan perangkat keras pun terlihat jelas
- Target eksperimennya adalah Dell 3100 Chromebook dengan Intel Celeron N4020, RAM 4GB DDR4, eMMC 32GB, dan layar TN 1366×768, tetapi debugging dalam casing tertutup berbasis Cr50 yang semula diharapkan ternyata gagal pada board ini
- Setelah jalur Cr50 buntu, sebuah Pi Pico berbasis RP2040 dipasang di dalam perangkat dan dihubungkan langsung ke UART serta flash SPI, lalu dengan CircuitPython dan serprog dibuatlah perangkat debugging dan flashing sementara bernama PicoCCD
- Log boot awal sulit diperoleh karena UART MMIO 16550 di balik PCI tidak mudah dipakai secara langsung, sehingga IO port 0x80 yang dicatat oleh ChromeOS EC dimanfaatkan sebagai kanal keluaran sementara yang lambat
- Dukungan eMMC akhirnya mencapai sebagian sesi grafis setelah melewati perbedaan inisialisasi SD/MMC, kontrol daya SDHCI yang hilang, dan penonaktifan perintah khusus SD, tetapi performa, stabilitas, dan perapian patch masih tersisa
Memilih Dell 3100 Chromebook sebagai target perangkat keras nyata
- Saat ingin terlibat lebih dalam dengan SerenityOS, kelemahan pertama yang paling terlihat adalah bahwa ia bisa berjalan di QEMU tetapi dukungan perangkat keras nyata masih kurang
- Dukungan UEFI sudah dikerjakan oleh spholz, jadi tidak disentuh, dan dalam pekerjaan ini cukup jika kernel branch master bisa boot lewat GRUB pada runtime TianoCore UEFI
- Ingin menghindari cara debugging OS pada perangkat yang sama dengan mesin pengembangan utama, dan memilih perangkat keras yang relatif baru agar setidaknya masih layak dipakai sehari-hari
- Setelah mencari Chromebook murah di Allegro, akhirnya membeli Dell 3100 seharga 95PLN, sekitar 25EUR
- Intel Celeron N4020, 2 core, tanpa Hyper-Threading
- DDR4 4GB
- eMMC onboard 32GB
- layar TN 1366×768 yang digerakkan oleh IGP UHD600
- 2x USB-A, 2x USB-C, jack 3,5mm
- keyboard yang terasa lebih baik daripada laptop bisnis kelas atas Dell
- Perangkat ini selanjutnya disebut dengan hostname octopus
Harapan debugging berbasis Cr50 dan kegagalannya
- Alasan besar memilih Chromebook adalah karena chip keamanan Cr50 dan embedded controller-nya menyediakan fitur yang berguna untuk debugging dalam casing tertutup
- Hampir semua Chromebook setelah 2018 bisa memakai satu port USB-C untuk debugging dengan kabel SuzyQ, dan Cr50 biasanya mengekspos tiga perangkat ttyUSB
- konsol Cr50 internal
- konsol AP, yaitu port serial Chromebook
- konsol cros_ec, yaitu embedded controller
- Tujuannya adalah mengakses konsol serial tanpa harus membiarkan kabel menjuntai saat laptop terbuka, dan jika mempertimbangkan emulasi input keyboard serta kontrol status daya dari cros_ec, bentuk KVM sederhana pun tampak mungkin
- Pada octopus yang sebenarnya, Cr50 CCD tidak berfungsi
- Kabel SuzyQ baru dibuat dan hasil solder diverifikasi pada Chromebook lain, tetapi tetap gagal
- octopus ternyata termasuk sedikit laptop di mana Dell tidak memasang sebagian resistor pada board sehingga CCD tidak berfungsi
- Ada yang melaporkan sebagian keberhasilan dalam kondisi arah port tertentu dan charger terhubung, tetapi pada perangkat ini sama sekali tidak berfungsi
- Informasi yang kemudian ditemukan menyebut resistor yang hilang seharusnya hanya memengaruhi flashing SPI, bukan bridge USB itu sendiri, sehingga alasan pasti mengapa debug Cr50 sama sekali tidak bekerja masih belum jelas
PicoCCD yang dibuat dengan Pi Pico
- Setelah jalur Cr50 tertutup, diperiksa apakah board Pi Pico biasa bisa dimasukkan ke ruang kosong di dalam perangkat, dan ternyata muat dengan cukup baik
- Mengacu pada skematik laptop serupa, tetapi tidak ada skematik yang benar-benar cocok dengan octopus
- Satu port debug besar pada board adalah JTAG dan test point terkait Intel, jadi tidak sesuai tujuan
- Yang lain adalah Google Servo, tetapi Google merilis beberapa probe debug dengan nama Servo dan dokumentasinya terbatas, sehingga sulit dicari
- Sebagai rujukan, digunakan dokumentasi Servo
- Dengan menyalakan applet UART milik Glasgow dan deteksi frekuensi, lalu menyelidiki langsung pad UART TX yang dicurigai saat Linux berulang kali mencetak ke
/dev/ttyS1- Pad TX ditemukan dalam beberapa menit
- RX lebih sulit karena memerlukan transmisi aktif dan menyentuh jalur yang salah bisa mereset board, yang memang terjadi dua kali
- Setelah itu, pin RX/TX untuk EC juga ditemukan dalam sekitar 10 menit
- Kabel yang disolder dipasang tetap dengan epoksi curing UV, dan selama 6 bulan tidak ada masalah koneksi
- Periferal SPI pada RP2040 juga dimanfaatkan dengan menyolder 6 kabel ke chip flash, lalu trace menuju pin write-protect dipotong dan dihubungkan ke GND agar akses tulis bisa diperoleh tanpa izin Cr50
- Untuk perangkat lunak dipilih CircuitPython
- karena skrip dan data bisa diunggah lewat perangkat USB mass storage
- pekerjaan menjembatani UART ke perangkat USB
cdc_acmcukup sederhana - karena flash SPI juga terhubung, dibutuhkan pula fungsi flashing
- Sebagai alat flashing EEPROM/SPI open source yang umum dipakai, digunakan flashrom, dan serprog yang mem-proxy SPI lewat UART terasa cocok untuk tujuan ini
- Sudah ada implementasi C pico-serprog dari stacksmashing, tetapi harus mem-flash ulang Pico setiap kali ingin mem-flash BIOS, dan itu tidak cocok
- Sebagai gantinya, serprog diimplementasikan dengan CircuitPython dan banyak merujuk pada applet serprog Glasgow
- Kode hasilnya dirapikan menjadi solusi debugging dalam casing tertutup yang dibuat cepat, yaitu PicoCCD, dan repositorinya ada di PicoCCD di Forgejo
- WeirdTreeThing juga menulis kode C RP2040 dengan tujuan serupa, dan ada pula versi PicoCCD miliknya
Mendapatkan log boot SerenityOS
- Alpine Linux dipasang untuk keperluan debugging, lalu disiapkan utilitas dasar untuk membawa kernel SerenityOS yang dibangun dari luar
- Setelah itu strukturnya berkembang hingga memiliki pengunduhan artefak otomatis dari mesin build, menimpa kernel setelah dekompresi, dan entri GRUB yang mengekstrak
.tarruang pengguna - Waktu iterasi sampai pengujian setelah perubahan pada saat penulisan sekitar 20 detik, yang cukup baik untuk ukuran hacking bare metal
- Entri boot GRUB pertama pada dasarnya adalah
multiboot /Kernel serial_debug, tetapi tidak ada keluaran baik di layar maupun port serial - Untuk masalah keluaran layar, ditemukan bahwa menambahkan
insmod all_videoke entri boot GRUB adalah arah yang benar; itu belum menyelesaikan semuanya, tetapi membantu - Tidak adanya keluaran serial adalah masalah yang lebih besar
- Log coreboot masih masuk sampai beberapa detik sebelumnya
- UART pada perangkat ini bukan 16550 port-mapped tradisional, melainkan 16550A berbasis MMIO
- Log Linux menunjukkan
ttyS0danttyS1sebagai 16550A pada alamat MMIO - Pada
lspci, perangkat itu terlihat sebagai PCI device Intel Celeron/Pentium Silver Processor Serial IO UART Host Controller
Solusi sementara 16550 UART dan port 0x80
- Secara tradisional, perangkat eksternal pada IBM PC dipetakan ke port I/O x86 dan diakses dengan instruksi seperti
outbdaninb - Banyak perangkat kemudian berpindah ke MMIO, tetapi port serial tetap mempertahankan cara lama karena kompetisi kecepatan tinggi tidak penting, sehingga berguna sebagai port debug
- Dalam lingkungan umum, menulis sesuatu seperti
outb 0x3f8, 0x41akan membuat sisi lain menerimaA, dan inisialisasinya juga singkat sehingga mudah diimplementasikan dalam proyek kecil - UART milik octopus adalah perangkat MMIO di balik PCI, dan pada tahap sangat awal boot SerenityOS sulit berharap PCI sudah diinisialisasi
- SerenityOS memang memiliki implementasi bus PCI, tetapi tahap boot-nya terlalu dini
PCISerialDeviceyang ada juga belum pernah dipakai dalam konteks MMIO- Membuat driver ini tanpa keluaran debug jelas bukan situasi ideal
- Embedded controller pada perangkat ChromeOS mencatat semua penulisan ke IO port 0x80
- Port ini secara tradisional dipakai untuk melaporkan status POST
- Indikator kode boot 7-segmen pada motherboard bekerja dengan mendekode port 80
- Hipotesis ini diuji dengan skrip yang menulis byte ke
/dev/portdi Linux, dan byte tersebut bisa dibaca pada konsol cros_ec - Dengan menaruh kode seperti
IO::out8(0x80, 1);di sekitar titik awal SerenityOS yaituKernel/Arch/init.cpp, lokasi kemajuan bisa dilacak hingga menyempit ke titik crash diMemory::MemoryManager::initialize(0); - Setelah itu dicoba pendekatan mengubah alamat rutinitas tulis serial dari 0x3f8 menjadi 0x80
- Awalnya banyak byte keluar, tetapi cros_ec tidak mampu me-relay-nya secara stabil sehingga terjadi overflow
- Lebih jauh lagi, keluaran log cros_ec sendiri juga ikut rusak
- Tidak seperti chip serial sungguhan, ia tidak memiliki buffer besar
- Ini diakali dengan menyisipkan banyak keadaan tunggu berbasis
nopdi antara setiap penulisan- Jika semua pesan boot dicetak, waktu boot yang tadinya beberapa detik menjadi beberapa menit
- Meski begitu, biaya ini masih dianggap bisa diterima untuk debugging bare metal
- Untuk mem-parsing otomatis baris log cros_ec dan mendekodenya ke ASCII, digunakan one-liner Bash yang menggabungkan
picocom,watch,grep,sed,cut, danxxd
Framebuffer dan keluaran grafis pertama
- Setelah mendapatkan log boot, selama beberapa hari masalahnya dicoba dipahami dengan membaca codebase langsung, tetapi akhirnya bantuan komunitas diminta
- spholz memberi tahu tentang SerenityOS PR #24435 yang saat itu sedang terbuka, dan ketika dibangun dengan branch itu, generic framebuffer pun bekerja
- Di layar muncul hasil yang terlihat seperti berhasil padahal pekerjaannya sebenarnya gagal, dan setelah itu masalah penyimpanan mulai tampak serius
eMMC dan masalah inisialisasi SD/MMC
- Crash StorageManagement yang ada berujung pada assertion bahwa daftar controller kosong setelah inisialisasi SD Host Controller gagal
- Dalam log terlihat
PCI: Failed to initialize SD Host ControllerdanASSERTION FAILED: !m_controllers.is_empty() - Akibatnya kernel panic terjadi di
StorageManagement::enumerate_storage_devices()
- Dalam log terlihat
- octopus memiliki chip eMMC 32GB, dan karena SerenityOS sudah punya sebagian driver SD, tampaknya menambahkan dukungan MMC seharusnya cukup
- Untuk menggunakan kartu SD/MMC, pada dasarnya dibutuhkan tiga komponen besar
- Host Controller: pada perangkat modern biasanya SDHCI sesuai spesifikasi SD Association
- Bus yang menghubungkan ke Host Controller: dalam kasus ini PCI
- Implementasi protokol komunikasi antara host dan kartu
- Berdasarkan log crash, SerenityOS sudah memiliki dua komponen pertama, jadi masalah yang tersisa ada di sisi protokol
- Protokol SD memiliki spesifikasi terbuka, tetapi MMC menjadi standar JEDEC pada 2007 dan akses resminya sejak itu berbayar
- SD dan MMC memiliki urutan inisialisasi yang berbeda
- SerenityOS memulai dengan mengirim CMD0 dan menunggu respons, dan ini seharusnya lolos baik pada SD maupun MMC
- Setelah itu ia mengirim CMD8 untuk mengatur tegangan, tetapi MMC tidak mendukungnya sehingga seharusnya terjadi error
- Beberapa referensi menyarankan setelah itu kartu di-reset lagi dan dianggap sebagai MMC
- Referensi lain menunjukkan alur yang lebih menyeluruh dengan kombinasi hasil CMD8 dan CMD58 untuk membedakan versi SD dan tipe kapasitas juga
- Semua pemeriksaan kompatibilitas tingkat lanjut tidak diimplementasikan; hanya pemeriksaan dasar yang dibuat
Register kontrol daya yang hilang dan perbaikannya
- Secara ringkas, alur inisialisasi MMC saat itu terdiri dari langkah-langkah berikut
- setelah reset, setel clock ke 400KHz
- tunggu 1ms lalu tunggu 74 clock lagi
- kirim CMD0 dan tunggu respons
- ulangi CMD1 sampai bit ke-31 pada respons bernilai 1
- setelah loop selesai, simpan nilainya ke register Operating Conditions
- lanjutkan algoritme inisialisasi SD dengan melewati pembacaan register khusus SD
- secara opsional deteksi kompatibilitas High-Speed dan aktifkan salah satu dari beberapa mode HS
- Kode berhasil mencapai sekitar langkah 4, tetapi setelah itu eMMC tidak lagi merespons permintaan apa pun
- Setelah beberapa hari tidak menemukan penyebabnya, eMMC mulai merespons ketika kode terkait reset controller dihapus, sehingga masalahnya menyempit ke fungsi
reset_host_controller() - Keanehan fungsi itu adalah bahwa register
host_configurationtidak ditemukan dalam standar- Kode sebelumnya rupanya telah mengelompokkan beberapa register secara sewenang-wenang menjadi dua grup
host_configuration - Inisialisasinya juga belum sepenuhnya selesai, dan grup pertama hanya disetel ke 0 begitu saja
- Kode sebelumnya rupanya telah mengelompokkan beberapa register secara sewenang-wenang menjadi dua grup
- Di dalam grup pertama itu ternyata terdapat register Power Control yang mengendalikan regulator daya kartu
- Pada sebagian perangkat keras, termasuk semua implementasi yang menggunakan eMMC, register ini diperlukan untuk benar-benar menyalakan kartu
- Pada desain lain yang menghubungkan rel daya langsung ke slot, pengaturan ini bisa diabaikan
- Sebagai solusi sementara, nilai asli yang seharusnya ada pada
host_configuration_0diambil dan digunakan - Inti masalahnya adalah upaya berkomunikasi dengan kartu saat dayanya bahkan belum dinyalakan
- Setelah itu butuh beberapa jam lagi untuk menemukan dan menonaktifkan perintah tertentu yang hanya valid untuk kartu SD, dan ketika keluaran debug dari controller menjadi lebih bermakna, sisa pekerjaannya berjalan relatif biasa
Status saat ini dan pekerjaan yang tersisa
- Pada akhirnya SerenityOS berhasil menampilkan sesi grafis yang sangat lambat dan sebagian rusak, tetapi segera hang
- Masalah sesi grafis ini dan proses mengembalikan framebuffer ke kondisi normal akan dibahas dalam tulisan lanjutan
- Seluruh pekerjaan ini merupakan proses belajar selama sekitar 6 bulan, dan di sela-selanya ada pekerjaan lain juga
- Target berikutnya adalah merapikan patch dan mengirimkannya ke upstream tahun ini
1 komentar
Opini Hacker News
Saya pernah membaca bahwa menyesuaikan driver NetBSD untuk kernel kustom relatif mudah, jadi mungkin Serenity juga bisa menempuh jalan seperti itu
Bagi OS baru, driver perangkat adalah hambatan besar
Karena konfigurasi perangkat kerasnya hampir tetap, membuat atau mengambil driver serta menguji sistem jadi lebih mudah
Driver bisa dijalankan di user space dengan dukungan dasar yang minimal
https://en.wikipedia.org/wiki/Rump_kernel
Namun untuk sisi driver, saya kurang tahu
Sejauh yang terlihat, inilah kurang lebih cara yang sejak awal dilakukan Apple, dan ini satu-satunya contoh besar yang sukses di keluarga Unix untuk konsumen
System76 juga hampir seperti itu, dan Frame.work juga mirip, tetapi kurang berfokus pada OS itu sendiri
Membuatnya berjalan di mesin yang semua kondisinya tidak menguntungkan adalah pekerjaan hacking yang benar-benar hebat, dan tampak sebagai hasil dari upaya luar biasa orang-orang berbakat
Membaca tulisan seperti ini membuat saya penasaran bagaimana cara mulai masuk ke dunia driver dan OS
Kelihatannya terlalu rumit, jadi saya tidak begitu tahu harus mulai dari mana
Ini disebut memory-mapped I/O (MMIO). Di aplikasi biasa hal ini tidak bisa dilakukan karena kernel mencegah akses langsung ke memori perangkat keras
Untuk memulai, Anda butuh bahasa seperti Rust/C++/C/Zig yang bisa menghasilkan machine code untuk CPU target, dan sebaiknya tanpa runtime atau GC. Kalau baru pertama kali memakai bahasa level rendah, saya menyarankan C karena contohnya banyak
Anda juga perlu mempelajari assembly dasar untuk CPU target, dan beberapa instruksi mungkin tidak tersedia sebagai fungsi bawaan di bahasa level tinggi
Setelah itu, dengan menulis kernel hello world, Anda akan mempelajari bagaimana CPU memulai kernel, serta bagaimana mode eksekusi dan tingkat privilege dibagi
Berikutnya, di x86 misalnya, Anda mengatur CPU sesuai keinginan, seperti beralih ke long mode untuk memakai instruksi 64-bit, dan biasanya di tahap ini juga mengatur virtual memory
Sampai di sini, Anda akan mulai memahami bagaimana CPU berinteraksi dengan OS, cara mengenumerasi perangkat yang tersedia dan menemukan lokasi memori, lalu masih banyak pekerjaan seperti file system dan scheduler
Perbedaan antara perangkat lunak yang berjalan di atas OS dan kernel OS pada akhirnya adalah mode CPU yang sedang menjalankan kode tersebut, dan pada privilege tertinggi Anda bisa memakai instruksi yang tidak bisa digunakan aplikasi biasa
Belakangan saya menemukan materi seperti harta karun yang tersembunyi di dokumentasi FreeBSD, dan di antaranya FreeBSD Architecture Handbook serta FreeBSD Developers' Handbook bisa sangat membantu
https://lwn.net/Kernel/LDD3/
https://docs.freebsd.org/en/books/
Minix ditulis dengan sangat rapi, kernelnya juga sekitar 5 ribu baris, dan dibahas di banyak buku ajar
Saya mengimplementasikan server sederhana dan juga mencoba hacking kernel; karena Minix adalah microkernel, sebagian besar driver bekerja dengan cara seperti itu
Saya membaca materi kuliah terlebih dahulu dan hampir tidak mengikuti kuliahnya, tetapi tetap mendapat nilai 8 dari 10
Saya juga mendengar banyak hal baik tentang NetBSD dan SerenityOS, dan Andreas melakukan banyak pengembangan lewat live streaming
Kalau tahu harus mulai dari mana, sebenarnya jadi mudah
Misalnya, driver perangkat berperan mengekspos antarmuka agar program lain yang berjalan di komputer bisa mengakses dan mengendalikan suatu perangkat
https://m.youtube.com/watch?v=juGNPLdjLH4 adalah kuliah kilat yang lumayan
Anda juga bisa membuat perangkat USB sederhana dengan Arduino atau semacamnya untuk bertukar informasi dengan PC. Contoh: https://m.youtube.com/watch?v=yTc2GLXfCOY
Setelah itu, pahami apa yang dilakukan subsistem yang Anda minati dan bagaimana menjalankannya, lalu tulis kodenya. Perangkat penyimpanan, perangkat grafis, dan sebagainya termasuk di sini
Raspberry Pi juga bisa menjadi titik awal yang baik untuk eksperimen semacam ini. Contoh: Writing a bare metal operating system for the raspberry pi https://github.com/babbleberry/rpi4-osdev
https://wiki.osdev.org/Bare_Bones
Saya suka konsep SerenityOS dan browser Ladybird, jadi senang melihat kemajuan seperti ini
Ladybird bukan hanya menjadi proyek independen, tetapi juga tidak lagi melihat SerenityOS sebagai platform target
Ladybird sedang semakin banyak melepas lapisan Serenity miliknya sendiri dan menggantinya dengan alternatif yang lebih arus utama
Sebagai pengguna yang terutama memakai Linux, saya menantikan Ladybird menjadi alternatif nyata di Linux
Namun sebagai penggemar SerenityOS, sayang rasanya energi dan inovasi yang masuk ke Ladybird keluar dari SerenityOS
Jika butuh bantuan untuk hacking Chromebook, tanyakan saja di milis chromium-os-dev
Sepertinya ada yang bisa membantu membuat CCD berfungsi
https://groups.google.com/a/chromium.org/g/chromium-os-dev?p...
Bootloader Depthcharge juga mendukung boot jaringan lewat TFTP
Memang harus dibangun sendiri dan di-flash ke SPI, tetapi ini fitur yang sangat bagus saat mengembangkan kernel secara iteratif
https://chromium.googlesource.com/chromiumos/platform/depthc...
Saya kira SerenityOS sudah pernah berjalan di perangkat keras nyata; apakah sejauh ini masih semuanya hanya berjalan di dalam QEMU?
Namun hampir tidak ada driver yang layak disebut, jadi hanya berjalan dalam arti paling dasar, hanya mungkin di perangkat keras tertentu, dan mungkin tidak berjalan terlalu baik
Upaya kali ini bertujuan membuatnya berjalan dengan andal setidaknya di satu platform perangkat keras nyata
Serenity tetap mengesankan, meski kadang saya tidak setuju dengan cara implementasinya
Saya datang untuk melihat hal menyeramkan seperti ini
doas dd seek=$((0x$1)) bs=1 count=1 of=/dev/port < <(xxd -p -r <<< "$2")