ویرگول
ورودثبت نام
Sirous
Sirous
خواندن ۳ دقیقه·۵ سال پیش

اضافه کردن ماشین جدید به qemu

اولش بگم اینا همه برداشت‌های منه و ممکنه درست نباشه! یکی از شبیه‌سازهای کامپیوتر خیلی پرکاربرد qemu (مخفف Quick Emulator) هستش. به کمک kvm توی خیلی ‌جا ها استفاده می‌شه. به صورت پیشفرض یه قسمتیش به TCG وضیفه اجرای دستورالعمل‌های پردازنده‌ها رو داره ولی kvm کمک می‌کنه بهش که به جای TCG از تکنولوژی‌های مجازی سازی اینتل و AMD (VT-X و AMD-V) استفاده کنه و بقیه بخشا رو خود qemu شبیه سازی می‌کنه (مثل pci، usb و ...). یکی از قابلیت‌هاش شبیه سازی پردازنده‌های مبتنی بر هسته‌های cortex-m3 و cortex-m4 هستش ولی به جز Texas Instruments بقیه سازنده‌ها، میکروکنترلر‌های خودشونو به کد‌های qemu اضافه نکردن. توی این نوشته و چند تا بعدیش من می‌خوام سعی کنم میکروکنترلر خودمو به qemu اضافه کنم. منظورم از میکروکنترلر خودم اینه که سعی می‌کنم خودم چند تا پریفرال میکرو مثل gpio، uart و ... رو بنویسیم.

داکیومنتی برای qemu توی اینترنت پیدا نمیشه (یا حداقل من پیدا نکردم). برای این کار یا باید از بقیه کد بقیه دستگاه‌ها استفاده کرد یا از سایتایی مثل stackoverflow استفاده کرد.

اگر کد‌های دستگاهی مثل zynq رو ببینیم آخرش این شکلیه:

static void zynq_machine_init(MachineClass *mc) { mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; mc->init = zynq_init; mc->max_cpus = 1; mc->no_sdcard = 1; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); } DEFINE_MACHINE("xilinx-zynq-a9", zynq_machine_init)

این که اون DEFINE_MACHINE چجوری کار می‌کنه رو توی نوشته‌های بعدی شاید توضیح بدم. اما نکته مهم اینه که اون mc->init تابعیه که باید ماشین رو اینتیت کنه برای ماشین من میشه یه همچین چیزی:

static void myMachineClassInit(MachineClass *mc) { mc->desc = "This is my machine!"; mc->init = myMachineInit; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3"); } DEFINE_MACHINE("My Machine", myMachineClassInit)

تابع myMachineInit هم توی این پست فقط نوع پردازنده و فلش و رم میکرو رو مشخص می‌کنیم. توی qemu پردازنده و پریفرالا و ... همه یه «نوع» هستند. در واقع ماشین هم یه نوع که اون DEFINE_MACHINE کارش اضافه کردنش به کد اصلی هستش. تابع myMachineInit هم این شکلی میشه:

static void myMachineInit(MachineState *ms) { DeviceState* nvic; MemoryRegion *sram = g_new(MemoryRegion, 1); MemoryRegion *flash = g_new(MemoryRegion, 1); MemoryRegion *system_memory = get_system_memory(); memory_region_init_ram(flash, NULL, "my_machine.flash", MY_MACHINE_FLASH_SIZE, &error_fatal); memory_region_set_readonly(flash, true); memory_region_add_subregion(system_memory, 0, flash); memory_region_init_ram(sram, NULL, "my_machine.sram", MY_MACHIN_SRAM1_SIZE, &error_fatal); memory_region_add_subregion(system_memory, 0x20000000, sram); nvic = qdev_create(NULL, TYPE_ARMV7M); qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES); qdev_prop_set_string(nvic, "cpu-type", ms->cpu_type); qdev_prop_set_bit(nvic, "enable-bitband", true); object_property_set_link(OBJECT(nvic), OBJECT(get_system_memory()), "memory", &error_abort); qdev_init_nofail(nvic); armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, MY_MACHINE_FLASH_SIZE); }

کد بالا تقریبا همه چیش معلومه. اول حافظه اصلی و زیر بخشاش (فلش و رم رو تعریف می‌کنه). بعد پارامتر‌های هسته‌ رو تنظیم می‌کنه. در آخر هم فایل برنامه رو توی فلش لود می‌کنه.

این فایلو تو این آدرس کاملشو می‌تونید ببینید. حالا باید این فایلو به لیست فایلایی که بیلد میشن اضافه کنیم. سیستم بیلد qemu مثل سیستم بیلد کرنل لینوکسه. کاری که باید کرد اینه که این فایلو به hw/arm/Makefile.objs اضافه کرد. این جوری‌ (اسم فایلو میذاریم hw/arm/my_machine.c) هستش:

obj-$(CONFIG_MY_MACHINE) += my_machine.o

بعدش باید تو hw/arm/kconfig این خط‌ها رو اضافه کنیم تا بدونه این فایل به چه فایل‌های دیگه‌ای نیاز داره:

config MY_MACHINE bool select ARM_V7M select CMSDK_APB_WATCHDOG

آخر هم باید بگیم می‌خوایم این فایلا تو کدوم برنامه‌هایی که ساخته می‌شن وجود داشته باشن. چون من اینو از روی کد‌های دستگاه‌های تگزاس بوده منم توی همون برنامه‌ای که اونا ساخته می‌شدن این دستگاه رو اضافه می‌کنم. برای میکرو‌های تگزاس توی فایل arm-softmmu هستش.

برای این کار فایل default-configs/arm-softmmu.mak این خطو اضافه می‌کنیم:

CONFIG_MY_MACHINE=y

حالا باید کد رو دوباره بیلد کنیم. اینم نتیجه:

تغییراتی که توی این نوشته دادم توی این کامیت معلومن. توی نوشته بعدی سعی می‌کنم پریفرالUART به این دستگاه اضافه کنم.

شاید از این پست‌ها خوشتان بیاید