flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
bzt 15 Jan 2024, 21:46
Hi,
I've created a simple and easy to use boot manager, Easyboot, which works on BIOS and UEFI machines as well (and on RPi, but that's not relevant here). I've also implemented an Easyboot plugin to boot MenuetOS 32 / 64 with this loader. This works very well, but sadly it is BIOS only. I wish to add UEFI support to it, but since MenuetOS64 is closed source, I'm not sure how to proceed. Can somebody help me? The most problematic part is, that the kernel's entry point is in real mode, and it calls some BIOS services before it switches to protected / long mode (which obviously doesn't exists on a UEFI system). For the records, I've already managed to do this for KolibriOS (a MenuetOS 32 fork), but since Kolibri is Open Source and most of the work were already done, that was pretty easy. The main required steps were: - adding the protected mode entry point in the kernel's header (so that loaders could skip the real mode part), but the kernel still starts with the real mode code for backward compatibility - all initialization code moved before that entry point, so protmode part now only relies on a BOOT_LO structure nothing else - in my loader's kolibri.c plugin I create exactly the same BOOT_LO struct that the real mode kernel part would, and I jump directly to the protected mode entry point - since my loader can create that BOOT_LO struct on BIOS as well as on UEFI machines, and the kernel's protmode code does not use any BIOS services, this means that the OS can be loaded on UEFI too out-of-the-box (tested, works like a charm). Is there a standardized way to boot MenuetOS under UEFI? And if not, is there any chance to apply similar changes to its kernel as described above? And please don't go mad, but would it be possible to Open Source MenuetOS64 kernel? Not the entire thing, just the initialization part? That way I could help with implementing UEFI support (I don't care how long mode is initialized, I'm only interested in finding the protmode entry point and what environment it expects, because there are surely no BIOS calls after that point, so boot firmware shouldn't matter for the rest of the code.) Cheers, bzt |
|||
![]() |
|
bzt 16 Jan 2024, 20:19
Ville wrote: I'll add the following header to next release, friday the latest. Ville wrote:
Ville wrote: When entering at protected_mode_entry_1, M64 expects that lgdt is loaded from lgdt_load_address and cr0 bit 0 is set and bits 29 and 30 are cleared. Is it okay if I don't set up the segment registers just the gdt? (The very first thing that Kolibri does at the protmode entry point is to set up segments, is this true to MenuetOS as well?) Ville wrote: boot_info_base defines the address for following structure and the loader must set the varibles marked with *. On Kolibri, all detection code has been removed from protmode code in kernel.asm; now E820 and EBDA parsing is done in bootbios.asm. So the protmode code just uses what's in BOOT_LO. On UEFI these values come from the boot loader, and again, the protmode code just uses what's in the boot structure (with the converted E820 memory map and ACPI pointer). There are no more firmware dependent things, just these two (actually there are, but those are already part of the boot structure). Cheers, bzt |
|||
![]() |
|
Ville 17 Jan 2024, 22:46
Great work, thanks! The header is now located at +8 of kernel.mnt file, but I recommend scanning for it. And no need to set the segment registers, since those are set at the protected mode entry. And boot_info_base does not have other parameters defined, so you can return the memory map pointer and both RSD PTR and RSDT/XSDT pointers to boot_info_base +0x70, +0x78 and +0x80.
|
|||
![]() |
|
bzt 19 Jan 2024, 01:17
Great! I have a few more questions though.
Ville wrote: you can return the memory map pointer Code: qword base_address ; in bytes qword length ; in bytes dword type ; E820 type code dword padding ; always 0 on BIOS, but I can put the UEFI type code here on UEFI Code: dword magic ; always 6 dword size ; size of the block in bytes dword reclen ; size of one record in bytes, always 24 dword padding ; always 0 ; memory map records, (size - 16) / 24 times Code: word numrec ; memory map records, numrec times Third option is to always terminate the list with full zero record (base_address and type can be zero, but normally length can't be). Fourth possible option is to add numrec directly to boot_info. Even adding it to the most significant 16 bits of memory map pointer makes sense, because it's unlikely that any boot loader would allocate this above 4G, much less above 256T. So +70 .. +75 pointer, +76 .. +77 number of entries. (This is tricky, but does not increase the size of boot_info and also keeps its fields 8-bytes aligned.) Fifth option (this is what Kolibri does) that boot_info has the numrec as its very last field, there's no memory map pointer, rather the memory map records follow the boot_info struct directly (I personally think having a memory map pointer in boot_info is a more flexible and more future proof solution). It also has 20 bytes per records (so there's no padding field), which is more compact, but makes the records unaligned. It really doesn't matter to me which one you prefer (you could also come up with a total different approach). For example, in the boot protocol that I've designed, length must be multiple of 16 bytes, and type is stored in its lowest 4 bits. Ville wrote: both RSD PTR and RSDT/XSDT pointers to boot_info_base +0x70, +0x78 and +0x80. To sum it up, does this work for you? Code: +0x70 pword memory_map_ptr ; with 24 bytes records (qword base, qword length, dword type, dword padding) +0x76 word num_memory_map ; number of records +0x78 qword rsdp_ptr ; pointer to RSD PTR (with a pointer to RSDT/XSDT inside) Cheers, bzt |
|||
![]() |
|
Ville 19 Jan 2024, 16:53
Multiboot2 section 3.6.8 memory map (8+8+4+4) is fine by me. And I would also include the number of entries to boot_info and use qword alignment for all parameters.
The header is now labeled "PMENTRY0". Included is a test image with "PMENTRY0" struct at +8 of kernel.mnt. Version has multiprocessor support disabled for now, since some of the initialization is done at the 16bit code. Also the test image does not yet have memory map tests. M64 uses memory from 0x8000-0x58000, 1MB-13.99MB and 16MB - amount_of_ram defined at config.mnt. Code: +0x70 qword memory_map_ptr ; with 24 bytes records (qword base, qword length, dword type, dword padding) +0x78 qword num_memory_map ; number of records +0x80 qword rsdp_ptr ; pointer to RSD PTR (with a pointer to RSDT/XSDT inside)
|
|||||||||||
![]() |
|
bzt 22 Jan 2024, 12:52
Hi Ville,
Thanks! Sorry for the delay, I'm rather busy with other projects. I've checked the attachment, but now I have a problem with identifying the MenuetOS kernel. The KERNEL.MNT used to look like this: Code: 00000000 e9 e6 07 4d 65 6e 75 65 74 4f 53 20 36 34 62 69 |...MenuetOS 64bi| 00000010 74 20 76 31 2e 34 39 0d 0a 0d 0a 00 00 00 00 00 |t v1.49.........| 00000020 00 00 00 00 4e 6f 20 32 34 20 6f 72 20 33 32 20 |....No 24 or 32 | Code: 00000000 e9 0f 08 90 90 90 90 90 50 4d 45 4e 54 52 59 30 |........PMENTRY0| 00000010 78 18 01 00 40 18 01 00 00 90 00 00 00 00 01 00 |x...@...........| 00000020 00 40 05 00 00 00 10 00 20 1c 01 00 4d 65 6e 75 |.@...... ...Menu| My question is, would it be possible to keep the MenuetOS identification string and version as they were, at offset 3 and move PMENTRY0 instead? Something like: Code: 00000000 e9 0f 08 4d 65 6e 75 65 74 4f 53 20 36 34 62 69 |...MenuetOS 64bi| 00000010 74 20 76 31 2e 34 39 0d 0a 0d 0a 00 00 00 00 00 |t v1.49.........| 00000020 50 4d 45 4e 54 52 59 30 78 18 01 00 40 18 01 00 |PMENTRY0x...@...| 00000030 00 90 00 00 00 00 01 00 00 40 05 00 00 00 10 00 |.........@......| 00000040 20 1c 01 00 4e 6f 20 32 34 20 6f 72 20 33 32 20 | ...No 24 or 32 | What are your thoughts on this? bzt |
|||
![]() |
|
Ville 23 Jan 2024, 22:43
Sounds good! In the included version PMENTRY0 is located at +0x20 and kernel version at +0x3. Also SMP is now enabled when [boot_info_base+0x68] is set to 1. SMP code checks if "RSD PTR " is located at [rsdp_ptr] and if not, the code falls back to scanning for the header. I'll add the memory checks next.
|
|||||||||||
![]() |
|
bzt 24 Jan 2024, 10:10
Hi Ville,
Ville wrote: Sounds good! In the included version PMENTRY0 is located at +0x20 and kernel version at +0x3. Ville wrote: Also SMP is now enabled when [boot_info_base+0x68] is set to 1. Ville wrote: SMP code checks if "RSD PTR " is located at [rsdp_ptr] and if not, the code falls back to scanning for the header. And now about your attachment, I've tested it. It works in real mode on BIOS (as it did), but also using the protmode entry on BIOS! MenuetOS boots up nicely and quickly and it uses the framebuffer that the loader passes! So this part is a success. On UEFI however, it hangs. Not sure what's going on, the kernel is booted as it should, it can find the config and the ramdisk, it even switches to long mode, but then nothing happens. Nontheless I've uploaded the new plugin, because I believe it probably is okay and should work correctly (let me know if it doesn't!), and also so that you could play with it. For debugging, your PMENTRY0 is loaded at 6F8h (so that pm_entry1 is at 700h). I've also put a "jmp $" in the plugin right before it would transfer control over and created a register and memory dump for you, both on BIOS and UEFI. I've also attached a memory dump when the kernel freeze. I hope these would help you with your debugging. Edit: hmm, looks like the 64Mb memory dump was too big for this forum, I had to remove it. Anyway, here's a 4Mb dump right before control is transfered to the kernel, on both BIOS and UEFI, so that you can compare them. Oh, one more thing: Easyboot sets up dummy exception handlers, so you could see if there were any, but no indication of that. Of course this works only up to the point where you set up your own IDT (which I'm not sure if happens before or after the hang), so I've also tried qemu with -d int, no exceptions. It just hangs at 22863c3h, very much above your kernel's binary, I don't know how execution got there, but maybe you do. Good luck with your debugging, and let me know if I can help with anything! Cheers, bzt
|
|||||||||||||||||||||||||||||||
![]() |
|
Ville 25 Jan 2024, 16:20
Thats excellent news! I also have UEFI booting working with the included pre3 files (in qemu). M64 PM-entry simply clears unused variables at boot_info and both entry points now have the same target address. And transparency and SMP work fine when qemu is started with the following options. Memory map checks are not yet included.
qemu-system-x86_64 -bios uefi.bin -m 640 -drive file=disk.img,format=raw -serial stdio -smp 2
Last edited by Ville on 27 Jan 2024, 13:11; edited 1 time in total |
|||||||||||
![]() |
|
bzt 27 Jan 2024, 01:05
Hi Ville,
I've tested this latest attachment and I can confirm that it works perfectly! - BIOS with real mode: works! - BIOS with protmode entry: works! - UEFI with protmode entry: works! Well done! This is excellent news! |
|||
![]() |
|
Chrisw2011 08 Mar 2025, 02:00
How to use easyboot please? I can seem to get it to boot. Is there a bootx64.efi loader that must go into efi/boot
|
|||
![]() |
|
bzt 08 Mar 2025, 10:42
Chrisw2011 wrote: Is there a bootx64.efi loader that must go into efi/boot Chrisw2011 wrote: How to use easyboot please? Let's assume you create a directory named "boot", in this case here are all the required files: - boot/KERNEL.MNT - the MenuetOS kernel file. - boot/CONFIG.MNT - the MenuetOS configuration file. - boot/RAMDISK.MNT - the MenuetOS ramdisk file. - boot/easyboot/menuetos.tga - MenuetOS icon from here (or use any icon you'd like). - boot/easyboot/menuet_x86_64.plg - the Easyboot plugin to parse and load MenuetOS kernels. - boot/easyboot/menu.cfg - the Easyboot menu configuration, see example here (full doc here). Code: # this is just an example, you might create multiple boot options menuentry menuetos { kernel KERNEL.MNT module CONFIG.MNT module RAMDISK.MNT } Once you have these files in the "boot" directory, just run the disk creator tool Code: easyboot boot diskimage.iso And that's all. This will create a bootable disk image with a GPT partitioning table and a FAT formatted EFI System Partition. It will copy all files from the "boot" directory into that partition, along with the required loader binaries. There's no difference between BIOS boot and UEFI boot, Easyboot (and its menuet plugin) is written in a way to work on both platforms out-of-the-box. The created image is multi-bootable, no matter the firmware. ps: for advanced users, MenuetOS options can be passed in menu.cfg on the "kernel" line, for example Code: kernel KERNEL.MNT noauto real ps2: I've attached an example diskimage.iso that I've just created. Tested with "qemu-system-x86_64 diskimage.iso". Hope this helps, bzt
|
|||||||||||
![]() |
|
Chrisw2011 08 Mar 2025, 21:43
Hi thanks. Got it to work in qemu eventualy - it was stalling on Initializing CD/DVD on the boot screen, had to change
auto_configuration = 00000000 in the config.mnt file then booted straight away. Cant get it to boot natively from usb though as it sticks on easyboot loader parsing kernel...... Any solution for this |
|||
![]() |
|
bzt 10 Mar 2025, 13:03
Chrisw2011 wrote: Hi thanks. Got it to work in qemu eventualy - it was stalling on Initializing CD/DVD on the boot screen Chrisw2011 wrote: Cant get it to boot natively from usb though as it sticks on easyboot loader parsing kernel...... Easyboot has been tested by many volunteers on many computers and with many OSes, but I still can't guarantee that it will work in all possible scenarios. If you provide detailed information on how to reproduce your issue, then I can take a look. First, does the exact same image work in qemu using the same firmware? What firmware is you machine using? BIOS or UEFI? What is the firmware brand and version? Second, what can you see if you add "verbose 3" to the easyboot/menu.cfg file? (This latter should print out detailed boot messages. Could you attach a photo of these messages perhaps?) Third, how did you write the image to the USB stick? Did you use the easyboot tool with a device file or did you use dd? If the former, then did the stick already had GPT and ESP? Anyway I need more info in order to help with the issue. ps: to test the image in qemu under UEFI, you'll have to download the OVMF.fd file from the official UEFI site and run qemu as "qemu -m 64 -bios path/to/your/OVMF.fd diskimage.iso" (the "-m 64" flag is not mentioned in the doc, but it is needed because UEFI requires at least 64 megabytes of memory. The "-bios OVMF.fd" flag can be ommited if you rename OVMF.fd to bios.bin and place it in the appropriate directory. I personally wouldn't recommend that, as using a flag is simple and more flexible). ps2: if you have used the easyboot tool with a device file to install the loader on the USB stick, then could you please repeat it with the "easyboot -vv ..." flag? This will do extra validation and will print verbose messages of the installation process. |
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.