پرش به محتوای اصلی

CPU فراموشکار (لینوکس در M4)

هکرنیوز۱۴۰۵ مهر ۱۰, جمعه، ساعت ۱۷:۵۲حدود 8 دقیقه مطالعه

آدرس مقاله: https://yuka.dev/blog-2026-10-02-linux-m4.html آدرس نظرات: https://news.ycombinator.com/item?id=49933869 امتیاز: 251 # نظرات: 175

این پست وبلاگ به جزئیات کاملی درباره نحوه راه‌اندازی لینوکس در M4 Mac mini می‌پردازد. من شما را تشویق می کنم اصطلاحات و مفاهیمی را که نمی دانید جستجو کنید، زیرا نمی توانم تمام پیشینه را در این پست توضیح دهم ;)

قبل از گفتن هر چیز بیشتر، لازم است از کل تیم لینوکس آساهی برای تمام کارهای قبلی و کمک آنها در طول سفر تشکر کنم. اگر می‌خواهید لینوکس خط اصلی بیشتری را در مورد Apple Silicon ببینید، لطفا به Asahi Open Collective کمک مالی کنید!

در نوامبر 2024، من یک M4 Mac mini خریدم، که می‌خواستم شبیه دستگاه‌های Apple Silicon M1-M3 باشد و به سرعت در لینوکس Asahi پشتیبانی شود. در حالی که M4 چندین ماه روی میز من نشسته بود، جزئیات بیشتری در مورد این SoC ظاهر شد.

معلوم شد که این کار دشوارتر است، زیرا دستگاه‌های M4 اولین نسل از سیلیکون اپل هستند که SPTM (Secure Page Table Monitor) را اجباری می‌کنند، که در برابر آسیب‌پذیری‌ها در هسته XNU macOS سخت‌تر می‌شود. در نسل‌های قبلی، بالا آمدن لینوکس عمدتا بر اساس ردیابی‌های MMIO بود که با استفاده از هایپروایزر m1n1 گرفته شده بود و امکان تجزیه و تحلیل تعاملات بین درایورهای اصلی macOS و سخت‌افزار را فراهم می‌کرد.

با SPTM، تغییرات عمده در m1n1 برای اجرای macOS تحت هایپروایزر مورد نیاز است، و این تغییرات مطمئنا فراتر از چیزی است که من به عنوان یک تازه کار در این فضا می توانم به آن دست پیدا کنم. با این حال، این یک هدف کاملا گمشده نبود. به موازات کار Hypervisor، من اولین تلاش خود را برای بوت کردن لینوکس در M4 آغاز کردم. این به معنای غیرفعال کردن امنیت بوت دقیق، نصب m1n1 به عنوان یک شی بوت سفارشی از طریق بازیابی macOS 1 و دریافت یک کنسول سریال 2 برای بررسی گزارش‌ها بود.

در ابتدا، m1n1 فقط می‌توانست در حالت BRINGUP شروع به کار کند و در حالی که تلاش می‌کرد تا GXF 3 را در غیر این صورت مقداردهی اولیه کند، بلافاصله از کار افتاد. مشخص شد که عملکرد GXF در حالت بوت خام در این SoCهای M4+ غیرفعال/قفل شده است، بنابراین شرطی کردن مقداردهی اولیه آن و نادیده گرفتن آن در این دستگاه‌ها کار درستی بود. علاوه بر ویژگی غیرفعال GXF، RVBAR (Reset Vector Base Address Register) نیز وجود دارد: مکانی در حافظه (یکی برای هر هسته CPU) که ​​تعیین می‌کند هسته در هنگام روشن شدن از کجا شروع به اجرا می‌کند.

کد m1n1 آدرس نقطه ورودی خود را در RVBAR برای هر هسته هنگام بوت کردن هسته یا بارگذاری زنجیره ای m1n1 دیگر می نویسد. نوشتن بر روی آن همچنین منجر به خرابی M4 شد، اما به طور خلاصه، از قبل دارای مقدار صحیحی بود، بنابراین این نوشتن نیز باید نادیده گرفته می‌شد.

در این مرحله، مدت زیادی گذشت بدون اینکه من مک مینی را لمس کنم. در کنگره ارتباطات آشوب در پایان سال 2025، انگیزه جدیدی پیدا کردم. در نهایت، من یک درخت دستگاه بسیار حداقلی را که فقط حاوی هسته‌های CPU و کنترل‌کننده وقفه AIC بود را هک کردم و هسته لینوکس (با استفاده از linux.py m1n1) را با پارامتر earlycon بارگیری کردم، اما هیچ خروجی بعد از "Vectoring to next step" ندیدم.

از آنجایی که من هیچ خروجی مفیدی از هسته دریافت نمی‌کردم، فقط می‌توانستم حدس‌های عجیبی در مورد اینکه چه مشکلی دارد انجام می‌دهد، درست است؟ تصمیم گرفتم روش brute-force را امتحان کنم: println -debugging خوب قدیمی. من روال مونتاژ debug_putc را از m1n1 گرفتم و آن را طوری تنظیم کردم که یک کاراکتر "a" را چاپ کند 4 . من این را در ابتدای راه‌اندازی در کد هسته لینوکس وارد کردم، و مطمئنا، پس از «Vectoring to next stage» یک «a» دریافت کردم! اساسا، من کد بوت لینوکس را دو نیم کردم و به کد اولیه MMU رسیدم (که هنوز خیلی زود است، هنوز در کد اسمبلی در arch/arm64/kernel/head.S ).

آیا مقداردهی اولیه MMU به نوعی CPU را خراب می کرد؟ نه کاملا: UART با استفاده از I/O دارای نقشه حافظه قابل دسترسی است. هنگامی که MMU فعال می شود، تمام دسترسی های حافظه به آدرس های مجازی هدایت می شوند که از طریق جداول صفحه به آدرس های فیزیکی مربوطه نگاشت می شوند. در حالی که m1n1 نقشه‌هایی را ایجاد می‌کند تا فضای آدرس MMIO را در آدرس‌های مجازی یکسان نشان دهد، لینوکس این کار را انجام نمی‌دهد، به این معنی که پس از فعال شدن MMU، به جای UART به فضای نقشه‌برداری نشده دسترسی پیدا می‌کنیم.

من صفحات اولیه را تغییر دادم تا این نقشه برداری 1:1 را برای فضای MMIO اضافه کنم، و اکنون debug_putc من خیلی بیشتر در فرآیند بوت کار کرد. دوباره دو نیم شد، چاپ تا جایی در مقداردهی اولیه کنترل کننده وقفه کار کرد! من آن را به یک نوشتن در رجیستر CPU مخصوص پیاده سازی SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2 محدود کردم، که باعث خرابی جدید شد. بعد از اینکه من برای این نوشتن نظر گذاشتم، هسته به یک پوسته بوت شد. بیا برویم!

SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2، که مربوط به مجازی‌سازی است، از آن زمان در نسخه‌های جدید iBoot باز شده است، بنابراین اظهار نظر در مورد نوشتن دیگر ضروری نیست.

اکنون که می‌دانستم کد لینوکس واقعا اجرا می‌شود، یک بار دیگر به این موضوع نگاه کردم که چرا با وجود پارامتر بوت earlycon، قبلا هیچ خروجی چاپی روی کنسول سریال دریافت نکرده‌ام.

مطمئنا، درخت دستگاه فقط stdout-path = "serial0" را نداشت، و پس از اضافه کردن آن، در هنگام خرابی‌های اولیه، موارد ثبت نام کامل و ردپای پشته را از لینوکس دریافت کردم.

در حال حاضر، m1n1 هسته‌های ثانویه را راه‌اندازی نکرد زیرا smp_start_offset وجود نداشت (یک آفست کدگذاری شده در m1n1؛ بدون آن، smp_init حذف می‌شود). من افست مورد استفاده برای پایه M1 - M3 را امتحان کردم و توانستم هسته های ثانویه را راه اندازی کنم. وقتی دوباره سعی کردم لینوکس را بارگیری کنم، به یک خرابی مرموز دیگر رسیدم.

CPU های سیلیکون قبلی اپل قبلا در مورد دستورالعمل WFI نکات عجیبی را می دانستند. بسته به وضعیت بیت مرغ (بیتی در یک رجیستر، که به فروشنده اجازه می‌دهد تا برخی از بهینه‌سازی‌ها یا ویژگی‌های CPU را غیرفعال کند، یا آنها را خارج کند) به نام ARM64_REG_CYC_OVRD_ok2pwrdn_force_mask در کد XNU OSS، دستور WFI باعث می‌شود که رجیسترهای CPU این نسل‌های قبلی x0-x1 را صفر کند. XNU این رجیسترها را در پشته قبل از WFI ذخیره می کند و سپس آنها را بازیابی می کند. در SoC های M1-M3، m1n1 این رفتار را غیرفعال می کند، بنابراین CPU مانند سایر پردازنده های arm64 رفتار می کند.

هسته Asahi بعدا به طور خاص این رفتار را مجددا فعال می کند تا به هسته های CPU اجازه دهد به حالت خواب عمیق تری برسند و در مصرف انرژی صرفه جویی کنند. این همچنین برای اجازه دادن به یک هسته در خوشه برای افزایش سرعت کلاک بالاتر زمانی که همه هسته‌های دیگر در این حالت خواب عمیق‌تر WFI هستند، لازم است.

به نظر می رسد این قطعه مرغ یا قفل شده است یا در M4 حذف شده است، و رفتار پیش فرض با مشخصات ARM64 مطابقت ندارد (به طور خاص: "اگر سیستم به گونه ای پیکربندی شده است که دستورالعمل WFI می تواند تکمیل شود، پس دستورالعمل WFI نباید باعث از بین رفتن حالت معماری شود." در آوریل 2026، با جایگزین کردن تمام دستورالعمل‌های WFI و WFIT (منتظر وقفه با تایم‌اوت) در هسته خود با NOP (بدون عملیات)، موفق شدم لینوکس را روی M4 با تمام هسته‌های فعال بوت کنم.

با این کار، یک سفر طولانی به سمت راه حل بالادستی برای مشکل WFI آغاز شد. در ابتدا، من به نحوه برخورد با خطاها (رفتارهای نادرست سیلیکون) نگاه کردم. یک چارچوب کامل در لینوکس وجود دارد که به آن اجازه می‌دهد در هنگام راه‌اندازی اولیه، خود را در حافظه وصله کند. با این حال، این رویکرد کنار گذاشته شد، زیرا تشخیص دقیق مواردی که در آن WFI باید NOP'ed شود، بسیار دشوار است. یعنی یک ماشین مجازی که تحت هایپروایزر macOS کار می‌کند نیز منطق اشتباه را راه‌اندازی می‌کند، اما WFI توسط هایپروایزر macOS به دام افتاده و برای برنامه‌ریزی موثر مهمان‌های مختلف استفاده می‌شود.

تشخیص مجازی‌سازی (به‌ویژه زمانی که مجازی‌سازی تودرتو فعال باشد) نیز پیچیده است، بنابراین Will Deacon راه‌حل جایگزینی را پیشنهاد کرد: هسته باید برای غیرفعال کردن WFI idle با استفاده از بوتارگ جدید 6 پشتیبانی کند و سپس m1n1 می‌تواند بوتارگ‌های مناسب را به صورت مشروط در هنگام راه‌اندازی در ماشین‌های بدون فلز که دارای WFI هستند اضافه کند. سپس مکانیزمی را اضافه می کنیم که به لینوکس اجازه می دهد هسته ها را در حالت خواب قرار دهد. در حال حاضر، می‌توان از درایور پایین‌دستی cpuidle-apple برای این کار استفاده کرد، اما کار مجرای PSCI EFI Sven برای راه‌حل بالادستی آینده بسیار امیدوارکننده است.

خوشحالم که بگویم مکانیسم جلوگیری از خرابی لینوکس در دستورالعمل‌های WFI و WFIT در Linux 7 8 و m1n1 9 خط اصلی ادغام شده است، بنابراین آخرین نسخه‌های این نسخه‌ها می‌توانند به صورت بومی با هسته‌های ثانویه در M4 Mac بوت شوند!

این کار تاکنون یک مشکل اساسی در اجرای لینوکس روی تراشه‌های M4 و بعد از آن اپل سیلیکون را کشف کرده و به آن پرداخته است، و به لینوکس اجازه می‌دهد تا روی پوسته‌ای با تمام هسته‌های قابل استفاده راه‌اندازی شود (همان راه‌حل‌های WFI روی تراشه‌های M4 Pro، M4 Max و M5 کار می‌کنند!). مهندسی معکوس لوازم جانبی، که در اینجا به جزئیات آن نمی پردازم، با سرعت آهسته اما پیوسته پیش می رود.

کار خستگی ناپذیر Sven در ساخت هایپروایزر m1n1 قادر به راه‌اندازی و ردیابی macOS در این دستگاه‌ها برای مقابله با اجزای پیچیده‌تر مانند دوربین داخلی، کنترل‌کننده نمایشگر و مقداردهی اولیه GPU بسیار مفید خواهد بود. در بیشتر موارد، من کارم را مستقیما به پروژه های بالادستی مربوطه ارسال می کنم و به همه اجازه می دهم از آن بهره ببرند. گاهی اوقات اگر پروژه های خاصی که بودجه زیادی دریافت می کنند، در مورد نحوه بهره مندی آنها از پیشرفت پروژه های بالادستی شفاف تر باشد.

اگر می‌خواهید از کار من در لینوکس در M4 حمایت کنید، من کمک‌های مالی را در LiberaPay یا حامیان مالی GitHub دریافت می‌کنم. لطفا به Asahi Open Collective برای لینوکس بیشتر در مورد Apple Silicon کمک مالی کنید.

مثل همیشه امیدوارم چیزی یاد بگیری :)

راهنمای کاربر m1n1 - Asahi Linux Documentation ↩︎

اشکال زدایی از طریق کنسول سریال - Asahi Linux Documentation ↩︎

اسرار سخت افزار سیلیکون اپل: SPRR و سطوح استثنای محافظت شده (GXF) | سون پیتر ↩︎

هک: DEBUG: debug_putc در اوایل بوت شدن در t8132 (8c86bd8c) · تعهدات · Yureka Lilian / linux · GitLab ↩︎

منتظر وقفه باشید - مستندات - توسعه دهنده بازو ↩︎

پاسخ: [PATCH v2] arm64: خطا: مدیریت از دست دادن وضعیت اپل WFI - Will Deacon ↩︎

arch: arm64: add early_param idle=<wfi|yield|nop> - kernel/git/torvalds/linux.git - درخت منبع هسته لینوکس ↩︎

arm64: اضافه کردن لغو برای WFxT - kernel/git/torvalds/linux.git - درخت منبع هسته لینوکس ↩︎

kboot: در صورت از دست دادن حالت wfi توسط yuyuyureka، wfi/wfit را غیرفعال کنید · درخواست کشش شماره 672 · AsahiLinux/m1n1 ↩︎

خواندن متن کامل در هکرنیوزبه زبان اصلی، در سایت ناشر باز می‌شود
متن اصلی (انگلیسی)

The Forgetful CPU (Linux on M4)

Article URL: https://yuka.dev/blog-2026-10-02-linux-m4.html Comments URL: https://news.ycombinator.com/item?id=49933869 Points: 251 # Comments: 175

همه‌ی اخبار فناوری