* kern/err.c: Include `<grub/i18n.h>'. (grub_print_error): Add full stop. Gettextizze. * loader/i386/bsd.c (grub_netbsd_boot): Change grub_error description. (grub_bsd_load_elf): Capitalise ELF. (grub_cmd_freebsd_loadenv): Add `s' in error string. (grub_cmd_freebsd_module): Likewise. (grub_cmd_freebsd_module_elf): Likewise. * loader/i386/bsdXX.c (SUFFIX): Capitalise ELF.
		
			
				
	
	
		
			329 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			329 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <grub/loader.h>
 | |
| #include <grub/cpu/bsd.h>
 | |
| #include <grub/mm.h>
 | |
| #include <grub/elf.h>
 | |
| #include <grub/misc.h>
 | |
| #include <grub/i386/loader.h>
 | |
| 
 | |
| #define ALIGN_PAGE(a)	ALIGN_UP (a, 4096)
 | |
| 
 | |
| static inline grub_err_t
 | |
| load (grub_file_t file, void *where, grub_off_t off, grub_size_t size)
 | |
| {
 | |
|   if (PTR_TO_UINT32 (where) + size > grub_os_area_addr + grub_os_area_size)
 | |
|     return grub_error (GRUB_ERR_OUT_OF_RANGE,
 | |
| 		       "not enough memory for the module");
 | |
|   if (grub_file_seek (file, off) == (grub_off_t) -1)
 | |
|     return grub_errno;
 | |
|   if (grub_file_read (file, where, size)
 | |
|       != (grub_ssize_t) size)
 | |
|     {
 | |
|       if (grub_errno)
 | |
| 	return grub_errno;
 | |
|       else
 | |
| 	return grub_error (GRUB_ERR_BAD_OS, "file is truncated");
 | |
|     }
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| static inline grub_err_t
 | |
| read_headers (grub_file_t file, Elf_Ehdr *e, char **shdr)
 | |
| {
 | |
|  if (grub_file_seek (file, 0) == (grub_off_t) -1)
 | |
|     return grub_errno;
 | |
| 
 | |
|   if (grub_file_read (file, (char *) e, sizeof (*e)) != sizeof (*e))
 | |
|     {
 | |
|       if (grub_errno)
 | |
| 	return grub_errno;
 | |
|       else
 | |
| 	return grub_error (GRUB_ERR_BAD_OS, "file is too short");
 | |
|     }
 | |
| 
 | |
|   if (e->e_ident[EI_MAG0] != ELFMAG0
 | |
|       || e->e_ident[EI_MAG1] != ELFMAG1
 | |
|       || e->e_ident[EI_MAG2] != ELFMAG2
 | |
|       || e->e_ident[EI_MAG3] != ELFMAG3
 | |
|       || e->e_ident[EI_VERSION] != EV_CURRENT
 | |
|       || e->e_version != EV_CURRENT)
 | |
|     return grub_error (GRUB_ERR_BAD_OS, "invalid arch independent ELF magic");
 | |
| 
 | |
|   if (e->e_ident[EI_CLASS] != SUFFIX (ELFCLASS))
 | |
|     return grub_error (GRUB_ERR_BAD_OS, "invalid arch dependent ELF magic");
 | |
| 
 | |
|   *shdr = grub_malloc (e->e_shnum * e->e_shentsize);
 | |
|   if (! *shdr)
 | |
|     return grub_errno;
 | |
| 
 | |
|   if (grub_file_seek (file, e->e_shoff) == (grub_off_t) -1)
 | |
|     return grub_errno;
 | |
| 
 | |
|   if (grub_file_read (file, *shdr, e->e_shnum * e->e_shentsize)
 | |
|       != e->e_shnum * e->e_shentsize)
 | |
|     {
 | |
|       if (grub_errno)
 | |
| 	return grub_errno;
 | |
|       else
 | |
| 	return grub_error (GRUB_ERR_BAD_OS, "file is truncated");
 | |
|     }
 | |
| 
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| /* On i386 FreeBSD uses "elf module" approarch for 32-bit variant
 | |
|    and "elf obj module" for 64-bit variant. However it may differ on other
 | |
|    platforms. So I keep both versions.  */
 | |
| #if OBJSYM
 | |
| grub_err_t
 | |
| SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc,
 | |
| 					  char *argv[], grub_addr_t *kern_end)
 | |
| {
 | |
|   Elf_Ehdr e;
 | |
|   Elf_Shdr *s;
 | |
|   char *shdr;
 | |
|   grub_addr_t curload, module;
 | |
|   grub_err_t err;
 | |
| 
 | |
|   err = read_headers (file, &e, &shdr);
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   curload = module = ALIGN_PAGE (*kern_end);
 | |
| 
 | |
|   for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
 | |
| 						+ e.e_shnum * e.e_shentsize);
 | |
|        s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
 | |
|     {
 | |
|       if (s->sh_size == 0)
 | |
| 	continue;
 | |
| 
 | |
|       if (s->sh_addralign)
 | |
| 	curload = ALIGN_UP (curload, s->sh_addralign);
 | |
|       s->sh_addr = curload;
 | |
| 
 | |
|       grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
 | |
| 		    (unsigned) curload, (int) s->sh_size,
 | |
| 		    (int) s->sh_addralign);
 | |
| 
 | |
|       switch (s->sh_type)
 | |
| 	{
 | |
| 	default:
 | |
| 	case SHT_PROGBITS:
 | |
| 	  err = load (file, UINT_TO_PTR (curload), s->sh_offset, s->sh_size);
 | |
| 	  if (err)
 | |
| 	    return err;
 | |
| 	  break;
 | |
| 	case SHT_NOBITS:
 | |
| 	  if (curload + s->sh_size > grub_os_area_addr + grub_os_area_size)
 | |
| 	    return grub_error (GRUB_ERR_OUT_OF_RANGE,
 | |
| 			       "not enough memory for the module");
 | |
| 	  grub_memset (UINT_TO_PTR (curload), 0, s->sh_size);
 | |
| 	  break;
 | |
| 	}
 | |
|       curload += s->sh_size;
 | |
|     }
 | |
| 
 | |
|   *kern_end = ALIGN_PAGE (curload);
 | |
| 
 | |
|   err = grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE_OBJ,
 | |
| 				      argc - 1, argv + 1, module,
 | |
| 				      curload - module);
 | |
|   if (! err)
 | |
|     err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA
 | |
| 				 | FREEBSD_MODINFOMD_ELFHDR,
 | |
| 				 &e, sizeof (e));
 | |
|   if (! err)
 | |
|     err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA
 | |
| 				 | FREEBSD_MODINFOMD_SHDR,
 | |
| 				 shdr, e.e_shnum * e.e_shentsize);
 | |
| 
 | |
|   return err;
 | |
| }
 | |
| 
 | |
| #else
 | |
| 
 | |
| grub_err_t
 | |
| SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[],
 | |
| 				      grub_addr_t *kern_end)
 | |
| {
 | |
|   Elf_Ehdr e;
 | |
|   Elf_Shdr *s;
 | |
|   char *shdr;
 | |
|   grub_addr_t curload, module;
 | |
|   grub_err_t err;
 | |
| 
 | |
|   err = read_headers (file, &e, &shdr);
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   curload = module = ALIGN_PAGE (*kern_end);
 | |
| 
 | |
|   for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
 | |
| 						+ e.e_shnum * e.e_shentsize);
 | |
|        s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
 | |
|     {
 | |
|       if (s->sh_size == 0)
 | |
| 	continue;
 | |
| 
 | |
|       if (! (s->sh_flags & SHF_ALLOC))
 | |
| 	continue;
 | |
| 
 | |
|       grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
 | |
| 		    (unsigned) curload, (int) s->sh_size,
 | |
| 		    (int) s->sh_addralign);
 | |
| 
 | |
|       switch (s->sh_type)
 | |
| 	{
 | |
| 	default:
 | |
| 	case SHT_PROGBITS:
 | |
| 	  err = load (file, UINT_TO_PTR (module + s->sh_addr),
 | |
| 		      s->sh_offset, s->sh_size);
 | |
| 	  if (err)
 | |
| 	    return err;
 | |
| 	  break;
 | |
| 	case SHT_NOBITS:
 | |
| 	  if (module + s->sh_addr + s->sh_size
 | |
| 	      > grub_os_area_addr + grub_os_area_size)
 | |
| 	    return grub_error (GRUB_ERR_OUT_OF_RANGE,
 | |
| 			       "not enough memory for the module");
 | |
| 	  grub_memset (UINT_TO_PTR (module + s->sh_addr), 0, s->sh_size);
 | |
| 	  break;
 | |
| 	}
 | |
|       if (curload < module + s->sh_addr + s->sh_size)
 | |
| 	curload = module + s->sh_addr + s->sh_size;
 | |
|     }
 | |
| 
 | |
|   load (file, UINT_TO_PTR (module), 0, sizeof (e));
 | |
|   if (curload < module + sizeof (e))
 | |
|     curload = module + sizeof (e);
 | |
| 
 | |
|   load (file, UINT_TO_PTR (curload), e.e_shoff,
 | |
| 	e.e_shnum * e.e_shentsize);
 | |
|   e.e_shoff = curload - module;
 | |
|   curload +=  e.e_shnum * e.e_shentsize;
 | |
| 
 | |
|   load (file, UINT_TO_PTR (curload), e.e_phoff,
 | |
| 	e.e_phnum * e.e_phentsize);
 | |
|   e.e_phoff = curload - module;
 | |
|   curload +=  e.e_phnum * e.e_phentsize;
 | |
| 
 | |
|   *kern_end = curload;
 | |
| 
 | |
|   grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE,
 | |
| 				argc - 1, argv + 1, module,
 | |
| 				curload - module);
 | |
|   return SUFFIX (grub_freebsd_load_elf_meta) (file, kern_end);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| grub_err_t
 | |
| SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end)
 | |
| {
 | |
|   grub_err_t err;
 | |
|   Elf_Ehdr e;
 | |
|   Elf_Shdr *s;
 | |
|   char *shdr;
 | |
|   unsigned symoff, stroff, symsize, strsize;
 | |
|   grub_addr_t curload;
 | |
|   grub_freebsd_addr_t symstart, symend, symentsize, dynamic;
 | |
|   Elf_Sym *sym;
 | |
|   const char *str;
 | |
|   unsigned i;
 | |
| 
 | |
|   err = read_headers (file, &e, &shdr);
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
 | |
| 			       FREEBSD_MODINFOMD_ELFHDR, &e,
 | |
| 			       sizeof (e));
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
 | |
| 						+ e.e_shnum * e.e_shentsize);
 | |
|        s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
 | |
|       if (s->sh_type == SHT_SYMTAB)
 | |
| 	break;
 | |
|   if (s >= (Elf_Shdr *) ((char *) shdr
 | |
| 			+ e.e_shnum * e.e_shentsize))
 | |
|     return grub_error (GRUB_ERR_BAD_OS, "no symbol table");
 | |
|   symoff = s->sh_offset;
 | |
|   symsize = s->sh_size;
 | |
|   symentsize = s->sh_entsize;
 | |
|   s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
 | |
|   stroff = s->sh_offset;
 | |
|   strsize = s->sh_size;
 | |
| 
 | |
|   if (*kern_end + 4 * sizeof (grub_freebsd_addr_t) + symsize + strsize
 | |
|       > grub_os_area_addr + grub_os_area_size)
 | |
|     return grub_error (GRUB_ERR_OUT_OF_RANGE,
 | |
| 		       "not enough memory for kernel symbols");
 | |
| 
 | |
|   symstart = curload = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
 | |
|   *((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = symsize;
 | |
|   curload += sizeof (grub_freebsd_addr_t);
 | |
|   if (grub_file_seek (file, symoff) == (grub_off_t) -1)
 | |
|     return grub_errno;
 | |
|   sym = (Elf_Sym *) UINT_TO_PTR (curload);
 | |
|   if (grub_file_read (file, UINT_TO_PTR (curload), symsize) !=
 | |
|       (grub_ssize_t) symsize)
 | |
|     {
 | |
|       if (! grub_errno)
 | |
| 	return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
 | |
|       return grub_errno;
 | |
|     }
 | |
|   curload += symsize;
 | |
| 
 | |
|   *((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = strsize;
 | |
|   curload += sizeof (grub_freebsd_addr_t);
 | |
|   if (grub_file_seek (file, stroff) == (grub_off_t) -1)
 | |
|     return grub_errno;
 | |
|   str = (char *) UINT_TO_PTR (curload);
 | |
|   if (grub_file_read (file, UINT_TO_PTR (curload), strsize)
 | |
|       != (grub_ssize_t) strsize)
 | |
|     {
 | |
|       if (! grub_errno)
 | |
| 	return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
 | |
|       return grub_errno;
 | |
|     }
 | |
|   curload += strsize;
 | |
|   curload = ALIGN_UP (curload, sizeof (grub_freebsd_addr_t));
 | |
|   symend = curload;
 | |
| 
 | |
|   for (i = 0;
 | |
|        i * symentsize < symsize;
 | |
|        i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
 | |
|     {
 | |
|       const char *name = str + sym->st_name;
 | |
|       if (grub_strcmp (name, "_DYNAMIC") == 0)
 | |
| 	break;
 | |
|     }
 | |
| 
 | |
|   if (i * symentsize < symsize)
 | |
|     {
 | |
|       dynamic = sym->st_value;
 | |
|       grub_dprintf ("bsd", "dynamic = %llx\n", (unsigned long long) dynamic);
 | |
|       err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
 | |
| 				   FREEBSD_MODINFOMD_DYNAMIC, &dynamic,
 | |
| 				   sizeof (dynamic));
 | |
|       if (err)
 | |
| 	return err;
 | |
|     }
 | |
| 
 | |
|   err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
 | |
| 			       FREEBSD_MODINFOMD_SSYM, &symstart,
 | |
| 			       sizeof (symstart));
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
 | |
| 			       FREEBSD_MODINFOMD_ESYM, &symend,
 | |
| 			       sizeof (symend));
 | |
|   if (err)
 | |
|     return err;
 | |
|   *kern_end = ALIGN_PAGE (curload);
 | |
| 
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 |