2 * Copyright (C) 2001-2002 Hewlett-Packard Co.
3 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
5 * Copyright (C) 2001 Silicon Graphics, Inc.
6 * Contributed by Brent Casavant <bcasavan@sgi.com>
8 * This file is part of the ELILO, the EFI Linux boot loader.
10 * ELILO is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * ELILO is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with ELILO; see the file COPYING. If not, write to the Free
22 * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 * Please check out the elilo.txt for complete documentation on how
26 * to use this program.
37 #define LD_NAME L"plain_elf32"
40 is_valid_header(Elf32_Ehdr *ehdr)
45 machine = ehdr->e_machine;
47 DBG_PRT((L"class=%d type=%d data=%d machine=%d\n",
48 ehdr->e_ident[EI_CLASS],
50 ehdr->e_ident[EI_DATA],
53 return ehdr->e_ident[EI_MAG0] == 0x7f
54 && ehdr->e_ident[EI_MAG1] == 'E'
55 && ehdr->e_ident[EI_MAG2] == 'L'
56 && ehdr->e_ident[EI_MAG3] == 'F'
57 && ehdr->e_ident[EI_CLASS] == ELFCLASS32
58 && type == ET_EXEC /* must be executable */
59 && machine == EM_386 ? 0 : -1;
63 plain_probe(CHAR16 *kname)
69 UINTN size = sizeof(ehdr);
71 status = fops_open(kname, &fd);
72 if (EFI_ERROR(status))
75 status = fops_read(fd, &ehdr, &size);
76 if (EFI_ERROR(status) || size != sizeof(ehdr))
79 ret = is_valid_header(&ehdr);
87 load_elf(fops_fd_t fd, kdesc_t *kd)
92 INTN ret = ELILO_LOAD_ERROR;
93 UINTN i, total_size = 0;
94 UINTN pages, size, bss_sz, osize;
95 VOID *low_addr = (VOID *)~0;
96 VOID *max_addr = (VOID *)0;
97 UINTN paddr, memsz, filesz;
100 Print(L"Loading Linux... ");
104 status = fops_read(fd, &ehdr, &size);
105 if (EFI_ERROR(status) || size < sizeof(ehdr))
106 return ELILO_LOAD_ERROR;
108 if (is_valid_header(&ehdr) == -1) {
109 ERR_PRT((L"%s : not a 32-bit ELF image\n", LD_NAME));
110 return ELILO_LOAD_ERROR;
113 Print(L"ELF Header information: \n");
114 Print(L"\tEntry point "PTR_FMT"\n", (ehdr.e_entry & PADDR_MASK));
115 Print(L"\t%d program headers\n", ehdr.e_phnum);
116 Print(L"\t%d segment headers\n", ehdr.e_shnum);
119 phnum = ehdr.e_phnum;
121 if (fops_seek(fd, ehdr.e_phoff) < 0) {
122 ERR_PRT((L"%s : seek to %d for phdrs failed", LD_NAME, ehdr.e_phoff));
123 return ELILO_LOAD_ERROR;
125 size = osize = (phnum * sizeof(Elf32_Phdr));
127 DBG_PRT((L"%s : allocate %d bytes for %d pheaders each of size:%d phentsize=%d\n",
128 LD_NAME, size, phnum, sizeof(Elf32_Phdr), ehdr.e_phentsize));
130 phdrs = (Elf32_Phdr *)alloc(size, 0);
132 ERR_PRT((L"%s : allocate for phdrs failed", LD_NAME));
133 return ELILO_LOAD_ERROR;
135 status = fops_read(fd, phdrs, &size);
136 if (EFI_ERROR(status) || size != osize) {
137 ERR_PRT((L"%s : phdr load failed", LD_NAME, status));
141 * First pass to figure out total memory footprint
143 for (i = 0; i < phnum; i++) {
145 paddr = (phdrs[i].p_paddr & PADDR_MASK);
146 memsz = phdrs[i].p_memsz;
148 DBG_PRT((L"Phdr %d paddr ["PTR_FMT"-"PTR_FMT"] offset "PTR_FMT""
149 " filesz "PTR_FMT" memsz="PTR_FMT" bss_sz="PTR_FMT" p_type="PTR_FMT"\n",
150 1+i, paddr, paddr+phdrs[i].p_filesz, phdrs[i].p_offset,
151 phdrs[i].p_filesz, memsz,
152 (memsz - phdrs[i].p_filesz), phdrs[i].p_type));
154 if (phdrs[i].p_type != PT_LOAD)
156 if (paddr < (UINTN)low_addr)
157 low_addr = (VOID *)paddr;
158 if (paddr + memsz > (UINTN)max_addr)
159 max_addr = (VOID *)paddr + memsz;
162 if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) {
163 ERR_PRT((L"%s : kernel low address "PTR_FMT" not page aligned\n",
167 /* how many bytes are needed to hold the kernel? */
168 total_size = (UINTN)max_addr - (UINTN)low_addr;
170 /* round up to get required number of pages */
171 pages = EFI_SIZE_TO_PAGES(total_size);
173 /* keep track of location where kernel starts and ends */
174 kd->kstart = low_addr;
175 kd->kend = (low_addr + (pages << EFI_PAGE_SHIFT));
176 kd->kentry = (VOID *)(ehdr.e_entry & PADDR_MASK);
179 Print(L"Lowest PhysAddr: "PTR_FMT"\nTotalMemSize:%d bytes (%d pages)\n",
180 low_addr, total_size, pages);
181 Print(L"Kernel entry @ "PTR_FMT"\n", kd->kentry);
184 /* now allocate memory for the kernel at the exact requested spot */
185 if (alloc_kmem(low_addr, pages) == -1) {
186 ERR_PRT((L"%s : AllocatePages(%d, "PTR_FMT") for kernel failed\n",
187 LD_NAME, pages, low_addr));
188 ERR_PRT((L"%s : Could not alloc %d pages for the kernel at "PTR_FMT""
189 " and relocation is not not been implemented!\n",
190 LD_NAME, pages, low_addr));
193 /* Pure paranoia. Clear the memory first. Just in case... */
194 Memset(low_addr, 0, (pages << EFI_PAGE_SHIFT));
196 VERB_PRT(1, Print(L"Press any key to interrupt\n"));
199 * Walk through the program headers
200 * and actually load data into physical memory
203 for (i = 0; i < phnum; i++) {
205 /* Check for pure loadable segment; ignore if not loadable */
206 if (phdrs[i].p_type != PT_LOAD)
209 VERB_PRT(3, Print(L"poffs: "PTR_FMT" (phdrs[%d].p_offset)\n",
210 phdrs[i].p_offset, i));
212 filesz = phdrs[i].p_filesz;
213 low_addr = (VOID *)((UINTN) phdrs[i].p_paddr & PADDR_MASK);
215 /* Move to the right position */
216 if (fops_seek(fd, phdrs[i].p_offset) < 0)
219 /* How many BSS bytes to clear */
220 bss_sz = phdrs[i].p_memsz - filesz;
223 Print(L"\nHeader #%d\n", i);
224 Print(L"Offset in file "PTR_FMT"\n", phdrs[i].p_offset);
225 Print(L"Physical addr "PTR_FMT"\n", low_addr);
226 Print(L"BSS size %d bytes\n", bss_sz);
230 * Read actual segment into memory
232 ret = fops_read(fd, low_addr, &filesz);
233 if (ret == ELILO_LOAD_ABORTED) goto load_abort;
234 if (ret == ELILO_LOAD_ERROR) goto out;
240 Memset((VOID *)low_addr+filesz, 0, bss_sz);
246 return ELILO_LOAD_SUCCESS;
249 Print(L"..Aborted\n");
250 ret = ELILO_LOAD_ABORTED;
252 /* free kernel memory */
260 plain_load_kernel(CHAR16 *kname, kdesc_t *kd)
267 * Moving the open here simplifies the load_elf() error handling
269 status = fops_open(kname, &fd);
270 if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
272 Print(L"Loading %s...", kname);
274 ret = load_elf(fd, kd);
280 loader_ops_t plain_loader={