~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/openbios/libopenbios/linuxbios_info.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}