]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/powerpc/kboot/ppc64_elf_freebsd.c
bhyvectl(8): Normalize the man page date
[FreeBSD/FreeBSD.git] / stand / powerpc / kboot / ppc64_elf_freebsd.c
1 /*-
2  * Copyright (c) 2001 Benno Rice <benno@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #define __ELF_WORD_SIZE 64
31
32 #include <sys/param.h>
33 #include <sys/endian.h>
34 #include <sys/linker.h>
35
36 #include <machine/metadata.h>
37 #include <machine/elf.h>
38
39 #include <stand.h>
40
41 #include "bootstrap.h"
42 #include "host_syscall.h"
43
44 extern char             end[];
45 extern void             *kerneltramp;
46 extern size_t           szkerneltramp;
47
48 struct trampoline_data {
49         uint32_t        kernel_entry;
50         uint32_t        dtb;
51         uint32_t        phys_mem_offset;
52         uint32_t        of_entry;
53         uint32_t        mdp;
54         uint32_t        mdp_size;
55 };
56
57 vm_offset_t md_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtb);
58
59 int
60 ppc64_elf_loadfile(char *filename, uint64_t dest,
61     struct preloaded_file **result)
62 {
63         int     r;
64
65         r = __elfN(loadfile)(filename, dest, result);
66         if (r != 0)
67                 return (r);
68
69         return (0);
70 }
71
72 int
73 ppc64_elf_exec(struct preloaded_file *fp)
74 {
75         struct file_metadata    *fmp;
76         vm_offset_t             mdp, dtb;
77         Elf_Ehdr                *e;
78         int                     error;
79         uint32_t                *trampoline;
80         uint64_t                entry;
81         uint64_t                trampolinebase;
82         struct trampoline_data  *trampoline_data;
83         int                     nseg;
84         void                    *kseg;
85
86         if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) {
87                 return(EFTYPE);
88         }
89         e = (Elf_Ehdr *)&fmp->md_data;
90
91         /*
92          * Figure out where to put it.
93          *
94          * Linux does not allow to do kexec_load into
95          * any part of memory. Ask arch_loadaddr to
96          * resolve the first available chunk of physical
97          * memory where loading is possible (load_addr).
98          *
99          * Memory organization is shown below.
100          * It is assumed, that text segment offset of
101          * kernel ELF (KERNPHYSADDR) is non-zero,
102          * which is true for PPC/PPC64 architectures,
103          * where default is 0x100000.
104          *
105          * load_addr:                 trampoline code
106          * load_addr + KERNPHYSADDR:  kernel text segment
107          */
108         trampolinebase = archsw.arch_loadaddr(LOAD_RAW, NULL, 0);
109         printf("Load address at %#jx\n", (uintmax_t)trampolinebase);
110         printf("Relocation offset is %#jx\n", (uintmax_t)elf64_relocation_offset);
111
112         /* Set up loader trampoline */
113         trampoline = malloc(szkerneltramp);
114         memcpy(trampoline, &kerneltramp, szkerneltramp);
115
116         /* Parse function descriptor for ELFv1 kernels */
117         if ((e->e_flags & 3) == 2)
118                 entry = e->e_entry;
119         else {
120                 archsw.arch_copyout(e->e_entry + elf64_relocation_offset,
121                     &entry, 8);
122                 entry = be64toh(entry);
123         }
124
125         /*
126          * Placeholder for trampoline data is at trampolinebase + 0x08
127          * CAUTION: all data must be Big Endian
128          */
129         trampoline_data = (void*)&trampoline[2];
130         trampoline_data->kernel_entry = htobe32(entry + elf64_relocation_offset);
131         trampoline_data->phys_mem_offset = htobe32(0);
132         trampoline_data->of_entry = htobe32(0);
133
134         if ((error = md_load64(fp->f_args, &mdp, &dtb)) != 0)
135                 return (error);
136
137         trampoline_data->dtb = htobe32(dtb);
138         trampoline_data->mdp = htobe32(mdp);
139         trampoline_data->mdp_size = htobe32(0xfb5d104d);
140
141         printf("Kernel entry at %#jx (%#x) ...\n",
142             entry, be32toh(trampoline_data->kernel_entry));
143         printf("DTB at %#x, mdp at %#x\n",
144             be32toh(trampoline_data->dtb), be32toh(trampoline_data->mdp));
145
146         dev_cleanup();
147
148         archsw.arch_copyin(trampoline, trampolinebase, szkerneltramp);
149         free(trampoline);
150
151         if (archsw.arch_kexec_kseg_get == NULL)
152                 panic("architecture did not provide kexec segment mapping");
153         archsw.arch_kexec_kseg_get(&nseg, &kseg);
154
155         error = kexec_load(trampolinebase, nseg, (uintptr_t)kseg);
156         if (error != 0)
157                 panic("kexec_load returned error: %d", error);
158
159         error = host_reboot(0xfee1dead, 672274793,
160             0x45584543 /* LINUX_REBOOT_CMD_KEXEC */, (uintptr_t)NULL);
161         if (error != 0)
162                 panic("reboot returned error: %d", error);
163
164         while (1) {}
165 }
166
167 struct file_format      ppc_elf64 =
168 {
169         ppc64_elf_loadfile,
170         ppc64_elf_exec
171 };