Page 1 of 2
How to exec one kernel from inside another ?
Posted: Fri Jul 18, 2008 11:14 am
by sawdust
How do I exec one kernel from inside another ? e.g. I'm running say, pyros 1.0 and have binary of another version, say 2.0 kernel in a known location in the had disk.
A small driver copies that image and puts it in some memory location. Now if I want to exec the 2.0 kernel so that it takes complete control and starts to run, what should be done? Any help is appreciated.
Thanks in advance.
Re: How to exec one kernel from inside another ?
Posted: Fri Jul 18, 2008 11:42 am
by itisiuk
sounds like a virtual machine if im not mistaken.
and by that u may want to look at the source code for qemu or bochs or something like that.
Re: How to exec one kernel from inside another ?
Posted: Fri Jul 18, 2008 12:05 pm
by Adek336
No, I think he means aborting kernel_1 and booting kernel_2. Well I believe you'd need a function, say, kexec, which you make sure is in a memory place which will not be overwritten by kernel_2 and make sure that GDT will not be overwritten, same for IDT or turn off interrupts, then copy the kernel to the place it expects to be and do a jmp or something.
There are some complications as kernel_2 may expect hardware to be in an after-boot state so you might need to set the hardware to that state before passing control to kernel_2.
Re: How to exec one kernel from inside another ?
Posted: Fri Jul 18, 2008 12:44 pm
by itisiuk
soz my bad, i misunderstood what you ment.
for this you could map the new kernel into a region of mem using paging the load the effective address of new kernel into a register then jmp to that location.
1:1 mapping is probably best for this.
e.g.
lea eax, [newlocation]
jmp eax
and as Adek336 has said, you need to make sure the old kernel has setup the hardware state required by the new kernel.
i.e if paging is turned off when the new kernel 1st starts to run then youll need to make sure you turn paging off before you run the new kernel.
Re: How to exec one kernel from inside another ?
Posted: Mon Jul 21, 2008 9:27 am
by sawdust
My gmail was sending the replies to Spam
.
As Adek336 said, I want to abort kernel_1 and jump and execute kernel_2. Yes. Hardware is already setup. I would want to load new GDT and IDT with new ISRs. I want to serve Interrupt services from kernel_2.
Re: How to exec one kernel from inside another ?
Posted: Mon Jul 21, 2008 9:40 am
by lukem95
overwrite the original kernel image on the HDD, then reboot
Re: How to exec one kernel from inside another ?
Posted: Mon Jul 21, 2008 10:02 am
by sawdust
lukem95 wrote:overwrite the original kernel image on the HDD, then reboot
Nope!. I don't want to reboot. Only 'exec'
Re: How to exec one kernel from inside another ?
Posted: Mon Jul 21, 2008 10:31 am
by inflater
A quick and dirty way:
1. Add into your second kernel a "EXIT" function, which does the same as in the part 4.
2. Run your first kernel and copy the
whole kernel somewhere in free memory. Something like relocation, but don't free your first kernel's occupied memory. Now, jump to the relocated part.
3. In your first kernel's relocated part, load the second kernel at ORG, where the first kernel is loaded. Then, run the second kernel by CALLing
4. When the "EXIT" function is called in your second kernel, relocate the following "code-copying" routines somewhere in the free memory, then JMP to them. In there, load the first kernel from it's original relocation and copy it to the second kernel's ORG. Then run it by restoring the first kernel's EIP, which should point
right after e.g. "call RunSecondKernel" - make sure your stack is alright.
5. In your first kernel, free the relocated space and the relocated "code-copying" routines. (Not necessary.)
In this example, I assume that the ORG of both kernels are the same.
I highly recommend that your kernels are in assembly though.
C/C++ is too high level to do that.
I've added an example code, but it's untested.
Code: Select all
*** First kernel ****
call RelocateFirstKernel ;e.g. copy your first kernel to 0x100000
...
*** this is the Load second kernel function ****
LoadThe2ndKernel:
jmp LoadThe2ndKernel+0x100004 ;jump to the relocated part at address 0x100000 plus this label's offset
;but SKIP the JMP opcode in the reloc part!!! thats because its 0x100004
....
*** this is where it should begin ***
call LoadTheSecondKernelFromHDD ;e.g. load your second kernel to first's ORG, thus overwriting the first to save RAM
;but no worries, since we are in the relocated part
call dword[FirstKernel_Org] ;call the first kernel's ORG to load the 2nd one
*** in the 2nd kernel at the beginning ****
mov esi,SecondKernel_CodeCopy
mov ecx,0x200
mov edi,0x200000 ;reserve 512 bytes of the code copying routines and relocate to the 2nd megabyte
rep movsb
...
*** the code copying routines, DO NOT execute them directly as you'll overwrite the 2nd kernel ***
...
SecondKernel_CodeCopy:
mov esi,0x100000 ;load the first kernel from the relocated part (1st megabyte)
mov ecx,Size_of_your_first_kernel_in_bytes
mov edi,[FirstKernel_Org]
rep movsb
...
;MAKE SURE YOUR STACK ISN'T SCREWED HERE!
;EVERY PUSH, PUSHAD, PUSHA etc MUST HAVE CORRESPONDING POP, POPAD, POPA, etc. !!!
ret ;This should return right after the "call RunSecondKernel", if your stack contents are alright.
...
** Second kernel's EXIT function ****
jmp sys_code:0x200000 ;sys_code is your CS selector
Re: How to exec one kernel from inside another ?
Posted: Mon Jul 21, 2008 12:39 pm
by sawdust
inflater wrote:A quick and dirty way:
1. Add into your second kernel a "EXIT" function, which does the same as in the part 4.
2. Run your first kernel and copy the whole kernel somewhere in free memory. Something like relocation, but don't free your first kernel's occupied memory. Now, jump to the relocated part.
3. In your first kernel's relocated part, load the second kernel at ORG, where the first kernel is loaded. Then, run the second kernel by CALLing
4. When the "EXIT" function is called in your second kernel, relocate the following "code-copying" routines somewhere in the free memory, then JMP to them. In there, load the first kernel from it's original relocation and copy it to the second kernel's ORG. Then run it by restoring the first kernel's EIP, which should point right after e.g. "call RunSecondKernel" - make sure your stack is alright.
5. In your first kernel, free the relocated space and the relocated "code-copying" routines. (Not necessary.)
In this example, I assume that the ORG of both kernels are the same.
Thanks a lot for your time inflater
. I'll give this one a try and let you know.
Re: How to exec one kernel from inside another ?
Posted: Mon Jul 21, 2008 4:32 pm
by iammisc
linux has a similar mechanism to this called kexec. Why don't you research how linux does that?
Re: How to exec one kernel from inside another ?
Posted: Tue Jul 22, 2008 9:15 am
by inflater
Who cares about linux?
Re: How to exec one kernel from inside another ?
Posted: Tue Jul 22, 2008 11:59 am
by Adek336
nobody but we care about kexec
Re: How to exec one kernel from inside another ?
Posted: Fri Aug 01, 2008 9:55 am
by sawdust
I did the following
first_kernel ORG = 0x200000 (@ 2MB)
second_kernel ORG = 0x39b00000 (begins at last 100MB of 1GB)
With the following code, I got an exception 'Invalid Opcode - code 0'. I was assuming that with jmp to the second_kernel's ORG, it should start executing.
Any help would be greatly appreciated.
Code: Select all
static uint32_t _secondKernelEntry;
void cmain(unsigned long magic, multiboot_info_t *mbinfo)
{
Elf32_Ehdr* ehdr;
unsigned char *secondKernelImage = (unsigned char *)0x39b00000;
..........
// This function reads 256 sectors (128 KB) to memory area secondKernelImage
readSectors(startSector,sectorCount);
......
....
// cast the 2nd kernel image to elf header
ehdr = (Elf32_Ehdr *)(secondKernelImage);
// get entry point of kernel_2
_secondKernelEntry = ehdr->e_entry;
printf("elf entry=0x%x\n",_secondKernelEntry);
__asm__ __volatile__(
" cld \n\t"
" pushl %esi\n\t"
" pushl %edi\n\t"
" pushl %ebx\n\t"
" pushl %eax\n\t"
" push %gs\n\t"
" push %fs\n\t"
" push %ds\n\t"
" push %es\n\t"
" leal _secondKernelEntry ,%eax\n\t"
" jmp *(%eax)\n\t" /*'call' gives GPF */
" pop %es\n\t"
" pop %fs\n\t"
" pop %gs\n\t"
" popl %eax\n\t"
" popl %ebx\n\t"
" popl %edi\n\t"
" popl %esi\n\t"
);
printf ("should not come here");
........
.......
return;
}
Re: How to exec one kernel from inside another ?
Posted: Fri Aug 01, 2008 10:01 am
by inflater
Try to set both ORG's the same. And also I'm not really sure about ELF, I suggest to use binary format. Plus, running it in inline assembly is not a good idea, too.
Re: How to exec one kernel from inside another ?
Posted: Fri Aug 01, 2008 11:49 am
by JJeronimo
itisiuk wrote:and as Adek336 has said, you need to make sure the old kernel has setup the hardware state required by the new kernel.
i.e if paging is turned off when the new kernel 1st starts to run then youll need to make sure you turn paging off before you run the new kernel.
IMHO makes much more sense inventing a "hot load" protocol for the kernel.
This could include a special entry point for hot boots (or a special boot-time parameter so that the kernel knows it's being executed from inside a running system), that would skip paging and memory initialization. Additional information could also be passed, such as addresses for kernel structures and stuff alike.
*Skipping* driver initialization seems to be the difficult part. However, if a hot-swappable kernel fails to support this, the entire feature can become in part void (because the advantage of a kexec-like feature is precisely avoiding the delays introduced by system reboots).
Here, a microkernel has the advantage of allowing to fastly replace the micro-kernel (which needs minimal initialization, because it is micro
), and then replace the servers one-at-a-time, thus allowing for +/- continuous system responsiveness.
The problem is that some drivers may need to re-initialize it's hardware, and others may not need. Also, the same problem arises if you change e.g. the memory management structure's layout. The trick could be controlling this in a drive-by-drive fashion, and forbidding "hot swaps" if a critical kernel structure was modified.
I don't know how linux kexec works and never tried to use it.
JJ