Skip to content

Commit b3c72fc

Browse files
Daniel Kipersuryasaimadhu
Daniel Kiper
authored andcommitted
x86/boot: Introduce setup_indirect
The setup_data is a bit awkward to use for extremely large data objects, both because the setup_data header has to be adjacent to the data object and because it has a 32-bit length field. However, it is important that intermediate stages of the boot process have a way to identify which chunks of memory are occupied by kernel data. Thus introduce an uniform way to specify such indirect data as setup_indirect struct and SETUP_INDIRECT type. And finally bump setup_header version in arch/x86/boot/header.S. Suggested-by: H. Peter Anvin (Intel) <hpa@zytor.com> Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Ross Philipson <ross.philipson@oracle.com> Reviewed-by: H. Peter Anvin (Intel) <hpa@zytor.com> Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: ard.biesheuvel@linaro.org Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: dave.hansen@linux.intel.com Cc: eric.snowberg@oracle.com Cc: Ingo Molnar <mingo@redhat.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Juergen Gross <jgross@suse.com> Cc: kanth.ghatraju@oracle.com Cc: linux-doc@vger.kernel.org Cc: linux-efi <linux-efi@vger.kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: rdunlap@infradead.org Cc: ross.philipson@oracle.com Cc: Thomas Gleixner <tglx@linutronix.de> Cc: x86-ml <x86@kernel.org> Cc: xen-devel@lists.xenproject.org Link: https://lkml.kernel.org/r/20191112134640.16035-4-daniel.kiper@oracle.com
1 parent 00cd1c1 commit b3c72fc

File tree

10 files changed

+138
-17
lines changed

10 files changed

+138
-17
lines changed

Documentation/x86/boot.rst

+42-1
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,47 @@ Protocol: 2.09+
827827
sure to consider the case where the linked list already contains
828828
entries.
829829

830+
The setup_data is a bit awkward to use for extremely large data objects,
831+
both because the setup_data header has to be adjacent to the data object
832+
and because it has a 32-bit length field. However, it is important that
833+
intermediate stages of the boot process have a way to identify which
834+
chunks of memory are occupied by kernel data.
835+
836+
Thus setup_indirect struct and SETUP_INDIRECT type were introduced in
837+
protocol 2.15.
838+
839+
struct setup_indirect {
840+
__u32 type;
841+
__u32 reserved; /* Reserved, must be set to zero. */
842+
__u64 len;
843+
__u64 addr;
844+
};
845+
846+
The type member is a SETUP_INDIRECT | SETUP_* type. However, it cannot be
847+
SETUP_INDIRECT itself since making the setup_indirect a tree structure
848+
could require a lot of stack space in something that needs to parse it
849+
and stack space can be limited in boot contexts.
850+
851+
Let's give an example how to point to SETUP_E820_EXT data using setup_indirect.
852+
In this case setup_data and setup_indirect will look like this:
853+
854+
struct setup_data {
855+
__u64 next = 0 or <addr_of_next_setup_data_struct>;
856+
__u32 type = SETUP_INDIRECT;
857+
__u32 len = sizeof(setup_data);
858+
__u8 data[sizeof(setup_indirect)] = struct setup_indirect {
859+
__u32 type = SETUP_INDIRECT | SETUP_E820_EXT;
860+
__u32 reserved = 0;
861+
__u64 len = <len_of_SETUP_E820_EXT_data>;
862+
__u64 addr = <addr_of_SETUP_E820_EXT_data>;
863+
}
864+
}
865+
866+
.. note::
867+
SETUP_INDIRECT | SETUP_NONE objects cannot be properly distinguished
868+
from SETUP_INDIRECT itself. So, this kind of objects cannot be provided
869+
by the bootloaders.
870+
830871
============ ============
831872
Field name: pref_address
832873
Type: read (reloc)
@@ -986,7 +1027,7 @@ Field name: setup_type_max
9861027
Offset/size: 0x000c/4
9871028
============ ==============
9881029

989-
This field contains maximal allowed type for setup_data.
1030+
This field contains maximal allowed type for setup_data and setup_indirect structs.
9901031

9911032

9921033
The Image Checksum

arch/x86/boot/compressed/kaslr.c

+12
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,18 @@ static bool mem_avoid_overlap(struct mem_vector *img,
459459
is_overlapping = true;
460460
}
461461

462+
if (ptr->type == SETUP_INDIRECT &&
463+
((struct setup_indirect *)ptr->data)->type != SETUP_INDIRECT) {
464+
avoid.start = ((struct setup_indirect *)ptr->data)->addr;
465+
avoid.size = ((struct setup_indirect *)ptr->data)->len;
466+
467+
if (mem_overlaps(img, &avoid) && (avoid.start < earliest)) {
468+
*overlap = avoid;
469+
earliest = overlap->start;
470+
is_overlapping = true;
471+
}
472+
}
473+
462474
ptr = (struct setup_data *)(unsigned long)ptr->next;
463475
}
464476

arch/x86/boot/compressed/kernel_info.S

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ kernel_info:
1414
/* Size total. */
1515
.long kernel_info_end - kernel_info
1616

17-
/* Maximal allowed type for setup_data. */
17+
/* Maximal allowed type for setup_data and setup_indirect structs. */
1818
.long SETUP_TYPE_MAX
1919

2020
kernel_info_var_len_data:

arch/x86/boot/header.S

+1-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ _start:
300300
# Part 2 of the header, from the old setup.S
301301

302302
.ascii "HdrS" # header signature
303-
.word 0x020d # header version number (>= 0x0105)
303+
.word 0x020f # header version number (>= 0x0105)
304304
# or else old loadlin-1.5 will fail)
305305
.globl realmode_swtch
306306
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG

arch/x86/include/uapi/asm/bootparam.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#ifndef _ASM_X86_BOOTPARAM_H
33
#define _ASM_X86_BOOTPARAM_H
44

5-
/* setup_data types */
5+
/* setup_data/setup_indirect types */
66
#define SETUP_NONE 0
77
#define SETUP_E820_EXT 1
88
#define SETUP_DTB 2
@@ -11,8 +11,10 @@
1111
#define SETUP_APPLE_PROPERTIES 5
1212
#define SETUP_JAILHOUSE 6
1313

14-
/* max(SETUP_*) */
15-
#define SETUP_TYPE_MAX SETUP_JAILHOUSE
14+
#define SETUP_INDIRECT (1<<31)
15+
16+
/* SETUP_INDIRECT | max(SETUP_*) */
17+
#define SETUP_TYPE_MAX (SETUP_INDIRECT | SETUP_JAILHOUSE)
1618

1719
/* ram_size flags */
1820
#define RAMDISK_IMAGE_START_MASK 0x07FF
@@ -52,6 +54,14 @@ struct setup_data {
5254
__u8 data[0];
5355
};
5456

57+
/* extensible setup indirect data node */
58+
struct setup_indirect {
59+
__u32 type;
60+
__u32 reserved; /* Reserved, must be set to zero. */
61+
__u64 len;
62+
__u64 addr;
63+
};
64+
5565
struct setup_header {
5666
__u8 setup_sects;
5767
__u16 root_flags;

arch/x86/kernel/e820.c

+11
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,17 @@ void __init e820__reserve_setup_data(void)
999999
data = early_memremap(pa_data, sizeof(*data));
10001000
e820__range_update(pa_data, sizeof(*data)+data->len, E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
10011001
e820__range_update_kexec(pa_data, sizeof(*data)+data->len, E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
1002+
1003+
if (data->type == SETUP_INDIRECT &&
1004+
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) {
1005+
e820__range_update(((struct setup_indirect *)data->data)->addr,
1006+
((struct setup_indirect *)data->data)->len,
1007+
E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
1008+
e820__range_update_kexec(((struct setup_indirect *)data->data)->addr,
1009+
((struct setup_indirect *)data->data)->len,
1010+
E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
1011+
}
1012+
10021013
pa_data = data->next;
10031014
early_memunmap(data, sizeof(*data));
10041015
}

arch/x86/kernel/kdebugfs.c

+17-4
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ static ssize_t setup_data_read(struct file *file, char __user *user_buf,
4444
if (count > node->len - pos)
4545
count = node->len - pos;
4646

47-
pa = node->paddr + sizeof(struct setup_data) + pos;
47+
pa = node->paddr + pos;
48+
49+
/* Is it direct data or invalid indirect one? */
50+
if (!(node->type & SETUP_INDIRECT) || node->type == SETUP_INDIRECT)
51+
pa += sizeof(struct setup_data);
52+
4853
p = memremap(pa, count, MEMREMAP_WB);
4954
if (!p)
5055
return -ENOMEM;
@@ -108,9 +113,17 @@ static int __init create_setup_data_nodes(struct dentry *parent)
108113
goto err_dir;
109114
}
110115

111-
node->paddr = pa_data;
112-
node->type = data->type;
113-
node->len = data->len;
116+
if (data->type == SETUP_INDIRECT &&
117+
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) {
118+
node->paddr = ((struct setup_indirect *)data->data)->addr;
119+
node->type = ((struct setup_indirect *)data->data)->type;
120+
node->len = ((struct setup_indirect *)data->data)->len;
121+
} else {
122+
node->paddr = pa_data;
123+
node->type = data->type;
124+
node->len = data->len;
125+
}
126+
114127
create_setup_data_node(d, no, node);
115128
pa_data = data->next;
116129

arch/x86/kernel/ksysfs.c

+24-7
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,12 @@ static int __init get_setup_data_size(int nr, size_t *size)
100100
if (!data)
101101
return -ENOMEM;
102102
if (nr == i) {
103-
*size = data->len;
103+
if (data->type == SETUP_INDIRECT &&
104+
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT)
105+
*size = ((struct setup_indirect *)data->data)->len;
106+
else
107+
*size = data->len;
108+
104109
memunmap(data);
105110
return 0;
106111
}
@@ -130,7 +135,10 @@ static ssize_t type_show(struct kobject *kobj,
130135
if (!data)
131136
return -ENOMEM;
132137

133-
ret = sprintf(buf, "0x%x\n", data->type);
138+
if (data->type == SETUP_INDIRECT)
139+
ret = sprintf(buf, "0x%x\n", ((struct setup_indirect *)data->data)->type);
140+
else
141+
ret = sprintf(buf, "0x%x\n", data->type);
134142
memunmap(data);
135143
return ret;
136144
}
@@ -142,7 +150,7 @@ static ssize_t setup_data_data_read(struct file *fp,
142150
loff_t off, size_t count)
143151
{
144152
int nr, ret = 0;
145-
u64 paddr;
153+
u64 paddr, len;
146154
struct setup_data *data;
147155
void *p;
148156

@@ -157,19 +165,28 @@ static ssize_t setup_data_data_read(struct file *fp,
157165
if (!data)
158166
return -ENOMEM;
159167

160-
if (off > data->len) {
168+
if (data->type == SETUP_INDIRECT &&
169+
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) {
170+
paddr = ((struct setup_indirect *)data->data)->addr;
171+
len = ((struct setup_indirect *)data->data)->len;
172+
} else {
173+
paddr += sizeof(*data);
174+
len = data->len;
175+
}
176+
177+
if (off > len) {
161178
ret = -EINVAL;
162179
goto out;
163180
}
164181

165-
if (count > data->len - off)
166-
count = data->len - off;
182+
if (count > len - off)
183+
count = len - off;
167184

168185
if (!count)
169186
goto out;
170187

171188
ret = count;
172-
p = memremap(paddr + sizeof(*data), data->len, MEMREMAP_WB);
189+
p = memremap(paddr, len, MEMREMAP_WB);
173190
if (!p) {
174191
ret = -ENOMEM;
175192
goto out;

arch/x86/kernel/setup.c

+6
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,12 @@ static void __init memblock_x86_reserve_range_setup_data(void)
438438
while (pa_data) {
439439
data = early_memremap(pa_data, sizeof(*data));
440440
memblock_reserve(pa_data, sizeof(*data) + data->len);
441+
442+
if (data->type == SETUP_INDIRECT &&
443+
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT)
444+
memblock_reserve(((struct setup_indirect *)data->data)->addr,
445+
((struct setup_indirect *)data->data)->len);
446+
441447
pa_data = data->next;
442448
early_memunmap(data, sizeof(*data));
443449
}

arch/x86/mm/ioremap.c

+11
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,17 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
626626
paddr_next = data->next;
627627
len = data->len;
628628

629+
if ((phys_addr > paddr) && (phys_addr < (paddr + len))) {
630+
memunmap(data);
631+
return true;
632+
}
633+
634+
if (data->type == SETUP_INDIRECT &&
635+
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) {
636+
paddr = ((struct setup_indirect *)data->data)->addr;
637+
len = ((struct setup_indirect *)data->data)->len;
638+
}
639+
629640
memunmap(data);
630641

631642
if ((phys_addr > paddr) && (phys_addr < (paddr + len)))

0 commit comments

Comments
 (0)