From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1KOhr7-0001A6-M3 for mharc-grub-devel@gnu.org; Thu, 31 Jul 2008 19:46:49 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KOhr4-00019m-Vg for grub-devel@gnu.org; Thu, 31 Jul 2008 19:46:47 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KOhr3-00019Q-0l for grub-devel@gnu.org; Thu, 31 Jul 2008 19:46:46 -0400 Received: from [199.232.76.173] (port=39862 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KOhr2-00019N-Py for grub-devel@gnu.org; Thu, 31 Jul 2008 19:46:44 -0400 Received: from aybabtu.com ([69.60.117.155]:37168) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1KOhr2-0005Wq-DU for grub-devel@gnu.org; Thu, 31 Jul 2008 19:46:45 -0400 Received: from [192.168.10.10] (helo=thorin) by aybabtu.com with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1KOhk4-0005vz-Tf; Fri, 01 Aug 2008 01:39:33 +0200 Received: from rmh by thorin with local (Exim 4.63) (envelope-from ) id 1KOhpq-0004xl-6P; Fri, 01 Aug 2008 01:45:30 +0200 Date: Fri, 1 Aug 2008 01:45:30 +0200 From: Robert Millan To: The development of GRUB 2 Message-ID: <20080731234530.GA18681@thorin> References: <20080719230622.GA17043@thorin> <200807201109.03173.okuji@enbug.org> <20080727213949.GA24562@thorin> <20080730191510.GA18619@thorin> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="ibTvN161/egqYuK8" Content-Disposition: inline In-Reply-To: <20080730191510.GA18619@thorin> Organization: free as in freedom X-Message-Flag: Worried about Outlook viruses? Switch to Thunderbird! www.mozilla.com/thunderbird X-Debbugs-No-Ack: true User-Agent: Mutt/1.5.13 (2006-08-11) X-detected-kernel: by monty-python.gnu.org: Genre and OS details not recognized. Cc: "Yoshinori K. Okuji" Subject: Re: loadee relocation (Re: loader modules jumping back to kernel) X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 31 Jul 2008 23:46:47 -0000 --ibTvN161/egqYuK8 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, Jul 30, 2008 at 09:15:10PM +0200, Robert Millan wrote: > > Let's try to revive this discussion. Here's a patch I made a while ago that > implements support for loading at any address. It works by having a "special" > version of malloc() that is told to allocate a chunk of memory that does > _not_ overlap with a specific region. It does so by iteratively reserving > memory (and keeping track of what was reserved, of course). > > Then we use this function to allocate the asm relocator code in heap, asking > it to garantee that it won't overlap with our final destination. Finally, > our loadee can be put anywhere (e.g. in heap), and we just jump to the > relocator which will jump to the loadee. > > But I really find the approach really ugly. What do you think? If we agree > that this is the way to go, I can do some cleanup & update it to current svn > for a merge. Here's a new patch, with the following approach. We put this in a single heap area: we pick the relocator we want depending on wether we want to copy to a lower or higher address. This garantees that the relocator itself isn't overwritten. Then we set cpu context appropiately, and jump. I like this much better. Also, it doesn't depend on the static OS load area. Some doubts: - What to do about physical_entry_addr now? My patch currently discards it, which I suppose is not what we want. - Should we do the same for the elf64 loader? And how? I don't know of any example ELF64 images I could test with. -- Robert Millan The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and how) you may access your data; but nobody's threatening your freedom: we still allow you to remove your data and not access it at all." --ibTvN161/egqYuK8 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="relocate_payload.diff" Index: kern/i386/loader.S =================================================================== --- kern/i386/loader.S (revision 1755) +++ kern/i386/loader.S (working copy) @@ -123,6 +123,13 @@ * This starts the multiboot kernel. */ +VARIABLE(grub_multiboot_payload_size) + .long 0 +VARIABLE(grub_multiboot_payload_orig) + .long 0 +VARIABLE(grub_multiboot_payload_dest) + .long 0 + FUNCTION(grub_multiboot_real_boot) /* Push the entry address on the stack. */ pushl %eax @@ -138,9 +145,16 @@ /* Move the magic value into eax and jump to the kernel. */ movl $MULTIBOOT_MAGIC2,%eax - popl %ecx - jmp *%ecx + /* Where do we copy what from. */ + movl EXT_C(grub_multiboot_payload_size), %ecx + movl EXT_C(grub_multiboot_payload_orig), %esi + movl EXT_C(grub_multiboot_payload_dest), %edi + + /* Jump to the relocator. */ + popl %edx + jmp *%edx + /* * This starts the multiboot 2 kernel. */ Index: include/grub/i386/pc/kernel.h =================================================================== --- include/grub/i386/pc/kernel.h (revision 1755) +++ include/grub/i386/pc/kernel.h (working copy) @@ -86,6 +86,10 @@ extern grub_addr_t EXPORT_FUNC(grub_arch_memdisk_addr) (void); extern grub_off_t EXPORT_FUNC(grub_arch_memdisk_size) (void); +extern grub_addr_t EXPORT_VAR(grub_multiboot_payload_orig); +extern grub_addr_t EXPORT_VAR(grub_multiboot_payload_dest); +extern grub_size_t EXPORT_VAR(grub_multiboot_payload_size); + #endif /* ! ASM_FILE */ #endif /* ! KERNEL_MACHINE_HEADER */ Index: loader/i386/pc/multiboot.c =================================================================== --- loader/i386/pc/multiboot.c (revision 1756) +++ loader/i386/pc/multiboot.c (working copy) @@ -50,6 +50,28 @@ static struct grub_multiboot_info *mbi; static grub_addr_t entry; +static char *playground = NULL; +extern char *grub_multiboot_payload_orig, *grub_multiboot_payload_dest; +extern grub_size_t grub_multiboot_payload_size; + +static grub_uint8_t forward_relocator[] = +{ + 0xfc, /* cld */ + 0x89, 0xf2, /* movl %esi, %edx */ + 0xf3, 0xa4, /* rep movsb */ + 0xff, 0xe2, /* jmp *%edx */ +}; + +static grub_uint8_t backward_relocator[] = +{ + 0xfd, /* std */ + 0x01, 0xce, /* addl %ecx, %esi */ + 0x01, 0xcf, /* addl %ecx, %edi */ + 0x41, /* incl %ecx */ + 0xf3, 0xa4, /* rep movsb */ + 0xff, 0xe7, /* jmp *%edi */ +}; + static grub_err_t grub_multiboot_boot (void) { @@ -118,35 +140,50 @@ phdr_base = (char *) buffer + ehdr->e_phoff; #define phdr(i) ((Elf32_Phdr *) (phdr_base + (i) * ehdr->e_phentsize)) + + { + /* Find the highest address claimed by our payload. */ + char *end_addr = NULL; + for (i = 0; i < ehdr->e_phnum; i++) + { + grub_addr_t addr = (phdr(i)->p_paddr + phdr(i)->p_memsz); + if (addr > end_addr) + end_addr = addr; + } + grub_multiboot_payload_size = end_addr - phdr(0)->p_paddr; + } + if (playground) + grub_free (playground); + playground = grub_malloc (sizeof (forward_relocator) + grub_multiboot_payload_size + sizeof (backward_relocator)); + if (! playground) + return grub_errno; + + grub_multiboot_payload_orig = playground + sizeof (forward_relocator); + grub_multiboot_payload_dest = (char *) phdr(0)->p_paddr; + + grub_memmove (playground, forward_relocator, sizeof (forward_relocator)); + grub_memmove (grub_multiboot_payload_orig + grub_multiboot_payload_size, backward_relocator, sizeof (backward_relocator)); + /* Load every loadable segment in memory. */ for (i = 0; i < ehdr->e_phnum; i++) { if (phdr(i)->p_type == PT_LOAD) { - /* The segment should fit in the area reserved for the OS. */ - if (phdr(i)->p_paddr < grub_os_area_addr) - return grub_error (GRUB_ERR_BAD_OS, - "segment doesn't fit in memory reserved for the OS (0x%lx < 0x%lx)", - phdr(i)->p_paddr, grub_os_area_addr); - if (phdr(i)->p_paddr + phdr(i)->p_memsz > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_BAD_OS, - "segment doesn't fit in memory reserved for the OS (0x%lx > 0x%lx)", - phdr(i)->p_paddr + phdr(i)->p_memsz, - grub_os_area_addr + grub_os_area_size); + char *load_this_module_at = grub_multiboot_payload_orig + (phdr(i)->p_paddr - phdr(0)->p_paddr); - if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset) + if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset) == (grub_off_t) -1) return grub_error (GRUB_ERR_BAD_OS, "invalid offset in program header"); - if (grub_file_read (file, (void *) phdr(i)->p_paddr, phdr(i)->p_filesz) + if (grub_file_read (file, load_this_module_at, phdr(i)->p_filesz) != (grub_ssize_t) phdr(i)->p_filesz) return grub_error (GRUB_ERR_BAD_OS, "couldn't read segment from file"); if (phdr(i)->p_filesz < phdr(i)->p_memsz) - grub_memset ((char *) phdr(i)->p_paddr + phdr(i)->p_filesz, 0, + grub_memset (load_this_module_at + phdr(i)->p_filesz, 0, phdr(i)->p_memsz - phdr(i)->p_filesz); if ((entry >= phdr(i)->p_vaddr) && @@ -159,6 +196,13 @@ if (physical_entry_addr) entry = physical_entry_addr; + /* FIXME: how do we handle physical_entry_addr now? */ + + if (grub_multiboot_payload_dest >= grub_multiboot_payload_orig) + entry = (grub_addr_t) playground; + else + entry = (grub_addr_t) grub_multiboot_payload_orig + grub_multiboot_payload_size; + return grub_errno; } --ibTvN161/egqYuK8--