~ubuntu-branches/ubuntu/oneiric/base-installer/oneiric

« back to all changes in this revision

Viewing changes to dmi-available-memory.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2010-10-21 16:29:45 UTC
  • mfrom: (0.2.12 sid)
  • Revision ID: james.westby@ubuntu.com-20101021162945-hoyg6dy83kevgli5
Tags: 1.113ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - Use and depend on the Ubuntu keyring.
  - Enable the restricted component by default, unless
    apt-setup/restricted is preseeded to false.
  - Set up the default sources.list to look in -updates and -security (the
    latter from apt-setup/security_host) as well as the unadorned suite;
    also -proposed if apt-setup/proposed is true.
  - Use Ubuntu kernel image names.
  - Allow preseeding base-installer/kernel/override-image to force a given
    kernel to be used.
  - Install busybox-initramfs rather than busybox.
  - Revert Joey's patch to call base-installer.d hooks after running
    debootstrap, which broke console-setup's expectation of being able to
    insert its configuration file into /target before console-setup is
    installed by debootstrap.
  - Add armel/imx51, armel/dove, and armel/omap subarchitectures.
  - Install kernel headers to match the kernel. This may be overridden by
    setting base-installer/kernel/headers to false.
  - Add base-installer/kernel/backports-modules template, which may be
    preseeded to install selected linux-backports-modules-* packages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Some code here borrowed from dmidecode, also GPLed and copyrighted by:
2
 
 *   (C) 2000-2002 Alan Cox <alan@redhat.com>
3
 
 *   (C) 2002-2005 Jean Delvare <khali@linux-fr.org>
4
 
 * I (Colin Watson) copied it in reduced form rather than using dmidecode
5
 
 * directly because (a) the d-i initrd is tight on space and this is much
6
 
 * smaller and (b) parsing the output of dmidecode in shell is unreasonably
7
 
 * painful.
8
 
 */
9
 
 
10
 
#include <stdlib.h>
11
 
#include <string.h>
12
 
#include <stdint.h>
13
 
#include <unistd.h>
14
 
#include <sys/mman.h>
15
 
#include <sys/types.h>
16
 
#include <sys/stat.h>
17
 
#include <fcntl.h>
18
 
#include <stdio.h>
19
 
 
20
 
#define WORD(x) (*(const uint16_t *)(x))
21
 
#define DWORD(x) (*(const uint32_t *)(x))
22
 
 
23
 
struct dmi_header
24
 
{
25
 
        uint8_t type;
26
 
        uint8_t length;
27
 
        uint16_t handle;
28
 
};
29
 
 
30
 
static int checksum(const uint8_t *buf, size_t len)
31
 
{
32
 
        uint8_t sum = 0;
33
 
        size_t a;
34
 
 
35
 
        for (a = 0; a < len; a++)
36
 
                sum += buf[a];
37
 
        return (sum == 0);
38
 
}
39
 
 
40
 
/* Copy a physical memory chunk into a memory buffer.
41
 
 * This function allocates memory.
42
 
 */
43
 
static void *mem_chunk(size_t base, size_t len)
44
 
{
45
 
        void *p;
46
 
        int fd;
47
 
        size_t mmoffset;
48
 
        void *mmp;
49
 
 
50
 
        fd = open("/dev/mem", O_RDONLY);
51
 
        if (fd == -1)
52
 
                return NULL;
53
 
 
54
 
        p = malloc(len);
55
 
        if (p == NULL)
56
 
        {
57
 
                close(fd);
58
 
                return NULL;
59
 
        }
60
 
 
61
 
#ifdef _SC_PAGESIZE
62
 
        mmoffset = base % sysconf(_SC_PAGESIZE);
63
 
#else
64
 
        mmoffset = base % getpagesize();
65
 
#endif
66
 
        /* Please note that we don't use mmap() for performance reasons here,
67
 
         * but to workaround problems many people encountered when trying
68
 
         * to read from /dev/mem using regular read() calls.
69
 
         */
70
 
        mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd,
71
 
                   base - mmoffset);
72
 
        if (mmp == MAP_FAILED)
73
 
        {
74
 
                free(p);
75
 
                close(fd);
76
 
                return NULL;
77
 
        }
78
 
 
79
 
        memcpy(p, mmp + mmoffset, len);
80
 
 
81
 
        munmap(mmp, mmoffset + len);
82
 
 
83
 
        close(fd);
84
 
 
85
 
        return p;
86
 
}
87
 
 
88
 
static uint64_t dmi_table(uint32_t base, uint16_t len, uint16_t num)
89
 
{
90
 
        uint8_t *buf, *data;
91
 
        int i = 0;
92
 
        uint64_t available = 0;
93
 
 
94
 
        buf = mem_chunk(base, len);
95
 
        if (buf == NULL)
96
 
                return 0;
97
 
 
98
 
        data = buf;
99
 
        while (i < num && data + sizeof(struct dmi_header) <= buf + len)
100
 
        {
101
 
                uint8_t *next;
102
 
                struct dmi_header *h = (struct dmi_header *)data;
103
 
 
104
 
                /* Stop decoding at end of table marker */
105
 
                if (h->type == 127)
106
 
                        break;
107
 
 
108
 
                /* Look for the next handle */
109
 
                next = data + h->length;
110
 
                while (next - buf + 1 < len && (next[0] != 0 || next[1] != 0))
111
 
                        next++;
112
 
                next += 2;
113
 
                /* Memory Array Mapped Address */
114
 
                if (h->type == 19 && h->length >= 0x0F)
115
 
                {
116
 
                        uint64_t start, end;
117
 
                        start = DWORD(data + 0x04);
118
 
                        end = DWORD(data + 0x08);
119
 
                        if (end >= start)
120
 
                                /* output in kilobytes */
121
 
                                available += end - start + 1;
122
 
                }
123
 
 
124
 
                data = next;
125
 
                i++;
126
 
        }
127
 
 
128
 
        free(buf);
129
 
        return available;
130
 
}
131
 
 
132
 
static uint64_t smbios_decode(uint8_t *buf)
133
 
{
134
 
        if (checksum(buf, buf[0x05]) &&
135
 
            memcmp(buf + 0x10, "_DMI_", 5) == 0 &&
136
 
            checksum(buf + 0x10, 0x0F))
137
 
        {
138
 
                return dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16),
139
 
                                 WORD(buf + 0x1C));
140
 
        }
141
 
 
142
 
        return 0;
143
 
}
144
 
 
145
 
static uint64_t legacy_decode(uint8_t *buf)
146
 
{
147
 
        if (checksum(buf, 0x0F))
148
 
        {
149
 
                return dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06),
150
 
                                 WORD(buf + 0x0C));
151
 
        }
152
 
 
153
 
        return 0;
154
 
}
155
 
 
156
 
static uint64_t dmi_available_memory(void)
157
 
{
158
 
        uint8_t *buf;
159
 
        size_t fp;
160
 
        uint64_t ret = 0;
161
 
 
162
 
        buf = mem_chunk(0xF0000, 0x10000);
163
 
        if (buf == NULL)
164
 
                return 0;
165
 
 
166
 
        for (fp = 0; fp <= 0xFFF0; fp += 16)
167
 
        {
168
 
                if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0)
169
 
                {
170
 
                        ret = smbios_decode(buf + fp);
171
 
                        if (ret)
172
 
                                break;
173
 
                        fp += 16;
174
 
                }
175
 
                else if (memcmp(buf + fp, "_DMI_", 5) == 0)
176
 
                {
177
 
                        ret = legacy_decode(buf + fp);
178
 
                        if (ret)
179
 
                                break;
180
 
                }
181
 
        }
182
 
 
183
 
        free(buf);
184
 
        return ret;
185
 
}
186
 
 
187
 
int main(int argc, char **argv)
188
 
{
189
 
        printf("%llu\n", dmi_available_memory());
190
 
        return 0;
191
 
}