xref: /kvmtool/x86/bios/e820.c (revision 1cbb2c50ce18b5b2bd780f5a330f7b6e11311105)
1 #include "asm/bios/types.h"
2 #include "kvm/e820.h"
3 
4 #include "kvm/bios.h"
5 
6 #include <asm/processor-flags.h>
7 
flat_to_seg16(u32 address)8 static inline u16 flat_to_seg16(u32 address)
9 {
10 	return address >> 4;
11 }
12 
flat_to_off16(u32 address,u32 segment)13 static inline u16 flat_to_off16(u32 address, u32 segment)
14 {
15 	return address - (segment << 4);
16 }
17 
set_fs(u16 seg)18 static inline void set_fs(u16 seg)
19 {
20 	asm volatile("movw %0,%%fs" : : "rm" (seg));
21 }
22 
rdfs8(unsigned long addr)23 static inline u8 rdfs8(unsigned long addr)
24 {
25 	u8 v;
26 
27 	asm volatile("addr32 movb %%fs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr));
28 
29 	return v;
30 }
31 
rdfs32(unsigned long addr)32 static inline u32 rdfs32(unsigned long addr)
33 {
34 	u32 v;
35 
36 	asm volatile("addr32 movl %%fs:%1,%0" : "=q" (v) : "m" (*(u32 *)addr));
37 
38 	return v;
39 }
40 
e820_query_map(struct biosregs * regs)41 bioscall void e820_query_map(struct biosregs *regs)
42 {
43 	struct e820map *e820;
44 	u32 map_size;
45 	u16 fs_seg;
46 	u32 ndx;
47 
48 	e820		= (struct e820map *)E820_MAP_START;
49 	fs_seg		= flat_to_seg16(E820_MAP_START);
50 	set_fs(fs_seg);
51 
52 	ndx		= regs->ebx;
53 
54 	map_size	= rdfs32(flat_to_off16((u32)&e820->nr_map, fs_seg));
55 
56 	if (ndx < map_size) {
57 		u32 start;
58 		unsigned int i;
59 		u8 *p;
60 
61 		fs_seg	= flat_to_seg16(E820_MAP_START);
62 		set_fs(fs_seg);
63 
64 		start	= (u32)&e820->map[ndx];
65 
66 		p	= (void *) regs->edi;
67 
68 		for (i = 0; i < sizeof(struct e820entry); i++)
69 			*p++	= rdfs8(flat_to_off16(start + i, fs_seg));
70 	}
71 
72 	regs->eax	= SMAP;
73 	regs->ecx	= sizeof(struct e820entry);
74 	regs->ebx	= ++ndx;
75 
76 	/* Clear CF to indicate success.  */
77 	regs->eflags	&= ~X86_EFLAGS_CF;
78 
79 	if (ndx >= map_size)
80 		regs->ebx	= 0;	/* end of map */
81 }
82