Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / libopenbios / linuxbios_info.c
1 /* Adapted from Etherboot 5.1.8 */
2
3 #include "config.h"
4 #include "sysinclude.h"
5 #include "asm/types.h"
6 #include "asm/io.h"
7 #include "linuxbios.h"
8 #include "libopenbios/ipchecksum.h"
9 #include "libopenbios/sys_info.h"
10
11 #ifdef CONFIG_DEBUG_BOOT
12 #define debug printk
13 #else
14 #define debug(x...)
15 #endif
16
17 #define for_each_lbrec(head, rec) \
18         for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
19                 (((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes))  && \
20                 (rec->size >= 1) && \
21                 ((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
22                 rec = (struct lb_record *)(((char *)rec) + rec->size))
23
24 static void convert_memmap(struct lb_memory *lbmem, struct sys_info *info)
25 {
26     int lbcount;
27     int i;
28
29     lbcount = lbmem->size / sizeof(struct lb_memory_range);
30     info->memrange = malloc(lbcount * sizeof(struct memrange));
31     info->n_memranges = 0;
32     for (i = 0; i < lbcount; i++) {
33         debug("%#016llx %#016llx %d\n",
34               (long long)lbmem->map[i].start, (long long)lbmem->map[i].size,
35               (int) lbmem->map[i].type);
36         if (lbmem->map[i].type != LB_MEM_RAM)
37             continue;
38         info->memrange[info->n_memranges].base = lbmem->map[i].start;
39         info->memrange[info->n_memranges].size = lbmem->map[i].size;
40         info->n_memranges++;
41     }
42 }
43
44 static int read_lbtable(struct lb_header *head, struct sys_info *info)
45 {
46         int retval = 0;
47
48         /* Read linuxbios tables... */
49         struct lb_record *rec;
50
51         for_each_lbrec(head, rec) {
52                 switch(rec->tag) {
53                 case LB_TAG_MEMORY:
54                         convert_memmap((struct lb_memory *) rec, info);
55                         retval = 1;
56                         break;
57                 };
58         }
59         return retval;
60 }
61
62 static unsigned long count_lb_records(void *start, unsigned long length)
63 {
64         struct lb_record *rec;
65         void *end;
66         unsigned long count;
67         count = 0;
68         end = ((char *)start) + length;
69         for(rec = start; ((void *)rec < end) &&
70                 ((signed long)rec->size <=
71                  ((signed long)end - (signed long)rec));
72                 rec = (void *)(((char *)rec) + rec->size)) {
73                 count++;
74         }
75         return count;
76 }
77
78 static int find_lb_table(void *start, void *end, struct lb_header **result)
79 {
80         unsigned char *ptr;
81         /* For now be stupid.... */
82         for(ptr = start; (void *)ptr < end; ptr += 16) {
83                 struct lb_header *head = (struct lb_header *)ptr;
84                 if (    (head->signature[0] != 'L') ||
85                         (head->signature[1] != 'B') ||
86                         (head->signature[2] != 'I') ||
87                         (head->signature[3] != 'O')) {
88                         continue;
89                 }
90                 if (head->header_bytes != sizeof(*head))
91                         continue;
92                 debug("Found canidate at: %p\n", head);
93                 if (ipchksum((uint16_t *)head, sizeof(*head)) != 0)
94                         continue;
95                 debug("header checksum o.k.\n");
96                 if (ipchksum((uint16_t *)(ptr + sizeof(*head)), head->table_bytes) !=
97                         head->table_checksum) {
98                         continue;
99                 }
100                 debug("table checksum o.k.\n");
101                 if (count_lb_records(ptr + sizeof(*head), head->table_bytes) !=
102                         head->table_entries) {
103                         continue;
104                 }
105                 debug("record count o.k.\n");
106                 *result = head;
107                 return 1;
108         };
109         return 0;
110 }
111
112 void collect_linuxbios_info(struct sys_info *info)
113 {
114         struct lb_header *lb_table;
115         int found;
116         debug("Searching for LinuxBIOS tables...\n");
117         found = 0;
118         if (!found) {
119                 found = find_lb_table(phys_to_virt(0x00000), phys_to_virt(0x01000), &lb_table);
120         }
121         if (!found) {
122                 found = find_lb_table(phys_to_virt(0xf0000), phys_to_virt(0x100000), &lb_table);
123         }
124         if (!found)
125                 return;
126
127         debug("Found LinuxBIOS table at: %p\n", lb_table);
128         info->firmware = "LinuxBIOS";
129         read_lbtable(lb_table, info);
130 }