mirror of https://github.com/ipxe/ipxe.git
Merge from Etherboot 5.4
commit
9b18017296
|
@ -74,7 +74,7 @@ struct Elf_Bhdr *prepare_boot_params(void *header)
|
||||||
notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
|
notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
|
||||||
notes.nf1.n_type = EB_BOOTP_DATA;
|
notes.nf1.n_type = EB_BOOTP_DATA;
|
||||||
CP(notes.nf1_name, EB_PARAM_NOTE);
|
CP(notes.nf1_name, EB_PARAM_NOTE);
|
||||||
notes.nf1_bootp_data = virt_to_phys(BOOTP_DATA_ADDR);
|
notes.nf1_bootp_data = virt_to_phys(&bootp_data);
|
||||||
|
|
||||||
notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
|
notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
|
||||||
notes.nf2.n_descsz = sizeof(notes.nf2_header);
|
notes.nf2.n_descsz = sizeof(notes.nf2_header);
|
||||||
|
|
|
@ -56,28 +56,82 @@ struct multiboot_header {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct multiboot_header *mbheader;
|
static struct multiboot_header *mbheader;
|
||||||
|
static unsigned int mbimgoffset, mboffset;
|
||||||
|
static unsigned char mbbuffer[12];
|
||||||
|
|
||||||
static struct multiboot_info mbinfo;
|
static struct multiboot_info mbinfo;
|
||||||
|
|
||||||
static void multiboot_probe(unsigned char *data, int len)
|
static void multiboot_init(void)
|
||||||
|
{
|
||||||
|
mbheader = NULL;
|
||||||
|
mbimgoffset = 0;
|
||||||
|
mboffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember this probing function is actually different from the usual probing
|
||||||
|
* functions, since the Multiboot header is somewhere in the first 8KB of the
|
||||||
|
* image and it is byte aligned, but there is not much more known about how to
|
||||||
|
* find it. In the Etherboot context the most complicated issue is that the
|
||||||
|
* image has to be processed block-by-block, with unknown block size and no
|
||||||
|
* guarantees about block alignment with respect to the image. */
|
||||||
|
static void multiboot_peek(unsigned char *data, int len)
|
||||||
{
|
{
|
||||||
int offset;
|
|
||||||
struct multiboot_header *h;
|
struct multiboot_header *h;
|
||||||
|
|
||||||
/* Multiboot spec requires the header to be in first 8KB of the image */
|
/* If we have already searched the first 8KB of the image or if we have
|
||||||
if (len > 8192)
|
* already found a valid Multiboot header, skip this code. */
|
||||||
len = 8192;
|
if ((mboffset == 12) || (mbimgoffset >= 8192))
|
||||||
|
return;
|
||||||
|
|
||||||
for (offset = 0; offset < len; offset += 4) {
|
if (mbimgoffset + len >= 8192)
|
||||||
h = (struct multiboot_header *) (data + offset);
|
len = 8192 - mbimgoffset;
|
||||||
if (h->magic == MULTIBOOT_HEADER_MAGIC
|
|
||||||
&& h->magic + h->flags + h->checksum == 0) {
|
/* This piece of code is pretty stupid, since it always copies data, even
|
||||||
printf("/Multiboot");
|
* if it is word aligned. This shouldn't matter too much on platforms that
|
||||||
mbheader = h;
|
* use the Multiboot spec, since the processors are usually reasonably fast
|
||||||
return;
|
* and this code is only executed for the first 8KB of the image. Feel
|
||||||
}
|
* free to improve it, but be prepared to write quite a lot of code that
|
||||||
}
|
* deals with non-aligned data with respect to the image to load. */
|
||||||
mbheader = 0;
|
while (len > 0) {
|
||||||
|
mbimgoffset++;
|
||||||
|
memcpy(mbbuffer + mboffset, data, 1);
|
||||||
|
mboffset++;
|
||||||
|
data++;
|
||||||
|
len--;
|
||||||
|
if (mboffset == 4) {
|
||||||
|
/* Accumulated a word into the buffer. */
|
||||||
|
h = (struct multiboot_header *)mbbuffer;
|
||||||
|
if (h->magic != MULTIBOOT_HEADER_MAGIC) {
|
||||||
|
/* Wrong magic, this cannot be the start of the header. */
|
||||||
|
mboffset = 0;
|
||||||
|
}
|
||||||
|
} else if (mboffset == 12) {
|
||||||
|
/* Accumulated the minimum header data into the buffer. */
|
||||||
|
h = (struct multiboot_header *)mbbuffer;
|
||||||
|
if (h->magic + h->flags + h->checksum != 0) {
|
||||||
|
/* Checksum error, not a valid header. Check for a possible
|
||||||
|
* header starting in the current flag/checksum field. */
|
||||||
|
if (h->flags == MULTIBOOT_HEADER_MAGIC) {
|
||||||
|
mboffset -= 4;
|
||||||
|
memmove(mbbuffer, mbbuffer + 4, mboffset);
|
||||||
|
} else if (h->checksum == MULTIBOOT_HEADER_MAGIC) {
|
||||||
|
mboffset -= 8;
|
||||||
|
memmove(mbbuffer, mbbuffer + 8, mboffset);
|
||||||
|
} else {
|
||||||
|
mboffset = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Multiboot... ");
|
||||||
|
mbheader = h;
|
||||||
|
if ((h->flags & 0xfffc) != 0) {
|
||||||
|
printf("\nERROR: Unsupported Multiboot requirements flags\n");
|
||||||
|
longjmp(restart_etherboot, -2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mbimgoffset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void multiboot_boot(unsigned long entry)
|
static inline void multiboot_boot(unsigned long entry)
|
||||||
|
@ -94,7 +148,7 @@ static inline void multiboot_boot(unsigned long entry)
|
||||||
* strings of the maximum size are possible. Note this buffer
|
* strings of the maximum size are possible. Note this buffer
|
||||||
* can overrun if a stupid file name is chosen. Oh well. */
|
* can overrun if a stupid file name is chosen. Oh well. */
|
||||||
c = cmdline;
|
c = cmdline;
|
||||||
for (i = 0; KERNEL_BUF[i] != 0; i++) {
|
for (i = 0; KERNEL_BUF[i] != '\0'; i++) {
|
||||||
switch (KERNEL_BUF[i]) {
|
switch (KERNEL_BUF[i]) {
|
||||||
case ' ':
|
case ' ':
|
||||||
case '\\':
|
case '\\':
|
||||||
|
@ -106,6 +160,11 @@ static inline void multiboot_boot(unsigned long entry)
|
||||||
}
|
}
|
||||||
*c++ = KERNEL_BUF[i];
|
*c++ = KERNEL_BUF[i];
|
||||||
}
|
}
|
||||||
|
if (addparam != NULL) {
|
||||||
|
*c++ = ' ';
|
||||||
|
memcpy(c, addparam, addparamlen);
|
||||||
|
c += addparamlen;
|
||||||
|
}
|
||||||
(void)sprintf(c, " -retaddr %#lX", virt_to_phys(xend32));
|
(void)sprintf(c, " -retaddr %#lX", virt_to_phys(xend32));
|
||||||
|
|
||||||
mbinfo.flags = MULTIBOOT_MMAP_VALID | MULTIBOOT_MEM_VALID |MULTIBOOT_CMDLINE_VALID;
|
mbinfo.flags = MULTIBOOT_MMAP_VALID | MULTIBOOT_MEM_VALID |MULTIBOOT_CMDLINE_VALID;
|
||||||
|
@ -139,5 +198,11 @@ static inline void multiboot_boot(unsigned long entry)
|
||||||
os_regs.eax = 0x2BADB002;
|
os_regs.eax = 0x2BADB002;
|
||||||
os_regs.ebx = virt_to_phys(&mbinfo);
|
os_regs.ebx = virt_to_phys(&mbinfo);
|
||||||
xstart32(entry);
|
xstart32(entry);
|
||||||
longjmp(restart_etherboot, -2);
|
/* A Multiboot kernel by default never returns - there is nothing in the
|
||||||
|
* specification about what happens to the boot loader after the kernel has
|
||||||
|
* been started. Thus if the kernel returns it is definitely aware of the
|
||||||
|
* semantics involved (i.e. the "-retaddr" parameter). Do not treat this
|
||||||
|
* as an error, but restart with a fresh DHCP request in order to activate
|
||||||
|
* the menu again in case one is used. */
|
||||||
|
longjmp(restart_etherboot, 2);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue