1 /* Support for Multiboot */
2 
3 #include "config.h"
4 #include "asm/io.h"
5 #include "libopenbios/sys_info.h"
6 #include "multiboot.h"
7 
8 #ifdef CONFIG_DEBUG_BOOT
9 #define debug printk
10 #else
11 #define debug(x...)
12 #endif
13 
14 struct mbheader {
15     unsigned int magic, flags, checksum;
16 };
17 
18 const struct mbheader multiboot_header
19 	__attribute__((section (".hdr"))) =
20 {
21     MULTIBOOT_HEADER_MAGIC,
22     MULTIBOOT_HEADER_FLAGS,
23     -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
24 };
25 
26 /* Multiboot information structure, provided by loader to us */
27 
28 struct multiboot_mmap {
29 	unsigned entry_size;
30 	unsigned base_lo, base_hi;
31 	unsigned size_lo, size_hi;
32 	unsigned type;
33 };
34 
35 #define MULTIBOOT_MEM_VALID       0x01
36 #define MULTIBOOT_BOOT_DEV_VALID  0x02
37 #define MULTIBOOT_CMDLINE_VALID   0x04
38 #define MULTIBOOT_MODS_VALID      0x08
39 #define MULTIBOOT_AOUT_SYMS_VALID 0x10
40 #define MULTIBOOT_ELF_SYMS_VALID  0x20
41 #define MULTIBOOT_MMAP_VALID      0x40
42 
43 void collect_multiboot_info(struct sys_info *info);
collect_multiboot_info(struct sys_info * info)44 void collect_multiboot_info(struct sys_info *info)
45 {
46     struct multiboot_info *mbinfo;
47     struct multiboot_mmap *mbmem;
48     unsigned mbcount, mbaddr;
49     int i;
50     struct memrange *mmap;
51     int mmap_count;
52     module_t *mod;
53 
54     if (info->boot_type != 0x2BADB002)
55 	return;
56 
57     debug("Using Multiboot information at %#lx\n", info->boot_data);
58 
59     mbinfo = phys_to_virt(info->boot_data);
60 
61     if (mbinfo->mods_count != 1) {
62 	    printk("multiboot: no dictionary\n");
63 	    return;
64     }
65 
66     mod = (module_t *) mbinfo->mods_addr;
67     info->dict_start=(unsigned long *)mod->mod_start;
68     info->dict_end=(unsigned long *)mod->mod_end;
69     debug("multiboot: dictionary at %p-%p\n",
70 		    info->dict_start, info->dict_end);
71 
72     if (mbinfo->flags & MULTIBOOT_MMAP_VALID) {
73 	/* convert mmap records */
74 	mbmem = phys_to_virt(mbinfo->mmap_addr);
75 	mbcount = mbinfo->mmap_length / (mbmem->entry_size + 4);
76 	mmap = malloc(mbcount * sizeof(struct memrange));
77 	mmap_count = 0;
78 	mbaddr = mbinfo->mmap_addr;
79 	for (i = 0; i < mbcount; i++) {
80 	    mbmem = phys_to_virt(mbaddr);
81 	    debug("%08x%08x %08x%08x (%d)\n",
82 		    mbmem->base_hi,
83 		    mbmem->base_lo,
84 		    mbmem->size_hi,
85 		    mbmem->size_lo,
86 		    mbmem->type);
87 	    if (mbmem->type == 1) { /* Only normal RAM */
88 		mmap[mmap_count].base = mbmem->base_lo
89 		    + (((unsigned long long) mbmem->base_hi) << 32);
90 		mmap[mmap_count].size = mbmem->size_lo
91 		    + (((unsigned long long) mbmem->size_hi) << 32);
92 		mmap_count++;
93 	    }
94 	    mbaddr += mbmem->entry_size + 4;
95 	    if (mbaddr >= mbinfo->mmap_addr + mbinfo->mmap_length)
96 		break;
97 	}
98 	/* simple sanity check - there should be at least 2 RAM segments
99 	 * (base 640k and extended) */
100 	if (mmap_count >= 2)
101 	    goto got_it;
102 
103 	printk("Multiboot mmap is broken\n");
104 	free(mmap);
105 	/* fall back to mem_lower/mem_upper */
106     }
107 
108     if (mbinfo->flags & MULTIBOOT_MEM_VALID) {
109 	/* use mem_lower and mem_upper */
110 	mmap_count = 2;
111 	mmap = malloc(2 * sizeof(*mmap));
112 	mmap[0].base = 0;
113 	mmap[0].size = mbinfo->mem_lower << 10;
114 	mmap[1].base = 1 << 20; /* 1MB */
115 	mmap[1].size = mbinfo->mem_upper << 10;
116 	goto got_it;
117     }
118 
119     printk("Can't get memory information from Multiboot\n");
120     return;
121 
122 got_it:
123     info->memrange = mmap;
124     info->n_memranges = mmap_count;
125 
126     return;
127 }
128