The path of the binary to load in the KFS is given via the command line. It’s an ELF file.
In K, since you just need to load an ELF file and execute it, only the segments
are interesting. So the first thing is to get the program header table and its
size, fortunately, those information are present in the ELF main header. After
getting the program header table, you just have to load every segment marked as
PT_LOAD at the good memory address.
Don’t forget that in K, the data segment and the code segment are separated,
both in memory, with the help of the segmented memory, and in the ELF file. To
determine if an ELF segment is a code one, take a look at
PF_X defined in the
elf.h header. Due to the
sbrk() system call, the data segment should
physically be located above the code segment, so that this segment
could be expanded.
NAME sbrk - change data segment size SYNOPSIS void *sbrk(ssize_t increment); DESCRIPTION sbrk() increments the program's data space by increment bytes. Calling sbrk() with an increment of 0 can be used to find the current location of the program break. RETURN VALUE sbrk() return the old break value.
Jumping into userland
Once you’ve loaded the binary into memory, with separate segment for code and data, you should be able to execute the rom code. This code should run in ring3, so it means that it should be unprivilegied.
The pseudo-code that needs to be executed to launch an unprivilegied program is the following:
ds <- DS_USER | RING3_DPL ss <- DS_USER | RING3_DPL esp <- lower_address_of_elf_data_segment eflags <- enable_interrupts cs <- CS_USER | RING3_DPL eip <- rom_entry
This code should be atomic which means that it should be run on one instruction.
Unfortunately you cannot do that directly on x86. However it can be done with
the help of the
iret instruction. By simulating a return from interrupt, with
an hand crafted stack, the processor will set
eip from values taken on the stack. The only missing register here is
which can be set just before executing the
iret instruction as it doesn’t use
it. The layout of the stack on interrupt can be found on the
Possible bug causes
- You may have loaded some segments at the wrong place.
- Some segments have a memory occupation greater than their file occupation (think of the .bss section).
- Your filesystem code may be wrong.