Understanding ReactOS' Boot Process

Here you can discuss ReactOS related topics.

Moderator: Moderator Team

Post Reply
berylliumquestion
Posts: 10
Joined: Sun Sep 01, 2019 12:59 am

Understanding ReactOS' Boot Process

Post by berylliumquestion » Fri Dec 13, 2019 12:17 am

So I've looked over the isoboot.S file a lot, and I think I've learned a bit about it. That file tells the computer how to load the contents of a cd into system memory, is that right? It's pretty low level, because it's makes a few BIOS interrupt calls here and there, mainly text video services and low level disk services.

There's just one part that confuses. This last line of code executed in isoboot.S that hands it off to the bootloader:

Code: Select all

.jump_to_setupldr:
    // Transfer execution to the bootloader.
    ljmp16 0, FREELDR_BASE
Which code file is this going to?

The other thing, is that I know that isoboot.S comes before winldr.c, but there's got to be at least one step between the two. What is in between isoboot.S and winldr.c?

Thank you for reading this post. :)

ThFabba
Developer
Posts: 285
Joined: Sun Jul 11, 2010 11:39 am

Re: Understanding ReactOS' Boot Process

Post by ThFabba » Fri Dec 13, 2019 12:53 pm

Freeldr.sys isn't a real .sys file, it is built by combining the binary file frldr16.bin and the PE file freeldr_pe.sys:

Code: Select all

    concatenate_files(
        ${CMAKE_CURRENT_BINARY_DIR}/freeldr.sys
        ${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin
        ${CMAKE_CURRENT_BINARY_DIR}/$<TARGET_FILE_NAME:freeldr_pe>)
And frldr16.bin is built as follows:

Code: Select all

    CreateBootSectorTarget(frldr16
        ${CMAKE_CURRENT_SOURCE_DIR}/arch/realmode/i386.S
        ${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin
        F800)
So this jump will go to RealModeEntryPoint in boot/freeldr/freeldr/arch/realmode/i386.S.

The code branch you mention in particular will use setupldr.sys rather than freeldr.sys, but it's the same concept (and the same frldr16.bin).

berylliumquestion
Posts: 10
Joined: Sun Sep 01, 2019 12:59 am

Re: Understanding ReactOS' Boot Process

Post by berylliumquestion » Fri Dec 13, 2019 11:54 pm

So the process looks something like this:
isoboot.S --> i386.S + freeldr.spec? --> ? --> freeldr.c --> winldr.c

The first 512 bytes of setupldr.sys is in fathelp.inc, which is mostly skipped over at the entrypoint 0000:FA00 with a .byte directive coded to go to 0000:FA00. I can't really tell what's trying to say other than from the comment attached to it.

Here's the two lines that I can't read, but I understand the comments.

Code: Select all

// This code is loaded at 0000:F800 so we have to
// encode a jmp instruction to jump to 0000:FA00
.byte HEX(e9), HEX(fd), HEX(01)

Code: Select all

.byte HEX(0ff), HEX(25) // opcode of indirect jump
I can't seem find the corresponding opcodes that matches the hex values in the Appendix A Opcode Map of Intel Developer's manual for either of them.



Now this part of the realmode/i386.S file seems kind of important. (I included a header file.)

boot/freeldr/freeldr/include/arch/pc/x86common.h:

Code: Select all

#define FREELDR_PE_BASE HEX(10000)
boot/freeldr/freeldr/arch/realmode/i386.S:

Code: Select all

add eax, FREELDR_PE_BASE

/* Save entry point */
mov dword ptr ds:[pm_entrypoint], eax

Code: Select all

inpmode:
    .byte HEX(0ff), HEX(25) // opcode of indirect jump
    word pm_entrypoint, 0
pm_entrypoint:
    .long 0 // receives address of PE entry point
    nop
Does this go to some other source file? Is it loading it into memory for later use?

After that I think it goes to boot/freeldr/freeldr/arch/i386/entry.S? I'm not entirely sure. I'm just going a little bit by the notes file in the boot/freeldr directory.

ThFabba
Developer
Posts: 285
Joined: Sun Jul 11, 2010 11:39 am

Re: Understanding ReactOS' Boot Process

Post by ThFabba » Sat Dec 14, 2019 11:35 pm

berylliumquestion wrote:
Fri Dec 13, 2019 11:54 pm
So the process looks something like this:
isoboot.S --> i386.S + freeldr.spec? --> ? --> freeldr.c --> winldr.c

The first 512 bytes of setupldr.sys is in fathelp.inc, which is mostly skipped over at the entrypoint 0000:FA00 with a .byte directive coded to go to 0000:FA00. I can't really tell what's trying to say other than from the comment attached to it.

Here's the two lines that I can't read, but I understand the comments.

Code: Select all

// This code is loaded at 0000:F800 so we have to
// encode a jmp instruction to jump to 0000:FA00
.byte HEX(e9), HEX(fd), HEX(01)

Code: Select all

.byte HEX(0ff), HEX(25) // opcode of indirect jump
I can't seem find the corresponding opcodes that matches the hex values in the Appendix A Opcode Map of Intel Developer's manual for either of them.
You're right about fathelp.inc -- so it doesn't go to RealModeEntryPoint directly. However it does go there _almost_ directly.

e9 is just the regular "jmp rel16" instruction. http://ref.x86asm.net/coder32.html is a relatively easy to read table. You can also use something like this:

Code: Select all

$ echo -ne "\xe9\xfd\x01" >tmpfile && objdump -D -bbinary -mi8086 tmpfile

tmpfile:     file format binary


Disassembly of section .data:

00000000 <.data>:
   0:   e9 fd 01                jmp    0x200
So _then_ it jumps to RealModeEntryPoint, which loads the address of the PE file's entry point:

Code: Select all

    /* Get address of entry point */
    mov eax, dword ptr es:[eax + IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint]
    add eax, FREELDR_PE_BASE

    /* Save entry point */
    mov dword ptr ds:[pm_entrypoint], eax
Then it jumps to exit_to_protected, as you pointed out:
berylliumquestion wrote:
Fri Dec 13, 2019 11:54 pm
Now this part of the realmode/i386.S file seems kind of important. (I included a header file.)

boot/freeldr/freeldr/include/arch/pc/x86common.h:

Code: Select all

#define FREELDR_PE_BASE HEX(10000)
boot/freeldr/freeldr/arch/realmode/i386.S:

Code: Select all

add eax, FREELDR_PE_BASE

/* Save entry point */
mov dword ptr ds:[pm_entrypoint], eax

Code: Select all

inpmode:
    .byte HEX(0ff), HEX(25) // opcode of indirect jump
    word pm_entrypoint, 0
pm_entrypoint:
    .long 0 // receives address of PE entry point
    nop
This one is harder to look up in the opcode table since 0xff corresponds to different instructions and the second byte is a bit field. The disassembler can do the work for us though:

Code: Select all

$ echo -ne "\xff\x25\x78\x56\x34\x12" >tmpfile && objdump -D -bbinary -mi386 -Mintel tmpfile

tmpfile:     file format binary


Disassembly of section .data:

00000000 <.data>:
   0:   ff 25 78 56 34 12       jmp    DWORD PTR ds:0x12345678
So it's just an indirect jump (32 bit protected mode now) to whatever is stored at pm_entrypoint.

To find out the PE file's entry point, we have to look at CMake again. The default for a .sys file is DriverEntry, but it's set manually in this case:

Code: Select all

set_image_base(freeldr_pe 0x10000)
set_subsystem(freeldr_pe native)
set_entrypoint(freeldr_pe RealEntryPoint)
So we look for RealEntryPoint, which as you correctly guessed is in entry.S.

That ends up jumping to BootMain, so we finally end up in C code: https://git.reactos.org/?p=reactos.git; ... 264a92#l43

berylliumquestion
Posts: 10
Joined: Sun Sep 01, 2019 12:59 am

Re: Understanding ReactOS' Boot Process

Post by berylliumquestion » Sun Dec 15, 2019 4:26 am

Thanks for the explanations, and the resources too!

Now, let's see if I've got the boot process that leads up to KERNEL_ENTRY_POINT correct. I'll also include the code lines that lead to the next file in the boot process

isoboot.S:

Code: Select all

ljmp16 0, FREELDR_BASE
i386.S:

Code: Select all

.byte HEX(0ff), HEX(25)
entry.S:

Code: Select all

call _BootMain
freeldr.c:

Code: Select all

RunLoader();
bootmgr.c:

Code: Select all

OSLoadingMethods[i]OSLoader(Argc, Argv, NULL);
winldr.c:

Code: Select all

KERNEL_ENTRY_POINT KiSystemStartup;
That last line of code points to this file --> kiinit.c

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 2 guests