aboutsummaryrefslogtreecommitdiff
path: root/e820.c
blob: 627135321ff9378b6a2268df574425429919a8f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "bios.h"
#include "segment.h"

#include "processor-flags.h"
#include "e820.h"

static inline void set_fs(uint16_t seg)
{
	asm volatile("movw %0,%%fs" : : "rm" (seg));
}

static inline uint8_t rdfs8(unsigned long addr)
{
	uint8_t v;

	asm volatile("addr32 movb %%fs:%1,%0" : "=q" (v) : "m" (*(uint8_t *)addr));

	return v;
}

static inline uint32_t rdfs32(unsigned long addr)
{
	uint32_t v;

	asm volatile("addr32 movl %%fs:%1,%0" : "=q" (v) : "m" (*(uint32_t *)addr));

	return v;
}

struct e820map e820;

bioscall void e820_query_map(struct biosregs *regs)
{
	uint32_t map_size;
	uint16_t fs_seg;
	uint32_t ndx;

	fs_seg		= flat_to_seg16((uintptr_t) &e820);
	set_fs(fs_seg);

	ndx		= regs->ebx;

	map_size	= rdfs32(flat_to_off16((uintptr_t) &e820.nr_map));

	if (ndx < map_size) {
		uint32_t start;
		unsigned int i;
		uint8_t *p;

		start	= flat_to_off16((uintptr_t)&e820.map[ndx]);

		p	= (void *) regs->edi;

		for (i = 0; i < sizeof(struct e820entry); i++)
			*p++	= rdfs8(start + i);
	}

	regs->eax	= SMAP;
	regs->ecx	= sizeof(struct e820entry);
	regs->ebx	= ++ndx;

	/* Clear CF to indicate success.  */
	regs->eflags	&= ~X86_EFLAGS_CF;

	if (ndx >= map_size)
		regs->ebx	= 0;	/* end of map */
}