3 * 2003-07-02 mmap fix and header probe by SONE Takeshi
6 struct multiboot_mods {
13 struct multiboot_mmap {
15 unsigned int base_addr_low;
16 unsigned int base_addr_high;
17 unsigned int length_low;
18 unsigned int length_high;
22 /* The structure of a Multiboot 0.6 parameter block. */
23 struct multiboot_info {
25 #define MULTIBOOT_MEM_VALID 0x01
26 #define MULTIBOOT_BOOT_DEV_VALID 0x02
27 #define MULTIBOOT_CMDLINE_VALID 0x04
28 #define MULTIBOOT_MODS_VALID 0x08
29 #define MULTIBOOT_AOUT_SYMS_VALID 0x10
30 #define MULTIBOOT_ELF_SYMS_VALID 0x20
31 #define MULTIBOOT_MMAP_VALID 0x40
32 unsigned int memlower;
33 unsigned int memupper;
35 unsigned int cmdline; /* physical address of the command line */
37 struct multiboot_mods *mods_addr;
44 /* The structure actually ends here, so I might as well put
45 * the ugly e820 parameters here...
47 struct multiboot_mmap mmap[E820MAX];
50 /* Multiboot image header (minimal part) */
51 struct multiboot_header {
53 #define MULTIBOOT_HEADER_MAGIC 0x1BADB002
55 unsigned int checksum;
58 static struct multiboot_header *mbheader;
59 static unsigned int mbimgoffset, mboffset;
60 static unsigned char mbbuffer[12];
62 static struct multiboot_info mbinfo;
64 static void multiboot_init(void)
71 /* Remember this probing function is actually different from the usual probing
72 * functions, since the Multiboot header is somewhere in the first 8KB of the
73 * image and it is byte aligned, but there is not much more known about how to
74 * find it. In the Etherboot context the most complicated issue is that the
75 * image has to be processed block-by-block, with unknown block size and no
76 * guarantees about block alignment with respect to the image. */
77 static void multiboot_peek(unsigned char *data, int len)
79 struct multiboot_header *h;
81 /* If we have already searched the first 8KB of the image or if we have
82 * already found a valid Multiboot header, skip this code. */
83 if ((mboffset == 12) || (mbimgoffset >= 8192))
86 if (mbimgoffset + len >= 8192)
87 len = 8192 - mbimgoffset;
89 /* This piece of code is pretty stupid, since it always copies data, even
90 * if it is word aligned. This shouldn't matter too much on platforms that
91 * use the Multiboot spec, since the processors are usually reasonably fast
92 * and this code is only executed for the first 8KB of the image. Feel
93 * free to improve it, but be prepared to write quite a lot of code that
94 * deals with non-aligned data with respect to the image to load. */
97 memcpy(mbbuffer + mboffset, data, 1);
102 /* Accumulated a word into the buffer. */
103 h = (struct multiboot_header *)mbbuffer;
104 if (h->magic != MULTIBOOT_HEADER_MAGIC) {
105 /* Wrong magic, this cannot be the start of the header. */
108 } else if (mboffset == 12) {
109 /* Accumulated the minimum header data into the buffer. */
110 h = (struct multiboot_header *)mbbuffer;
111 if (h->magic + h->flags + h->checksum != 0) {
112 /* Checksum error, not a valid header. Check for a possible
113 * header starting in the current flag/checksum field. */
114 if (h->flags == MULTIBOOT_HEADER_MAGIC) {
116 memmove(mbbuffer, mbbuffer + 4, mboffset);
117 } else if (h->checksum == MULTIBOOT_HEADER_MAGIC) {
119 memmove(mbbuffer, mbbuffer + 8, mboffset);
124 printf("Multiboot... ");
126 if ((h->flags & 0xfffc) != 0) {
127 printf("\nERROR: Unsupported Multiboot requirements flags\n");
128 longjmp(restart_etherboot, -2);
137 static inline void multiboot_boot(unsigned long entry)
139 unsigned char cmdline[512], *c;
143 /* Etherboot limits the command line to the kernel name,
144 * default parameters and user prompted parameters. All of
145 * them are shorter than 256 bytes. As the kernel name and
146 * the default parameters come from the same BOOTP/DHCP entry
147 * (or if they don't, the parameters are empty), only two
148 * strings of the maximum size are possible. Note this buffer
149 * can overrun if a stupid file name is chosen. Oh well. */
151 for (i = 0; KERNEL_BUF[i] != '\0'; i++) {
152 switch (KERNEL_BUF[i]) {
161 *c++ = KERNEL_BUF[i];
163 if (addparam != NULL) {
165 memcpy(c, addparam, addparamlen);
168 (void)sprintf(c, " -retaddr %#lX", virt_to_phys(xend32));
170 mbinfo.flags = MULTIBOOT_MMAP_VALID | MULTIBOOT_MEM_VALID |MULTIBOOT_CMDLINE_VALID;
171 mbinfo.memlower = meminfo.basememsize;
172 mbinfo.memupper = meminfo.memsize;
173 mbinfo.bootdev = 0; /* not booted from disk */
174 mbinfo.cmdline = virt_to_phys(cmdline);
175 for (i = 0; i < (int) meminfo.map_count; i++) {
176 mbinfo.mmap[i].size = sizeof(struct multiboot_mmap)
177 - sizeof(unsigned int);
178 mbinfo.mmap[i].base_addr_low =
179 (unsigned int) meminfo.map[i].addr;
180 mbinfo.mmap[i].base_addr_high =
181 (unsigned int) (meminfo.map[i].addr >> 32);
182 mbinfo.mmap[i].length_low =
183 (unsigned int) meminfo.map[i].size;
184 mbinfo.mmap[i].length_high =
185 (unsigned int) (meminfo.map[i].size >> 32);
186 mbinfo.mmap[i].type = meminfo.map[i].type;
188 mbinfo.mmap_length = meminfo.map_count * sizeof(struct multiboot_mmap);
189 mbinfo.mmap_addr = virt_to_phys(mbinfo.mmap);
191 /* The Multiboot 0.6 spec requires all segment registers to be
192 * loaded with an unrestricted, writeable segment.
193 * xstart32 does this for us.
196 /* Start the kernel, passing the Multiboot information record
197 * and the magic number. */
198 os_regs.eax = 0x2BADB002;
199 os_regs.ebx = virt_to_phys(&mbinfo);
201 /* A Multiboot kernel by default never returns - there is nothing in the
202 * specification about what happens to the boot loader after the kernel has
203 * been started. Thus if the kernel returns it is definitely aware of the
204 * semantics involved (i.e. the "-retaddr" parameter). Do not treat this
205 * as an error, but restart with a fresh DHCP request in order to activate
206 * the menu again in case one is used. */
207 longjmp(restart_etherboot, 2);