The Pedigree Project  0.1
boot-hosted.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <assert.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <memory.h>
24 #include <stdio.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 
29 #include <elf.h>
30 
31 #include "pedigree/kernel/BootstrapInfo.h"
32 
33 extern "C" void _main(BootstrapStruct_t &bs);
34 
35 extern "C" int main(int argc, char *argv[])
36 {
37  struct stat st;
38  int r = 0;
39  int s = 0;
40  int initrd = -1;
41  int configdb = -1;
42  int kernel = -1;
43  int diskimage = -1;
44  void *initrd_mapping = MAP_FAILED;
45  void *configdb_mapping = MAP_FAILED;
46  void *kernel_mapping = MAP_FAILED;
47  void *diskimage_mapping = MAP_FAILED;
48  uintptr_t *module_region = (uintptr_t *) MAP_FAILED;
49  size_t initrd_length = 0;
50  size_t configdb_length = 0;
51  size_t kernel_length = 0;
52  size_t diskimage_length = 0;
53  Elf64_Ehdr *ehdr = 0;
54  Elf64_Shdr *shdrs = 0;
56  memset(&bs, 0, sizeof(bs));
57 
58  if (argc < 3)
59  {
60  fprintf(stderr, "Usage: kernel initrd config_database [diskimage]\n");
61  goto fail;
62  }
63 
64  fprintf(stderr, "Pedigree is starting...\n");
65 
66  // Load initrd and config database into RAM.
67  initrd = open(argv[1], O_RDONLY);
68  if (initrd < 0)
69  {
70  fprintf(stderr, "Can't open initrd: %s\n", strerror(errno));
71  goto fail;
72  }
73  configdb = open(argv[2], O_RDONLY);
74  if (configdb < 0)
75  {
76  fprintf(stderr, "Can't open config database: %s\n", strerror(errno));
77  goto fail;
78  }
79 
80  // Open ourselves to find section headers.
81  kernel = open(argv[0], O_RDONLY);
82  if (kernel < 0)
83  {
84  fprintf(stderr, "Can't open kernel: %s\n", strerror(errno));
85  goto fail;
86  }
87 
88  // Load initrd and configuration database.
89  r = fstat(initrd, &st);
90  if (r != 0)
91  {
92  fprintf(stderr, "Can't stat initrd: %s\n", strerror(errno));
93  goto fail;
94  }
95  initrd_length = st.st_size;
96  initrd_mapping = mmap(0, initrd_length, PROT_READ, MAP_PRIVATE, initrd, 0);
97  if (initrd_mapping == MAP_FAILED)
98  {
99  fprintf(stderr, "Can't map initrd: %s\n", strerror(errno));
100  goto fail;
101  }
102  fprintf(stderr, "initrd is at %p\n", initrd_mapping);
103 
104  r = fstat(configdb, &st);
105  if (r != 0)
106  {
107  fprintf(stderr, "Can't stat config database: %s\n", strerror(errno));
108  goto fail;
109  }
110  configdb_length = st.st_size;
111  configdb_mapping =
112  mmap(0, configdb_length, PROT_READ, MAP_PRIVATE, configdb, 0);
113  if (configdb_mapping == MAP_FAILED)
114  {
115  fprintf(stderr, "Can't map config database: %s\n", strerror(errno));
116  goto fail;
117  }
118  fprintf(stderr, "configuration database is at %p\n", configdb_mapping);
119 
120  r = fstat(kernel, &st);
121  if (r != 0)
122  {
123  fprintf(stderr, "Can't stat kernel: %s\n", strerror(errno));
124  goto fail;
125  }
126  kernel_length = st.st_size;
127  kernel_mapping =
128  mmap(0, kernel_length, PROT_READ | PROT_WRITE, MAP_PRIVATE, kernel, 0);
129  if (kernel_mapping == MAP_FAILED)
130  {
131  fprintf(stderr, "Can't map kernel: %s\n", strerror(errno));
132  goto fail;
133  }
134  fprintf(stderr, "kernel is at %p\n", kernel_mapping);
135 
136  // Make the module locations available to the kernel.
137  module_region = (uintptr_t *) mmap(
138  0, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
139  if (module_region == MAP_FAILED)
140  {
141  fprintf(
142  stderr, "Can't map module information region: %s\n",
143  strerror(errno));
144  goto fail;
145  }
146  fprintf(stderr, "module region is at %p\n", module_region);
147  memset(module_region, 0, 0x1000);
148 
149  // initrd
150  module_region[0] = reinterpret_cast<uintptr_t>(initrd_mapping);
151  module_region[1] =
152  reinterpret_cast<uintptr_t>(initrd_mapping) + initrd_length;
153 
154  // config database
155  module_region[4] = reinterpret_cast<uintptr_t>(configdb_mapping);
156  module_region[5] =
157  reinterpret_cast<uintptr_t>(configdb_mapping) + configdb_length;
158 
159  bs.mods_addr = reinterpret_cast<uintptr_t>(module_region);
160  bs.mods_count = 2;
161 
162  if (argc > 3)
163  {
164  diskimage = open(argv[3], O_RDWR);
165  if (diskimage < 0)
166  {
167  fprintf(stderr, "Can't open disk image: %s\n", strerror(errno));
168  goto fail;
169  }
170 
171  r = fstat(diskimage, &st);
172  if (r != 0)
173  {
174  fprintf(stderr, "Can't stat disk image: %s\n", strerror(errno));
175  goto fail;
176  }
177 
178  diskimage_length = st.st_size;
179  diskimage_mapping = mmap(
180  0, diskimage_length, PROT_READ | PROT_WRITE,
181  MAP_PRIVATE | MAP_NORESERVE, diskimage, 0);
182  if (diskimage_mapping == MAP_FAILED)
183  {
184  fprintf(stderr, "Can't map disk image: %s\n", strerror(errno));
185  goto fail;
186  }
187  fprintf(stderr, "disk image is at %p\n", diskimage_mapping);
188 
189  // Add to the multiboot info.
190  bs.mods_count++;
191  module_region[8] = reinterpret_cast<uintptr_t>(diskimage_mapping);
192  module_region[9] =
193  reinterpret_cast<uintptr_t>(diskimage_mapping) + diskimage_length;
194  }
195 
196  // Load ELF header to add ELF information.
197  ehdr = reinterpret_cast<Elf64_Ehdr *>(kernel_mapping);
198  bs.shndx = ehdr->e_shstrndx;
199  bs.num = ehdr->e_shnum;
200  bs.size = ehdr->e_shentsize;
201  bs.addr = reinterpret_cast<uintptr_t>(kernel_mapping) + ehdr->e_shoff;
202 
203  // Fix up section headers with no addresses.
204  shdrs = reinterpret_cast<Elf64_Shdr *>(bs.addr);
205  for (uint32_t i = 1; i < bs.num; ++i)
206  {
207  if (shdrs[i].sh_addr)
208  continue;
209 
210  shdrs[i].sh_addr =
211  shdrs[i].sh_offset + reinterpret_cast<uintptr_t>(kernel_mapping);
212  }
213 
214  // Kernel uses flags to know what it can and can't use.
215  bs.flags |= MULTIBOOT_FLAG_MODS | MULTIBOOT_FLAG_ELF;
216  _main(bs);
217 
218  goto cleanup;
219 fail:
220  s = 1;
221 cleanup:
222  if (module_region != MAP_FAILED)
223  munmap(module_region, 0x1000);
224  if (diskimage_mapping != MAP_FAILED)
225  munmap(diskimage_mapping, diskimage_length);
226  if (kernel_mapping != MAP_FAILED)
227  munmap(kernel_mapping, kernel_length);
228  if (configdb_mapping != MAP_FAILED)
229  munmap(configdb_mapping, kernel_length);
230  if (initrd_mapping != MAP_FAILED)
231  munmap(initrd_mapping, initrd_length);
232  close(diskimage);
233  close(kernel);
234  close(configdb);
235  close(initrd);
236  return s;
237 }
Bootstrap structure passed to the kernel entry point.