Skip to content

MMIO والمنافذُ والتخزينُ الساكن

ثلاثُ حاجاتٍ تلزمُ كلَّ مُشغِّل: أن تكتبَ في منفذٍ معزول، وأن تكتبَ في عنوانٍ فيزيائيّ، وأن تملكَ مخزنًا ساكنًا اسمُه ثابتٌ يعرفُه الرابط. الثلاثةُ مُخفَّضةٌ في المترجّمِ تجميعًا مضمَّنًا أو رمزَ بيانات — لا نداءَ مكتبةٍ في شيءٍ منها.

١ · المنافذُ المعزولة

sad
@رمز("com1_lsr") ثابت سجل_الحالة = 0x3FD

دالة رقم اقرأ_الحالة()
    ارجع اقرأ_منفذ(0x3FD)
نهاية

@رمز("serial_putc") دالة أرسل_حرفًا(رقم حرف)
    بينما ((اقرأ_الحالة() & 0x20) == 0)
    نهاية
    اكتب_منفذ(0x3F8، حرف)
نهاية
bash
$ sad-build منفذ.ص --حرّ --هدف=x86_64-unknown-none-elf --أظهر-llvm -o منفذ.ll

لا مخرَجَ. وفي الـIR:

llvm
@com1_lsr = constant i64 1021

%port.read = call i8 asm sideeffect "inb $1, $0",
             "={ax},{dx},~{dirflag},~{fpsr},~{flags}"(i16 1021)

define void @serial_putc(i64 %"حرف") {
  call void asm sideeffect "outb $0, $1",
       "{ax},{dx},~{dirflag},~{fpsr},~{flags}"(i8 %val, i16 1016)

العائلةُ كاملةً: اقرأ_منفذ · اقرأ_منفذ16 · اقرأ_منفذ32 ونظائرُها اكتب_منفذ · اكتب_منفذ16 · اكتب_منفذ32.

المنافذُ المعزولةُ عائلةُ x86 وحدَها

error: [SEM038] المدمجة «BUILTIN_PORT_WRITE» تُخفَّض إلى تعليمة «outb» تخصّ
عائلة x86 (i686 وx86_64)، والهدف المطلوب «aarch64»
  → ابنِ لهدف من العائلة نفسها (--هدف=i686-... أو --هدف=x86_64-...)، أو استبدل
    بالمدمجة نظيرًا محايدًا للمعماريّة، أو اعزل الاستدعاء خلف فرع خاصّ
    بالمعماريّة.

والقيدُ معماريٌّ لا خاصٌّ بالوضعِ الحرّ: المستضافُ على aarch64 يُرفَضُ كذلك، لأنّ التعليمةَ غائبةٌ عن المعماريّةِ لا عن المكتبة.

٢ · الذاكرةُ المُعنوَنة

اقرأ_ذاكرة32 · اكتب_ذاكرة32 · اقرأ_ذاكرة64 · اكتب_ذاكرة64 — وللشاشةِ النصّيّةِ اكتب_ذاكرة16. الوسيطُ الأوّلُ عنوانٌ عدديّ:

sad
دالة اكتب_خانة(رقم فهرس، رقم حرف، رقم لون)
    متغير خليّة = حرف + (لون * 256)
    اكتب_ذاكرة16(0xB8000 + (فهرس * 2)، خليّة)
نهاية

والخفضُ inttoptr ثمّ store volatile — بلا وسيطٍ ولا نداء:

llvm
  %addtmp5 = add i64 753664, %shltmp4     ; 753664 = 0xB8000
  %mem.ptr = inttoptr i64 %addtmp5 to ptr
  store volatile i16 %0, ptr %mem.ptr, align 2

volatile ليست خيارًا هنا

المسُّ صادرٌ عن اكتب_ذاكرة* يُبَثُّ volatile دائمًا. ولو لم يكن كذلك لأسقطَ المُحسِّنُ كتابةً في عنوانٍ لا يقرؤه أحدٌ في نظرِه — وهو بالضبطُ ما يفعلُه سجلُّ جهاز.

٣ · التخزينُ الساكن ورمزُ الرابط

مخزنٌ مفردٌ: @رمز + متطاير

sad
@رمز("kernel_ticks") متغير متطاير نبضات = 0
llvm
@kernel_ticks = global i64 0
...
  %"نبضات.gload" = load volatile i64, ptr @kernel_ticks, align 4
  store volatile i64 %addtmp, ptr @kernel_ticks, align 4
  • @رمز("اسم") سمةٌ اسميّةٌ سابقة، تمنحُ المخزنَ رمزَ رابطٍ مُصدَّرًا (ExternalLinkage) بدلَ الاسمِ الداخليِّ المُشوَّه. والاسمُ ASCII — رموزُ النواةِ كذلك، وLLVM يهرّبُ غيرَ ASCII في المعرّفات.
  • متطاير لصيقةٌ لاحقة (الموصوفُ ثمّ الصفة). وبدونِها يبقى المخزنُ internal بلا volatile — وذلك هو المقصودُ للمتغيّرِ العاديّ.

مصفوفةٌ مصفَّرةٌ في .bss

sad
@رمز("idt_ptr") متغير ساكن واصف_الجدول مصفوفة[10]
متغير ساكن إطار_الشاشة مصفوفة[4096]
llvm
@idt_ptr = global [10 x i8] zeroinitializer, align 16
@"إطار_الشاشة" = internal global [4096 x i8] zeroinitializer, align 16

قابلةٌ للكتابة (global لا constant)، محاذاةُ ١٦، ومُصدَّرةٌ أو داخليّةٌ بحسبِ وجودِ @رمز. والحجمُ عددٌ صحيحٌ حرفيٌّ موجب — وإلّا SEM023.

أخذُ العنوان: عنوان_رمز

sad
متغير قاعدة = عنوان_رمز("إطار_الشاشة")
اكتب_ذاكرة32(قاعدة + إزاحة، لون)

عنوان_رمز("اسم") تُخفَضُ ptrtoint على رمزٍ خارجيّ — بلا نداءِ زمنِ تشغيل، لأنّها إحالةُ رابطٍ لا محاكاة. وتعملُ في الوضعَين معًا. ورمزٌ مصرَّحٌ دالّةً (دالة خارجية) يُعادُ استعمالُه؛ وإلّا يُنشَأُ رمزُ بيانات. ووسيطٌ غيرُ ثابتٍ ⇒ SEM021.

٤ · وصفةٌ كاملةٌ مُترجَمة

sad
متغير ساكن إطار_الشاشة مصفوفة[4096]

دالة اكتب_نقطة(رقم إزاحة، رقم لون)
    متغير قاعدة = عنوان_رمز("إطار_الشاشة")
    اكتب_ذاكرة32(قاعدة + إزاحة، لون)
نهاية

دالة رئيسية()
    اكتب_منفذ(0x3F8، 65)
    اكتب_نقطة(0، 0x00FF00)
نهاية
bash
$ sad-build mmio.ص --حرّ --هدف=x86_64-unknown-none-elf --أظهر-llvm -o mmio.ll

لا مخرَجَ، والرمزُ صفر.

٥ · الكومةُ الساكنة

الكومةُ الحرّةُ مصفوفةٌ في .bss تُبَثُّ مع كلِّ وحدةٍ حرّة:

llvm
@__sad_heap = global [4194304 x i8] zeroinitializer, align 16

٤م.ب هنا (هدفٌ معدنيٌّ عارٍ). ويعلوه --حجم-الكومة=<ميغابايت> — وهو ضرورةٌ لا رفاهية: العددُ الكبيرُ يمدُّ _kernel_end فيحجزُ مخصِّصُ الإطاراتِ ما لا تملكُه الآلة، ولا سبيلَ للمترجّمِ إلى معرفةِ خريطتِك. التفصيلُ في الوضعِ الحرّ §٥.

ما يلي

مُرخَّص بموجب رخصة MIT