- SerenityOS ทำงานได้ดีเป็นหลักบน QEMU แต่เมื่ออยู่บนแล็ปท็อปจริงก็เริ่มติดขัดทีละจุดตั้งแต่การบูต การดีบัก ไปจนถึงการเข้าถึงสตอเรจ ทำให้เห็นช่องว่างของการรองรับฮาร์ดแวร์
- เครื่องทดลองคือ Dell 3100 Chromebook ที่มี Intel Celeron N4020, DDR4 4GB, eMMC 32GB และหน้าจอ TN 1366×768 โดยการดีบักแบบปิดฝาเครื่องผ่าน Cr50 ที่คาดหวังไว้ล้มเหลวบนบอร์ดนี้
- เมื่อเส้นทาง Cr50 ใช้ไม่ได้ จึงใส่ Pi Pico ที่ใช้ RP2040 เข้าไปภายในเครื่อง แล้วต่อกับ UART และ SPI flash โดยตรง สร้างอุปกรณ์ดีบักและแฟลชชั่วคราวชื่อ PicoCCD ด้วย CircuitPython และ serprog
- ล็อกบูตช่วงแรกเข้าถึง MMIO 16550 UART ที่อยู่หลัง PCI ได้ยาก จึงใช้ IO port 0x80 ที่ ChromeOS EC บันทึกไว้เป็นช่องทางเอาต์พุตชั่วคราวที่ช้าเพื่อเก็บล็อก
- การรองรับ eMMC ผ่านปัญหาความต่างของการเริ่มต้น SD/MMC, การขาดการควบคุมพลังงาน SDHCI และการปิดใช้คำสั่งเฉพาะ SD จนไปถึงกราฟิกเซสชันบางส่วนได้แล้ว แต่ยังเหลืองานด้านประสิทธิภาพ เสถียรภาพ และการจัดระเบียบแพตช์
Dell 3100 Chromebook ที่เลือกเป็นฮาร์ดแวร์จริงเป้าหมาย
- ระหว่างพยายามมีส่วนร่วมกับ SerenityOS ให้ลึกขึ้น จุดอ่อนแรกที่เห็นชัดคือ มันรันได้บน QEMU แต่การรองรับฮาร์ดแวร์จริงยังไม่พอ
- การรองรับ UEFI กำลังถูก spholz ดำเนินการอยู่แล้วจึงไม่ได้แตะ และสำหรับงานนี้เพียงให้เคอร์เนลจากบรานช์ master บูตด้วย GRUB บนรันไทม์ TianoCore UEFI ได้ก็เพียงพอ
- ไม่อยากดีบัก OS บนเครื่องเดียวกับเครื่องพัฒนาหลัก และเลือกฮาร์ดแวร์ที่ค่อนข้างใหม่พอให้ใช้งานจริงทุกวันได้
- ระหว่างหา Chromebook ราคาถูกบน Allegro ก็ซื้อ Dell 3100 มาในราคา 95PLN หรือประมาณ 25EUR
- Intel Celeron N4020, 2 คอร์, ไม่มี Hyper-Threading
- DDR4 4GB
- eMMC ออนบอร์ด 32GB
- หน้าจอ TN 1366×768 ที่ขับด้วย UHD600 IGP
- USB-A 2 พอร์ต, USB-C 2 พอร์ต, แจ็ก 3.5mm
- คีย์บอร์ดที่รู้สึกว่าดีกว่าแล็ปท็อปธุรกิจรุ่นสูงของ Dell
- ต่อจากนี้เครื่องนี้ถูกเรียกด้วย hostname ว่า octopus
ความคาดหวังและความล้มเหลวของการดีบักผ่าน Cr50
- เหตุผลใหญ่ที่เลือก Chromebook คือชิปความปลอดภัย/embedded controller Cr50 มีฟีเจอร์ที่มีประโยชน์สำหรับการดีบักแบบปิดฝาเครื่อง
- Chromebook แทบทั้งหมดหลังปี 2018 สามารถใช้พอร์ต USB-C หนึ่งพอร์ตเพื่อดีบักผ่านสาย SuzyQ ได้ และโดยทั่วไป Cr50 จะเผยอุปกรณ์ ttyUSB สามตัว
- คอนโซล Cr50 ภายใน
- คอนโซล AP หรือพอร์ต serial ของ Chromebook
- คอนโซล cros_ec หรือ embedded controller
- เป้าหมายคือเข้าถึง serial console โดยไม่ต้องเปิดแล็ปท็อปทิ้งไว้พร้อมสายห้อยออกมา และเมื่อรวมการจำลองอินพุตคีย์กับการควบคุมสถานะพลังงานของ cros_ec ก็ดูเหมือนจะทำรูปแบบ KVM แบบง่ายได้
- แต่บน octopus จริง Cr50 CCD ไม่ทำงาน
- ทำสาย SuzyQ เส้นใหม่และตรวจสอบงานบัดกรีด้วย Chromebook เครื่องอื่นแล้วแต่ก็ยังล้มเหลว
- octopus เป็นหนึ่งในแล็ปท็อปจำนวนน้อยที่ CCD ไม่ทำงานเพราะ Dell ไม่ใส่ตัวต้านทานบางตัวบนบอร์ด
- บางคนบอกว่าทำสำเร็จแบบจำกัดภายใต้เงื่อนไขทิศทางพอร์ตและการต่อเครื่องชาร์จบางอย่าง แต่บนเครื่องนี้ไม่ทำงานเลย
- ข้อมูลที่ตรวจสอบภายหลังยังบอกด้วยว่าตัวต้านทานที่ขาดไปควรมีผลเฉพาะกับการแฟลช SPI ไม่ใช่ตัว USB bridge เอง ดังนั้นเหตุผลที่ Cr50 debug ไม่ทำงานเลยยังไม่ชัดเจน
PicoCCD ที่ทำด้วย Pi Pico
- หลังเส้นทาง Cr50 ใช้ไม่ได้ ก็ตรวจดูว่าสามารถใส่บอร์ด Pi Pico ธรรมดาเข้าไปในพื้นที่ว่างภายในเครื่องได้หรือไม่ และพบว่ามีพื้นที่พอ
- อ้างอิงผังวงจรของแล็ปท็อปที่คล้ายกัน แต่ไม่มีผังวงจรที่ตรงกับ octopus พอดี
- พอร์ตดีบักขนาดใหญ่บนบอร์ดอันหนึ่งเป็น JTAG และ test point ที่เกี่ยวกับ Intel จึงไม่ตรงวัตถุประสงค์
- อีกอันคือ Google Servo แต่ Google ออก debug probe หลายตัวภายใต้ชื่อ Servo และเอกสารก็จำกัด จึงค้นหายาก
- ใช้ เอกสาร Servo เป็นเอกสารอ้างอิงที่เกี่ยวข้อง
- เปิด UART applet และการตรวจจับความถี่ของ Glasgow แล้วใช้ probe แตะ pad UART TX ที่น่าสงสัยโดยตรง ระหว่างที่ Linux ส่งเอาต์พุตซ้ำไปยัง
/dev/ttyS1- พบ pad TX ภายในไม่กี่นาที
- RX ยากกว่าเพราะต้องส่งสัญญาณแบบ active และถ้าแตะสายผิดบอร์ดอาจรีเซ็ตได้ ซึ่งเกิดรีเซ็ตจริงสองครั้ง
- ต่อมาพบขา RX/TX สำหรับ EC ได้ในราว 10 นาที
- สายที่บัดกรีไว้ถูกยึดด้วยอีพ็อกซีแบบ UV cure และตลอด 6 เดือนไม่มีปัญหาการเชื่อมต่อ
- ใช้ SPI peripheral ของ RP2040 ด้วย โดยบัดกรีสาย 6 เส้นเข้ากับชิป flash และตัด trace ที่ไปยังขา write-protect แล้วต่อเข้ากับ GND เพื่อให้ได้สิทธิ์เขียนโดยไม่ต้องขออนุญาตจาก Cr50
- เลือกใช้ CircuitPython เป็นซอฟต์แวร์
- เพราะสามารถอัปโหลดสคริปต์และข้อมูลผ่าน USB mass storage ได้
- งาน bridge UART เป็นอุปกรณ์ USB
cdc_acmทำได้ง่าย - เนื่องจากต่อ SPI flash ด้วย จึงต้องมีฟังก์ชันแฟลชด้วย
- ใช้ flashrom เป็นเครื่องมือโอเพนซอร์สทั่วไปสำหรับแฟลช EEPROM/SPI และ serprog ที่ proxy SPI ผ่าน UART ก็เหมาะกับเป้าหมาย
- มี implementation ภาษา C อย่าง pico-serprog ของ stacksmashing อยู่แล้ว แต่ไม่เข้ากับการต้องแฟลช Pico ใหม่ทุกครั้งที่จะแฟลช BIOS
- จึง implement serprog ด้วย CircuitPython แทน และอ้างอิง Glasgow serprog applet เป็นอย่างมาก
- โค้ดผลลัพธ์ถูกจัดเป็นโซลูชันดีบักแบบปิดฝาเครื่องที่ทำอย่างรวดเร็วชื่อ PicoCCD และรีโพซิทอรีอยู่ที่ PicoCCD บน Forgejo
- WeirdTreeThing ก็เขียนโค้ด RP2040 ภาษา C สำหรับจุดประสงค์คล้ายกัน และมี เวอร์ชัน PicoCCD ของเขา ด้วย
การเก็บล็อกบูตของ SerenityOS
- ติดตั้ง Alpine Linux สำหรับดีบัก และจัดชุดยูทิลิตีพื้นฐานเพื่อนำเคอร์เนล SerenityOS ที่ build จากภายนอกเข้ามา
- ต่อมาโครงสร้างขยายเป็นการดาวน์โหลด artifact อัตโนมัติจากเครื่อง build, แตกไฟล์เคอร์เนลแล้วเขียนทับ และมี GRUB entry ที่แตก
.tarของ user space - รอบเวลาตั้งแต่แก้ไขจนทดสอบ ณ เวลาที่เขียนอยู่ที่ประมาณ 20 วินาที ซึ่งถือว่าค่อนข้างดีสำหรับการแฮ็กแบบ bare-metal
- รายการบูต GRUB แรกแทบจะเป็น
multiboot /Kernel serial_debugแต่ทั้งหน้าจอและพอร์ต serial ไม่มีเอาต์พุตใด ๆ - สำหรับปัญหาเอาต์พุตหน้าจอ พบวิธีเพิ่ม
insmod all_videoลงในรายการบูต GRUB แม้เพียงเท่านี้ยังไม่แก้ปัญหา แต่เป็นทิศทางที่ถูก - การไม่มีเอาต์พุต serial เป็นปัญหาใหญ่กว่า
- ล็อก coreboot ยังเข้ามาจนถึงไม่กี่วินาทีก่อนหน้า
- UART ของเครื่องนี้ไม่ใช่ 16550 แบบ port-mapped ดั้งเดิม แต่เป็น 16550A แบบ MMIO
- ในล็อก Linux แสดง
ttyS0และttyS1เป็น 16550A ที่อยู่บนแอดเดรส MMIO - ใน
lspciเห็น Intel Celeron/Pentium Silver Processor Serial IO UART Host Controller เป็นอุปกรณ์ PCI
16550 UART และทางเลี่ยงผ่าน port 0x80
- ตามธรรมเนียม อุปกรณ์ภายนอกของ IBM PC ถูกแมปเข้ากับ port I/O ของ CPU x86 และเข้าถึงด้วยคำสั่งอย่าง
outbและinb - ต่อมาอุปกรณ์จำนวนมากย้ายไป MMIO แต่ serial port ไม่ต้องแข่งด้านความเร็วสูง จึงยังคงวิธีเก่าไว้และมีประโยชน์ในฐานะ debug port
- ในสภาพแวดล้อมทั่วไป ถ้าเขียนประมาณ
outb 0x3f8, 0x41ฝั่งตรงข้ามก็จะรับAได้ และการ initialize ก็สั้น ทำให้ง่ายต่อการ implement ในโปรเจกต์เล็ก ๆ - UART ของ octopus เป็นอุปกรณ์ MMIO ที่อยู่หลัง PCI และในช่วงต้นของการบูต SerenityOS การคาดหวังให้ PCI initialize แล้วเป็นเรื่องยาก
- SerenityOS มี implementation ของ PCI bus แต่เป็นช่วงที่เร็วเกินไปในขั้นตอนบูต
PCISerialDeviceเดิมก็ไม่เคยถูกใช้ในบริบท MMIO- การทำไดรเวอร์นี้โดยไม่มี debug output ไม่ใช่สถานการณ์ที่เหมาะ
- embedded controller ของอุปกรณ์ ChromeOS จะบันทึกการเขียนทั้งหมดไปยัง IO port 0x80 เป็นล็อก
- port นี้ถูกใช้ตามธรรมเนียมสำหรับรายงานสถานะ POST
- ตัวแสดง boot code แบบ 7-segment บนเมนบอร์ดทำงานโดย decode port 80
- ทดสอบสมมติฐานด้วยสคริปต์ที่เขียน byte ไปยัง
/dev/portบน Linux และสามารถอ่าน byte ดังกล่าวจากคอนโซล cros_ec ได้ - ใส่โค้ดอย่าง
IO::out8(0x80, 1);รอบ ๆKernel/Arch/init.cppซึ่งเป็นจุดเริ่มของ SerenityOS เพื่อติดตามตำแหน่งการทำงาน และจำกัดตำแหน่งที่ crash ได้ถึงMemory::MemoryManager::initialize(0); - จากนั้นลองเปลี่ยนแอดเดรสของรูทีนเขียน serial จาก 0x3f8 เป็น 0x80
- ตอนแรกมี byte ออกมาจำนวนมาก แต่ cros_ec relay ได้ไม่เสถียรและเกิด overflow
- ถัดไปอีก เอาต์พุตล็อกของ cros_ec เองก็เสียหาย
- เพราะต่างจากชิป serial จริง มันไม่มี buffer ขนาดใหญ่
- เลี่ยงปัญหาด้วยการแทรก wait state ที่อิง
nopจำนวนมากระหว่างการเขียนแต่ละครั้ง- ถ้าพิมพ์ข้อความบูตทั้งหมด การบูตที่เคยใช้ไม่กี่วินาทีกลายเป็นหลายนาที
- ถึงอย่างนั้นก็ถือเป็นต้นทุนที่ยอมรับได้สำหรับการดีบัก bare-metal
- ใช้คำสั่ง Bash หนึ่งบรรทัดที่ผสม
picocom,watch,grep,sed,cut,xxdเพื่อ parse บรรทัดล็อก cros_ec อัตโนมัติและ decode เป็น ASCII
Framebuffer และเอาต์พุตกราฟิกครั้งแรก
- หลังเก็บล็อกบูตได้แล้ว ใช้เวลาหลายวันอ่าน codebase เองเพื่อทำความเข้าใจปัญหา แต่สุดท้ายก็ขอความช่วยเหลือจากชุมชน
- spholz แจ้งเกี่ยวกับ SerenityOS PR #24435 ที่เปิดอยู่ในตอนนั้น และเมื่อ build ด้วยบรานช์ดังกล่าว generic framebuffer ก็ทำงาน
- บนหน้าจอปรากฏผลลัพธ์ที่งานล้มเหลวแต่ดูเหมือนสำเร็จ และหลังจากนั้นปัญหา storage ก็เริ่มเผยออกมาอย่างจริงจัง
eMMC และปัญหาการเริ่มต้น SD/MMC
- crash ของ StorageManagement เดิมตามมาจาก assertion ว่ารายการ controller ว่าง หลังการ initialize SD Host Controller ล้มเหลว
- ในล็อกเห็น
PCI: Failed to initialize SD Host ControllerและASSERTION FAILED: !m_controllers.is_empty() - ส่งผลให้เกิด kernel panic ใน
StorageManagement::enumerate_storage_devices()
- ในล็อกเห็น
- octopus มีชิป eMMC 32GB และ SerenityOS มีไดรเวอร์ SD อยู่บางส่วนแล้ว จึงดูเหมือนแค่เพิ่มการรองรับ MMC ก็พอ
- การใช้การ์ด SD/MMC ต้องมีองค์ประกอบหลักสามอย่าง
- Host Controller: ในเครื่องสมัยใหม่โดยปกติคือ SDHCI ตามสเปกของ SD Association
- บัสที่เชื่อมกับ Host Controller: ในกรณีนี้คือ PCI
- implementation ของโปรโตคอลที่ Host และการ์ดใช้สื่อสารกัน
- จากล็อก crash ดูเหมือน SerenityOS มีสององค์ประกอบแรกแล้ว และปัญหาที่เหลืออยู่ฝั่งโปรโตคอล
- โปรโตคอล SD มีสเปกสาธารณะ แต่ MMC หลังกลายเป็นมาตรฐาน JEDEC ในปี 2007 แล้วการเข้าถึงอย่างเป็นทางการต้องเสียค่าใช้จ่าย
- SD และ MMC มีลำดับ initialize ต่างกัน
- SerenityOS เริ่มด้วยการส่ง CMD0 แล้วรอ response ซึ่งทั้ง SD และ MMC ควรผ่าน
- ถัดไปส่ง CMD8 เพื่อตั้งค่าแรงดัน แต่ MMC ไม่รองรับจึงควรเกิด error
- แหล่งข้อมูลบางแห่งเสนอให้ reset การ์ดหลังจากนั้นและถือว่าเป็น MMC
- แหล่งข้อมูลอื่นเสนอ flow ที่ครอบคลุมกว่า โดยใช้ผลลัพธ์จาก CMD8 และ CMD58 ร่วมกันเพื่อแยกทั้งเวอร์ชัน SD และประเภทความจุ
- ไม่ได้ implement การตรวจสอบความเข้ากันได้ขั้นสูงทั้งหมด ทำเพียงการตรวจสอบพื้นฐาน
การขาด Power Control register และวิธีแก้
- flow การ initialize MMC สรุปได้เป็นขั้นตอนต่อไปนี้
- หลัง reset ตั้ง clock เป็น 400KHz
- รอ 1ms แล้วรออีก 74 clock
- ส่ง CMD0 แล้วรอ response
- ส่ง CMD1 ซ้ำจนกว่า bit ที่ 31 ของ response จะเป็น 1
- เมื่อจบ loop บันทึกค่าเป็น Operating Conditions register
- ดำเนินอัลกอริทึม initialize ของ SD ต่อ โดยยกเว้นการอ่าน register เฉพาะ SD
- ตรวจจับความเข้ากันได้กับ High-Speed แบบ optional และเปิดใช้หนึ่งในหลายโหมด HS
- โค้ดไปได้ถึงแถวขั้นตอนที่ 4 แต่หลังจากนั้น eMMC ไม่ตอบสนองต่อคำขอใด ๆ
- หาสาเหตุอยู่หลายวันไม่พบ จนเมื่อเอาโค้ดที่เกี่ยวกับการ reset controller ออก eMMC ก็เริ่มตอบสนอง และจำกัดปัญหาได้ที่ฟังก์ชัน
reset_host_controller() - จุดแปลกของฟังก์ชันนี้คือไม่พบ register
host_configurationในมาตรฐาน- โค้ดเดิมรวม register หลายตัวเข้าเป็นกลุ่ม
host_configurationสองกลุ่มตามอำเภอใจ - การ initialize ก็ยังไม่สมบูรณ์ และเพียงตั้งกลุ่มแรกเป็น 0
- โค้ดเดิมรวม register หลายตัวเข้าเป็นกลุ่ม
- กลุ่มแรกมี register Power Control ที่ควบคุมตัวปรับแรงดันไฟของการ์ดรวมอยู่ด้วย
- บนฮาร์ดแวร์บางส่วน รวมถึง implementation ทั้งหมดที่ใช้ eMMC register นี้จำเป็นต่อการเปิดการ์ดเอง
- ในดีไซน์อื่นที่ต่อ power rail เข้ากับสล็อตโดยตรง การตั้งค่านี้อาจถูกละเลยได้
- ใช้วิธีแก้ชั่วคราวโดยนำค่าดั้งเดิมที่อยู่ใน
host_configuration_0มาใช้ - ปัญหาหลักคือพยายามสื่อสารกับการ์ดทั้งที่ยังไม่ได้เปิดไฟให้การ์ด
- หลังจากนั้นใช้เวลาอีกหลายชั่วโมงหาคำสั่งบางตัวที่ใช้ได้เฉพาะกับ SD card แล้วปิดใช้ และเมื่อ controller เริ่มให้ debug output ที่มีความหมายมากขึ้น งานที่เหลือก็ดำเนินไปค่อนข้างปกติ
สถานะปัจจุบันและงานที่เหลือ
- สุดท้าย SerenityOS สามารถเปิดกราฟิกเซสชันบางส่วนที่เสียหายได้อย่างช้ามาก แต่ไม่นานก็ล็อกค้าง
- ปัญหากราฟิกเซสชันนี้และกระบวนการทำให้ framebuffer กลับมาปกติอีกครั้งจะกล่าวถึงในบทความถัดไป
- งานทั้งหมดเป็นกระบวนการเรียนรู้ที่ใช้เวลาราว 6 เดือน และระหว่างนั้นก็มีงานอื่น ๆ ดำเนินไปด้วย
- เป้าหมายถัดไปคือจัดระเบียบแพตช์และส่ง upstream ภายในปีนี้
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
เคยอ่านมาว่าการ ปรับไดรเวอร์ของ NetBSD ให้เข้ากับเคอร์เนลแบบกำหนดเอง นั้นค่อนข้างง่าย เลยคิดว่าฝั่ง Serenity อาจเดินเส้นทางนั้นได้เหมือนกัน
สำหรับ OS เกิดใหม่ ไดรเวอร์อุปกรณ์ เป็นอุปสรรคใหญ่
เพราะการจัดวางฮาร์ดแวร์แทบจะตายตัว จึงทำให้สร้างหรือนำไดรเวอร์มาใช้ และทดสอบระบบได้ง่ายขึ้น
สามารถรันไดรเวอร์ใน user space ได้โดยต้องมีการรองรับพื้นฐานเพียงเล็กน้อย
https://en.wikipedia.org/wiki/Rump_kernel
แต่ฝั่งไดรเวอร์ไม่ค่อยแน่ใจ
ดูเหมือนว่านี่คือแนวทางที่ Apple ทำมาตั้งแต่ต้นโดยรวม และเป็นกรณีเดียวในตระกูล Unix สำหรับผู้บริโภคที่ประสบความสำเร็จอย่างมาก
System76 ก็เกือบเป็นตัวอย่างแบบนั้น ส่วน Frame.work ก็คล้ายกันแต่ไม่ได้โฟกัสที่ตัว OS เองเท่าไร
การทำให้มันทำงานบนเครื่องที่ทุกเงื่อนไขไม่เป็นใจได้ นับเป็น งานแฮ็กที่ยอดเยี่ยมมาก และดูเหมือนเป็นผลจากความพยายามมหาศาลของคนมีฝีมือ
เวลาอ่านบทความแบบนี้ก็ทำให้อยากรู้ว่าจะเริ่มเข้าสู่โลกของ ไดรเวอร์และ OS ได้อย่างไร
มันดูซับซ้อนมากจนไม่ค่อยรู้ว่าจะเริ่มตรงไหนดี
สิ่งนี้เรียกว่า memory-mapped I/O (MMIO) ในแอปพลิเคชันทั่วไปทำไม่ได้ เพราะเคอร์เนลจะป้องกันการเข้าถึงหน่วยความจำฮาร์ดแวร์โดยตรง
ถ้าจะเริ่ม ต้องใช้ภาษาอย่าง Rust/C++/C/Zig ที่สร้าง machine code สำหรับ CPU เป้าหมายได้ และควรเป็นภาษาที่ไม่มี runtime หรือ GC ถ้าเพิ่งเริ่มกับภาษาระดับต่ำ แนะนำ C เพราะมีตัวอย่างเยอะ
ยังต้องเรียน assembly พื้นฐานของ CPU เป้าหมายด้วย และบางคำสั่งอาจไม่มีให้ผ่าน intrinsic ของภาษาระดับสูง
จากนั้นเมื่อเขียนเคอร์เนล hello world ก็จะได้เรียนรู้ว่า CPU เริ่มเคอร์เนลอย่างไร โหมดการรันและระดับสิทธิ์แบ่งกันอย่างไร
หลังจากนั้นบน x86 ก็ต้องตั้งค่า CPU ตามที่ต้องการ เช่น สลับไปใช้ long mode เพื่อใช้คำสั่ง 64 บิต และโดยปกติจะตั้งค่า virtual memory ในขั้นตอนนี้ด้วย
มาถึงตรงนี้ก็จะเริ่มจับทางได้ว่า CPU เชื่อมกับ OS อย่างไร วิธี enumerate อุปกรณ์ที่ใช้ได้และหาตำแหน่งหน่วยความจำทำอย่างไร จากนั้นยังเหลืองานอีกมาก เช่น filesystem และ scheduler
ความแตกต่างระหว่างซอฟต์แวร์ที่รันอยู่บน OS กับเคอร์เนลของ OS สุดท้ายแล้วคือ โหมดของ CPU ที่กำลังรันโค้ดนั้นอยู่ และในระดับสิทธิ์สูงสุดจะใช้คำสั่งที่แอปทั่วไปใช้ไม่ได้
ต่อมาผมเจอเอกสารเหมือนขุมทรัพย์ที่ซ่อนอยู่ในเอกสารของ FreeBSD โดยเฉพาะ FreeBSD Architecture Handbook และ FreeBSD Developers' Handbook น่าจะช่วยได้มาก
https://lwn.net/Kernel/LDD3/
https://docs.freebsd.org/en/books/
Minix เขียนไว้อย่างเป็นระเบียบมาก เคอร์เนลก็มีประมาณ 5,000 บรรทัด และถูกใช้ในตำราหลายเล่ม
ผมได้ลองทำเซิร์ฟเวอร์ง่าย ๆ และแฮ็กเคอร์เนลด้วย เพราะ Minix เป็น microkernel ไดรเวอร์ส่วนใหญ่จึงทำงานในลักษณะนั้น
ผมอ่านเอกสารการสอนล่วงหน้าและแทบไม่ได้เข้าฟังบรรยาย แต่ก็ได้ 8 จาก 10 คะแนน
NetBSD กับ SerenityOS ก็ได้ยินคำชมมาเยอะ และ Andreas ทำงานพัฒนาหลายอย่างผ่านไลฟ์สตรีม
ถ้ารู้ว่าจะเริ่มตรงไหน จริง ๆ แล้วมันจะง่ายขึ้น
ตัวอย่างเช่น ไดรเวอร์อุปกรณ์มีหน้าที่เปิดเผยอินเทอร์เฟซให้โปรแกรมอื่น ๆ ที่รันบนคอมพิวเตอร์เข้าถึงและควบคุมอุปกรณ์บางอย่างได้
https://m.youtube.com/watch?v=juGNPLdjLH4 เป็นคอร์สเร่งรัดที่ใช้ได้
คุณยังสามารถทำอุปกรณ์ USB ง่าย ๆ ด้วยของอย่าง Arduino เพื่อแลกเปลี่ยนข้อมูลกับ PC ได้ เช่น https://m.youtube.com/watch?v=yTc2GLXfCOY
จากนั้นก็ทำความเข้าใจว่า subsystem ที่สนใจทำอะไร จะทำให้มันทำงานอย่างไร แล้วเขียนโค้ด ส่วนนี้รวมถึงอุปกรณ์เก็บข้อมูล อุปกรณ์กราฟิก ฯลฯ
Raspberry Pi ก็อาจเป็นจุดเริ่มที่ดีสำหรับการทดลองแบบนี้ เช่น Writing a bare metal operating system for the raspberry pi https://github.com/babbleberry/rpi4-osdev
https://wiki.osdev.org/Bare_Bones
ผมชอบคอนเซปต์ของ SerenityOS และเบราว์เซอร์ Ladybird เลยดีใจที่เห็นความคืบหน้าแบบนี้
Ladybird ไม่เพียงกลายเป็นโปรเจกต์อิสระ แต่ยังไม่มอง SerenityOS เป็นแพลตฟอร์มเป้าหมายอีกต่อไป
Ladybird กำลังค่อย ๆ ถอดเลเยอร์ Serenity ของตัวเองออกและแทนที่ด้วยทางเลือกที่เป็นกระแสหลักมากขึ้น
ในฐานะคนที่ใช้ Linux เป็นหลัก ผมตั้งตารอที่ Ladybird จะกลายเป็นทางเลือกจริง ๆ บน Linux
แต่ในฐานะแฟน SerenityOS ก็เสียดายที่พลังงานและนวัตกรรมที่เคยไหลเข้า Ladybird กำลังออกจาก SerenityOS ไป
ถ้าต้องการความช่วยเหลือเรื่องการแฮ็ก Chromebook ลองถามใน เมลลิงลิสต์ chromium-os-dev ได้
น่าจะมีใครสักคนช่วยให้ CCD ทำงานได้
https://groups.google.com/a/chromium.org/g/chromium-os-dev?p...
บูตโหลดเดอร์ Depthcharge ก็รองรับการบูตผ่านเครือข่ายด้วย TFTP
ต้อง build เองแล้ว flash ลง SPI แต่เป็นฟีเจอร์ที่ยอดเยี่ยมมากเวลาพัฒนาเคอร์เนลแบบวนซ้ำ
https://chromium.googlesource.com/chromiumos/platform/depthc...
ผมนึกว่า SerenityOS เคยรันบน ฮาร์ดแวร์จริง แล้วเสียอีก หรือว่ายังรันอยู่แค่ใน QEMU ทั้งหมด?
แต่แทบไม่มีไดรเวอร์ที่พอจะพูดถึงได้ จึงทำงานได้แค่ในความหมายพื้นฐานที่สุด เป็นไปได้เฉพาะกับฮาร์ดแวร์บางรุ่น และคงไม่ได้รันดีนัก
ความพยายามครั้งนี้คือการทำให้มัน ทำงานได้อย่างน่าเชื่อถือ บนแพลตฟอร์มฮาร์ดแวร์จริงอย่างน้อยหนึ่งแพลตฟอร์ม
Serenity ยังคงน่าประทับใจ แม้บางครั้งผมจะไม่เห็นด้วยกับวิธีการ implementation ของมันก็ตาม
ผมมาดูอะไรน่ากลัว ๆ แบบนี้แหละ
doas dd seek=$((0x$1)) bs=1 count=1 of=/dev/port < <(xxd -p -r <<< "$2")