Cubitos هو نظام تشغيل متعدد الأغراض ، 64 بت ، (جزئيًا) (جزئيًا).
مكتوبة في لهجة شرارة ADA.
Cubit إلى حد كبير عمل في مجال التقدم! بعد قولي هذا ، يرجى إعطائها تدور. ترحيب المساهمين!
gprbuild ، gnat ، وما إلى ذلك في $PATH الخاص بكلإنشاء قابلة للتمهيد. iiso ، ستحتاج أيضًا:
التبعيات: ستحتاج إلى برنامج التحويل البرمجي GNAT 2020 ، وإذا كنت ترغب في إنشاء أدوات Live-CD ، فستحتاج إلى أدوات Xorriso و Grub-Mkrescue ، وربما Grub-PC-Bin اعتمادًا على بيئة المحاكي/المحاكاة الافتراضية التي تستخدمها. من المحتمل أن يتم توفيرها في مدير حزمة Distro الخاص بك. يمكن بناء ذلك في Linux وعلى Windows باستخدام WSL.
git clone https://github.com/docandrew/CuBit.git
make
سيؤدي ذلك إلى بناء Cubit وإنشاء ملف Live-CD .iso. يمكن تركيب ISO وتشغيله في VirtualBox أو Bochs أو QEMU.
| مهمة | يأمر |
|---|---|
| إنشاء توثيق (في البناء/المستندات) | make docs |
| Run Run | make prove |
| بناء وثائق HTML | make html |
يعد ADA غير حساس للحالة (وهو نوع من اللطيف ، بصراحة) ، ولكنه يجعل جميع الرموز التي تم تصديرها أقل حالة ، لذلك أي شيء في.
الأنواع المذكورة التي تحتوي على "ثقوب" تسبب GNAT لإدراج فحص وقت التشغيل لقيم صالحة عند تعيينها. لم أتمكن من العثور على pragma لتعطيل هذه الشيكات. في النهاية ، سنكتب وظائف معالج الاستثناء التي يمكنها إما إجراء عمليات الفحص أو التسبب في ذعر kernel ، ولكن في الوقت الحالي ، تملأ الثقوب بقيم واضحة مثل BAD_1 ، BAD_2 ، إلخ.
يرجى التأكد من تشغيل البراهين (باستخدام make prove ) قبل تقديم طلبات السحب. كن حذرًا جدًا بشأن شرح براغما لتعطيل التحذيرات. سوف يعطي gnatprove بعض التحذيرات الزائفة مثل statement has no effect أو unused assignment غير صحيحة بشكل واضح ، ولكن يرجى التحقق المزدوج.
يبدو أن السجلات المتغيرة تقوم بإدخال بعض الرصاص الإضافي في السجل الأساسي ، حتى لو تم استخدام Pragma Pack. لا تستخدم هذه كـ "تراكب" أعلى الذاكرة الحالية ، على سبيل المثال جداول ACPI. سيكون لديك مشكلات محاذاة مع بعض الحقول وينتهي بها الأمر بالبيانات غير المرغوب فيها. وينطبق الشيء نفسه حتى بالنسبة للسجلات غير المتزايدة التي تستخدم التمييز.
MAX_PHYS_ALLOC - تعيين في config.ads ، هذه هي الذاكرة الفعلية MAX التي تدعمها Cubit. هناك حد فقط هنا هو عملي ، حيث يتم إعداد مخصص MEM Boot لإنشاء نقار نقطي لجميع هذه الذاكرة (128 GIB) ، والتي تشغل مساحة لا بأس بها. (قد نفكر فقط في تخصيص قسم كومة صغير تم تعيينه خطيًا لاستخدام kernel وبناء مخصص أفضل حتى لم يعد هذا الحد عاملًا بعد الآن.)
max_phys_address - الحد الأقصى للذاكرة الفعلية النظرية التي تدعمها أجهزتنا (إذا استخدمنا رسم الخرائط الخطي). في حالة X86-64 ، لدينا عناوين افتراضية 48 بت قريبة ، لذلك إذا كنا نريد تعيين كل الذاكرة الفعلية في الذاكرة الافتراضية ، فقد تركنا حوالي 280 تيرابايت ، والتي نحتاج إلى تقسيمها لاستخدامها في النصف الأعلى ، لذلك 128TIB. لاحظ أن Intel تبحث في عنوان 56 بت مع جدول صفحة من خمسة مستويات ، لذلك قد يتغير هذا الرقم قريبًا مقابل x86-64.
max_phys_addressable - عنوان الذاكرة الفعلية العليا على نظامنا الذي نكتشفه في وقت التشغيل. نحن نقوم بمناطق الذاكرة الخطية حتى هذه النقطة (بدءًا من 0xFFFF_8000_0000_0000).
max_phys_usable - عنوان ذاكرة الوصول العشوائي القابلة للاستخدام على نظامنا . قد تكون هناك ثقوب داخل هذا ، لذلك لا يمكننا تخصيص الذاكرة بشكل أعمى من أسفل هذا الحد ، ولكن من المتوقع أن يتعامل المخصص المادي مع العناوين حتى هذه النقطة.
يجب إعداد بعض الهياكل المستخدمة ، مثل جداول GDT و PAGE ، في boot.asm قبل التبديل إلى الوضع الطويل. يشار إلى هذه الجداول "bootstrap" GDT و PAGE ، على التوالي. هناك أيضًا مخصص الذاكرة الفعلية "التمهيد". في وقت لاحق ، نقوم بإعادة تخطيط كامل الذاكرة المادية إلى النصف الأعلى من النواة جنبا إلى جنب مع GDT جديد في segment.adb . وتسمى هذه "جداول صفحة kernel" و "kernel gdt."
جداول صفحة bootstrap هوية خريطة الهوية الأولى من الذاكرة ، ثم قم بتخطيطها مرة أخرى في النصف الأعلى ، بدءًا من 0xFFFF_8000_0000_0000. لذلك يعمل P2V و V2P (مازيًا إلى قميصًا ، افتراضيًا إلى مادي) عن طريق الإضافة والطرح البسيطين لأنه يمكنك الوصول إلى الذاكرة الفعلية على ، على سبيل المثال ، 0x0000_0000_Dead_Beef على العناوين الافتراضية 0x0000_0000_beef و 0xffffff_8000_dead_beef.
عندما نتحول إلى خريطة kernel ، لم يعد بإمكاننا معالجة الذاكرة باستخدام عناوين فعلية مباشرة. بدلاً من ذلك ، يجب الوصول إلى عنوان فعلي معين باستخدام العنوان المُعين بالخطية على 0xFFFF_8000_0000_0000. نحن خريطة خريطة جميع الذاكرة الفعلية في 0xFFFF_8000_0000_0000 إلى 0xFFFF_8FFF_FFFF_FFFF.
لاحظ أنه بسبب x86-64 ABI ، يجب ربط النواة في أعلى 2GIB من الذاكرة عند استخدام McModel = kernel. لذلك ، تحتاج جداول الصفحات الخاصة بنا أيضًا إلى رسم خرائط لـ 0xFFFF_FFFF_8XXX_XXXX -> 0x0000_0000_0xxx_xxx.
نعم! لقد حاولت أن أجعل الكود ودودًا للغاية لأولئك الذين لا يعرفون مع Cubitos أو ADA أو Spark. يرجى تجربة ذلك على VM واسمحوا لي أن أعرف ما هو رأيك. ردود الفعل السلبية والنقد البناء مفيد أيضًا.
إنه موثق بشدة ، والمساهمين مرحب بهم!
قد يكون Cubitos نقطة انطلاق جيدة للبحث الأكاديمي. لدى Spark فتحة للهروب لأداء أدلة في COQ ، لذلك للمساهمين الذين يريدون التفكير الرياضي الذين يريدون تحديًا جيدًا ، انظر ما يمكنك إثباته في Cubitos!
يستخدم Spark Framework و Z3 SMT Solver. تعد حلول SMT الجيدة والسريعة دائمًا مجالًا للاهتمام ، وقد يكون Cubitos وسيلة جيدة لقياسها لاستخدامات العالم الحقيقي الأخرى.
| عنصر الكود | مؤتمر |
|---|---|
| الكلمات الرئيسية ADA (اكتب ، من أجل ، حلقة ، إلخ) | كل الأحرف الصغيرة |
| الأنواع (multibootstruct ، pageTableentry ، وما إلى ذلك) | كاميل كاميل |
| أسماء الحزمة | كاميل كاميل |
| المتغيرات ، والوظائف (kmain ، tohexstring ، وما إلى ذلك) | كامال غير معنويات |
| الثوابت (lt_gray ، kern_base ، إلخ) | كل القبعات |
| أسماء الملفات | كلها أقل أو snake_case |
ملاحظة: إذا كان التواصل مع مكون خارجي ، على سبيل المثال ، يجب أن تستخدم الأسماء المتغيرة نفس الاتفاقية مثل واجهة برمجة تطبيقات هذا المكون. على سبيل المثال ، يحتوي هيكل معلومات Multiboot على حقول مثل MEM_LOWER ، إلخ.
سنستخدم هذه الأسماء حرفيًا هنا لسهولة مرجع الوثائق. هذه ليست قاعدة صعبة وصعبة. إذا كانت أسماء واجهة برمجة التطبيقات (API) مرتفعة بشكل مفرط ، أو مربكة ، استخدم تدوينًا مجريًا غريبًا ، أو تكون غبية غير مسطحة ، فلا تتردد في إعادة تسميتها في رمز ADA.
تجنب اختصارات الزهرة بشكل مفرط. المصطلحات الشائعة مثل "Kern" لـ "kernel" ، أو "mem" للذاكرة ، على ما يرام إذا لم يكن هناك غموض. يمكن الخلط بين "VM" للذاكرة الافتراضية وبين "Virtual Machine" ، لذلك تفضل "Virtmem" أو مجرد تهجئتها تمامًا. يجب استخدام الاختصارات فقط إذا تم استخدامها على نطاق واسع أو اتفاقية للأجهزة الأساسية ، مثل ACPI ،
يرجى تحويل علامات التبويب إلى أربع مسافات.
يجب أن تكون ارتباطات خط LF.
تجنب "استخدام" الجمل ما لم يكن ذلك ضروريًا على خلاف ذلك للمشغلين ، ثم الحد من استخدامهم لبرامج فرعية محددة عند الحاجة أو استخدام جملة "استخدام". هذا يجبر الحزمة من النوع الذي يتم توضيحه بشكل صريح ، وبالتالي يمكن الرجوع بسهولة إلى الحزمة والقفز إليها في محرر. استثناءات لهذه القاعدة هي:
استخدم مصطلح "إطار" عند الإشارة إلى الذاكرة الفعلية ، و "الصفحة" عند مناقشة الذاكرة الافتراضية.
يرجى استخدام الأسماء الوصفية للمتغيرات ، والأنواع ، وما إلى ذلك
حاول الحفاظ على خطوط أقل من 80 Chars في معظمها ، ولكن إذا كان ذلك يؤثر سلبًا على قابلية القراءة لكسر الخط ، فلا بأس في وضع الحد الأقصى للاستهلاك. يمكن أن تتجاوز تعليقات نهاية الخط الثمانين إذا كان يؤلمني تدفق الكود لوضعها على خطها الخاص.
إذا تم تعطيل وضع الشرارة على جسم برنامج فرعي ، فيرجى إضافة تعليق لماذا. قد يكون هذا صالحًا تمامًا ، أي مضمّن ASM. ومع ذلك ، حاول إعادة هيكلة الكود لتمكين وضع الشرارة - وخاصة مواصفات البرنامج الفرعي. في بعض الأحيان ، قد يكون ذلك مؤلمًا بعض الشيء ، أي تغيير الوظائف إلى الإجراءات ذات المعلمات "الخارجية" المتعددة.
احتفل بالمسافة البيضاء. دع الرمز يتنفس. استخدم اثنين من الخطوط الجديدة بعد كل جسم برمجة فرعية. يكون أحد الخط الجديد بعد جسم البرنامج الفرعي مناسبًا إذا كانت البرامج الفرعية اختلافات بسيطة لبعضها البعض ، أي الحجج الزائدة ، وتم تجميعها بشكل وثيق لتوضيح علاقتها.
استخدم الكثير من التعليقات ، بتنسيق GNATDOC. من الواضح أن هذا مجال تختلف فيه الآراء ، لكنني أعتقد أن علاج نظام التشغيل مثل المكتبة ذات الوثائق الشاملة يشجع الصواب ويجعله أكثر ودية للمساهمين الجدد. هذا أيضًا يجعل من السهل على الوثائق التلقائية للعيون ، بدلاً من الحفاظ على الوثائق بشكل منفصل. كلنا نعرف واجهة برمجة تطبيقات جيدة عندما نرى واحدة.
"لكن الكود سيتغير وستكون التعليقات قديمة!"
لذلك ... أه ... فقط قم بتحديث التعليقات!
استعارة صفحة من أدلة مشغل الطائرات:
ملاحظة - تشير إلى المعلومات التي تعتبر مهمة للتأكيد
تحذير - يدل على المعلومات التي قد تؤدي ، إن لم يتم النظر فيها ، إلى تعطل النظام أو التشغيل غير الصحيح.
تحذير - يشير إلى المعلومات التي ، إذا لم يتم النظر فيها ، قد تؤدي إلى فقدان بيانات المستخدم أو تلف الأجهزة الأساسية.
| المصطلح المستخدم | مقاس |
|---|---|
| عاب | 4 بت |
| بايت | 8 بت |
| كلمة | 16 بت |
| DWORD (كلمة مزدوجة) | 32 بت |
| Qword (كلمة رباعية) | 64 بت |
يتم تضمين هذا هنا لتجنب الالتباس المستخدم عند وصف الواجهات أو مكونات الأجهزة التي قد تعني فيها "كلمة" شيئًا آخر غير 16 بت. نعني دائمًا 16 بت في رمز Cubit عند استخدام "Word" في التعليقات ، إلخ.
بشكل عام ، سنذكر صراحة طول نوع البيانات باستخدام حزمة واجهات ADA ، أي unsigned_8 ، unsigned_32 ، وما إلى ذلك. يمكن استخدام المصطلحات أعلاه في التعليقات بدلاً من توضيح "قيمة 32 بت" ، على سبيل المثال.
لا يُسمح لوظائف الشرارة بأن يكون لها أي آثار جانبية ، في كثير من الأحيان ، يتم استخدام الإجراء بدلاً من ذلك ، ويكون المعلمة الخارجية للنتيجة مطلوبة ، بدلاً من مجرد إرجاع النتيجة. من المؤلم بعض الشيء تعيين المنشئين لجميع نتائج الإجراء.
لا يمكن مشاركة تعريفات الثوابت (بسهولة) بين رمز ADA وملفات التجميع ، لذلك يتم تكرار بعضها. لقد حاولت الحصول على جميع الثوابت التي تستخدمها ملفات التجميع في Cubit.inc ، إلى جانب ملاحظة المكان الذي يمكن تكراره في رمز ADA. يرجى التأكد من أنك إذا قمت بتغيير أي من هذه القيم ، فسيتم تغييرها في كلا المكانين. إذا قمت بتقديم الثابت الخاص بك ، يتم مشاركته بين Assembly و ADA Code - تأكد من استخدام نفس الاسم!
يقسم Cubit مساحة المكدس الثابتة إلى أجزاء لكل CPU ، يتم تقسيم كل منها إلى أكوام أولية وثانوية لتلك وحدة المعالجة المركزية. المكدس الأساسي ينمو ، وينمو المكدس الثانوي. يتم تعيين مؤشر المكدس الأساسي لوحدة المعالجة المركزية الرئيسية في boot.asm ، وتعيين لكل وحدة المعالجة المركزية الإضافية عند التمهيد في boot_ap.asm.
STACK_TOP +-----------------------+
| |
| CPU 0 Primary Stack |
| |
+-----------------------+
| CPU 0 Secondary Stack |
+-----------------------+
| |
| CPU 1 Primary Stack |
| |
+-----------------------+
| CPU 1 Secondary Stack |
+-----------------------+
| . |
| . |
| . |
+-----------------------+
| |
| CPU N Primary Stack |
| |
+-----------------------+
| CPU N Secondary Stack |
STACK_BOTTOM +-----------------------+
يتم إجراء مكدس SS_INIT الثانوي خلال كل وحدة المعالجة المركزية. يجب اكتشاف فائض المكدس الثانوي في وقت التشغيل ، ومع ذلك توخي الحذر. أثناء syscalls والمقاطعات ، قد تكون مكدس kernel العملية قيد الاستخدام ، والتي لا تحتوي على مكدس ثانوي.
X يعني الانتهاء- يعني في التقدم [ ] There are a lot of potential circular dependencies for just "proof stuff",
i.e. preconditions where we don't want to call a blockingSleep until
interrupts are enabled -> don't want to enable interrupts until the
interrupt vector is loaded -> interrupt vector will update the value that
blockingSleep depends on. It might make sense to keep a big "state"
.ads file with nothing but Ghost variables used in SPARK proofs. It would
not have any dependencies itself, but could be included by everything else
to update their states. Downside is that it might grow huge and unwieldy,
and sorta breaks encapsulation. Might make proofs take a long time too.
[X] Put the stack at a more sensible location
[X] Per-CPU Stacks
[X] Secondary Stacks
[X] Print out full register dump with exceptions
[-] Make type-safe more of the address/number conversions I'm doing.
[-] Error-handling. Need to formalize the mechanism, could get very messy with MP.
[X] Exceptions (Last chance handler)
[ ] Broadcast panic to other CPUs
[ ] Figure out a keyboard scancode -> key array scheme with a future eye towards
internationalization. Maybe just use SDL's keyboard handling scheme and let them sort it out.
[X] Physical memory allocator
[X] Boot-mem allocator using bitmaps
[X] Boot phys memory allocator
[X] Keep track of free space as we allocate/free
[X] Buddy allocator
[X] Virtual memory mapper
[X] Mark 0 page as not present
[X] Re-map kernel pages with appropriate NXE bits, etc. depending on region.
[-] Virtual memory allocator
[-] Demand paging.
[-] Processes / Threads
[ ] Kernel Tasks
[X] Usermode
[-] Scheduler
[ ] Implement killing processes.
[ ] Suspend
[ ] Sleep / Wakeup
[-] ACPI tables
[X] Find RSDT/XSDT
[X] Sane code for parsing these.
[-] APIC
[ ] HPET
[ ] MCFG - PCI express
[ ] SSDT?
[-] I/O APIC
[-] Multiprocessing
[ ] MP Tables (necessary?)
[-] LAPIC
[ ] X2APIC
[ ] Hardware
[X] MSRs
[-] Full CPUID detection
[-] Disk drivers
[ ] MBR/GPT Partition Table
[-] PCI bus
[-] Hard Drives
[-] ATA
[-] AHCI
[ ] PCI express
[ ] Enhanced Configuration Access Mechanism (ECAM) via MCFG tables
[ ] NVMe
[ ] Sound
[ ] Video Drivers
[-] VESA Modes
[-] Filesystem / VFS Layer
[ ] Develop FS-agnostic set of VFS hooks to syscalls
[ ] Develop Drive-agnostic set of VFS hooks to hardware
[-] Ext2
[ ] Networking
[ ] Interface driver
[ ] TCP/IP Stack - RecordFlux should help here.
[ ] Security
[ ] ASLR / KASLR
[ ] Disable certain branch speculation behavior (see x86.MSR)
[ ] if processor supports IBRS in ARCH_CAPABILITIES
[-] KPTI
[ ] Disable KPTI if ARCH_CAPABILITIES MSR indicates not susceptible to RDCL
[ ] Sensible Kernel-Mode-Setting / Framebuffer / Compositor arrangement
[ ] Wow Factor / Eye Candy
[ ] Sweet GRUB splash screen w/ logo
[-] Syscalls
[X] SYSCALL/SYSRET working
[ ] Microkernel Concepts?
[ ] User-mode drivers?
[ ] IPC?
[-] More formal proofs of kernel correctness
[ ] Preventing race conditions - may not be feasible outside of
Ravenscar profile, which doesn't really apply to us.
[-] Implement more of the Ada standard library, especially for Tasks.
[-] Init model - should this look like UNIX? Something else?
[ ] Security Model
[-] Codify it
[ ] Prove it
[ ] Implement it
[-] IMGUI framework
[-] Make all package names Uppercase
[-] Rename all setupXYZ to just setup, since package name is already there.
[X] New Makefile
[-] Use gnatdoc format in comments
[ ] Edit gnatdoc format so NOTE, CAUTION, WARNING shows up as different
colors.
[ ] Edit gnatdoc format to ignore the leading and trailing horizontal rules
[-] Work out a CI/CD pipeline
[ ] Proof Step
[ ] Unit Testing
[X] Build
[ ] Integration/Functional Testing
[X] Generate Documentation
[-] Build installers, isos, etc.
[ ] Write unit tests
[ ] Fuzzing
[ ] Integration tests that run in the OS.
| مهمة | يأمر |
|---|---|
| إنشاء توثيق (في البناء/المستندات) | make docs |
| Run Run | make prove |
| بناء وثائق HTML | make html |
يمكنك إنشاء صورة قرص Ext2 وقراءتها في Cubit مع هذه الأوامر ، الموضحة هنا لقرص 128 ميغابايت:
dd if=/dev/zero of=vhd.img bs=1M count=128
mkfs -t ext2 -b 4096 vhd.img
mkdir vhd
mount -t auto -o loop vhd.img vhd
لديك الآن نظام ملفات فارغ في vhd/ يمكنك إضافة ملفات إلى الأذونات ، وما إلى ذلك ، وما إلى ذلك ، عند الانتهاء ، قم بإلغاء تثبيت الصورة. لاحظ أن تطبيق Cubit Ext2 يدعم حاليًا أحجام كتلة 4K فقط.
umount vhd
الآن لديك صورة قرص يمكنك تحويلها إلى تنسيق VirtualBox مع:
VBoxManage convertfromraw --format VDI vhd.img vhd.vdi
يمكنك إضافة القرص الجديد تحت التخزين -> وحدة تحكم IDE في إعدادات VM الخاصة بك. ربما سترغب في استخدام مجموعة شرائح ICH6. يستخدم Cubit حاليًا طريقة PIO القديمة لـ ATA I/O. إذا قمت بإنشاء صورة قرص وأضفتها إلى وحدة تحكم IDE مع مجموعة شرائح مختلفة ، فمن المحتمل أن تفشل القراءات.
لاحظ أن Cubit يقرأ للتو Ext2 Superblock حاليًا ، ولكن يتم إحراز تقدم مع دعم نظام الملفات الأساسي.
يرجى تجربة كميات مختلفة من ذاكرة الوصول العشوائي ، وعدد وحدات المعالجة المركزية ، إلخ.
VirtualBox هي أداة جيدة للاختبار ، ولكن QEMU لطيفة عندما تحتاج إلى استخدام GDB لتعقب بعض المشكلات. لاحظ أن Cubit يستخدم بعض ميزات وحدة المعالجة المركزية الحديثة إلى حد ما ، لذلك سترغب في إخبار Qemu باستخدام مجموعة شرائح ووحدة المعالجة المركزية الأحدث. يبدو أن خيارات -machine q35 و -cpu Broadwell تعمل بشكل جيد.
QEMU Command w/o debugger:
qemu-system-x86_64 -machine q35 -cpu Broadwell -m 64M -cdrom path/to/cubit_kernel.iso
نصائح GDB:
تسجيل add'l معلومات: سجلات rt : rg64 TRACE: k
لاستخدام QEMU لتصحيح:
qemu-system-x86_64 -machine q35 -cpu Broadwell -s -S -m 4G -cdrom pathtocubit_kernel.iso -serial stdio
ستبدأ Qemu في حالة توقف مؤقتًا بينما تنتظر تصحيح الأخطاء.
ثم قم بتشغيل GDB: gdb cubit_kernel (ملاحظة: لا ".iso" هنا ، نريد ملف كائن kernel نفسه ، والذي يحتوي على رموز تصحيح الأخطاء)
للاتصال بـ QEMU: target remote localhost:1234 استخدام (gdb) c للمتابعة.
من هنا ، تعمل أوامر GDB العادية ، مثل break ، x ، إلخ.
لاحظ أن Hyper-V لا يبدو أن يقوم بتمهيد .iso في الوقت الحالي. ينصح منصات المحاكاة الافتراضية أو المحاكاة الأخرى.
git clone https://github.com/Componolit/RecordFlux
install >= Python 3.6
install pip
install virtualenv if Python 3 not the default
source bin/activate
python setup.py build
python setup.py install
Now the rflx script at bin/rflx should work.