Skip to content

Commit 9338c22

Browse files
rosslagerwalljgross1
authored andcommitted
iscsi_ibft: Fix finding the iBFT under Xen Dom 0
To facilitate diskless iSCSI boot, the firmware can place a table of configuration details in memory called the iBFT. The presence of this table is not specified, nor is the precise location (and it's not in the E820) so the kernel has to search for a magic marker to find it. When running under Xen, Dom 0 does not have access to the entire host's memory, only certain regions which are identity-mapped which means that the pseudo-physical address in Dom0 == real host physical address. Add the iBFT search bounds as a reserved region which causes it to be identity-mapped in xen_set_identity_and_remap_chunk() which allows Dom0 access to the specific physical memory to correctly search for the iBFT magic marker (and later access the full table). This necessitates moving the call to reserve_ibft_region() somewhat later so that it is called after e820__memory_setup() which is when the Xen identity mapping adjustments are applied. The precise location of the call is not too important so I've put it alongside dmi_setup() which does similar scanning of memory for configuration tables. Finally in the iBFT find code, instead of using isa_bus_to_virt() which doesn't do the right thing under Xen, use early_memremap() like the dmi_setup() code does. The result of these changes is that it is possible to boot a diskless Xen + Dom0 running off an iSCSI disk whereas previously it would fail to find the iBFT and consequently, the iSCSI root disk. Signed-off-by: Ross Lagerwall <[email protected]> Reviewed-by: Juergen Gross <[email protected]> Acked-by: Konrad Rzeszutek Wilk <[email protected]> Acked-by: Dave Hansen <[email protected]> # for x86 Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Juergen Gross <[email protected]>
1 parent 04d6848 commit 9338c22

File tree

4 files changed

+46
-20
lines changed

4 files changed

+46
-20
lines changed

arch/x86/kernel/setup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,6 @@ static void __init early_reserve_memory(void)
796796

797797
memblock_x86_reserve_range_setup_data();
798798

799-
reserve_ibft_region();
800799
reserve_bios_regions();
801800
trim_snb_memory();
802801
}
@@ -1032,6 +1031,7 @@ void __init setup_arch(char **cmdline_p)
10321031
if (efi_enabled(EFI_BOOT))
10331032
efi_init();
10341033

1034+
reserve_ibft_region();
10351035
dmi_setup();
10361036

10371037
/*

arch/x86/xen/setup.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#include <linux/init.h>
9+
#include <linux/iscsi_ibft.h>
910
#include <linux/sched.h>
1011
#include <linux/kstrtox.h>
1112
#include <linux/mm.h>
@@ -764,17 +765,26 @@ char * __init xen_memory_setup(void)
764765
BUG_ON(memmap.nr_entries == 0);
765766
xen_e820_table.nr_entries = memmap.nr_entries;
766767

767-
/*
768-
* Xen won't allow a 1:1 mapping to be created to UNUSABLE
769-
* regions, so if we're using the machine memory map leave the
770-
* region as RAM as it is in the pseudo-physical map.
771-
*
772-
* UNUSABLE regions in domUs are not handled and will need
773-
* a patch in the future.
774-
*/
775-
if (xen_initial_domain())
768+
if (xen_initial_domain()) {
769+
/*
770+
* Xen won't allow a 1:1 mapping to be created to UNUSABLE
771+
* regions, so if we're using the machine memory map leave the
772+
* region as RAM as it is in the pseudo-physical map.
773+
*
774+
* UNUSABLE regions in domUs are not handled and will need
775+
* a patch in the future.
776+
*/
776777
xen_ignore_unusable();
777778

779+
#ifdef CONFIG_ISCSI_IBFT_FIND
780+
/* Reserve 0.5 MiB to 1 MiB region so iBFT can be found */
781+
xen_e820_table.entries[xen_e820_table.nr_entries].addr = IBFT_START;
782+
xen_e820_table.entries[xen_e820_table.nr_entries].size = IBFT_END - IBFT_START;
783+
xen_e820_table.entries[xen_e820_table.nr_entries].type = E820_TYPE_RESERVED;
784+
xen_e820_table.nr_entries++;
785+
#endif
786+
}
787+
778788
/* Make sure the Xen-supplied memory map is well-ordered. */
779789
e820__update_table(&xen_e820_table);
780790

drivers/firmware/iscsi_ibft_find.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ static const struct {
4242
};
4343

4444
#define IBFT_SIGN_LEN 4
45-
#define IBFT_START 0x80000 /* 512kB */
46-
#define IBFT_END 0x100000 /* 1MB */
4745
#define VGA_MEM 0xA0000 /* VGA buffer */
4846
#define VGA_SIZE 0x20000 /* 128kB */
4947

@@ -52,9 +50,9 @@ static const struct {
5250
*/
5351
void __init reserve_ibft_region(void)
5452
{
55-
unsigned long pos;
53+
unsigned long pos, virt_pos = 0;
5654
unsigned int len = 0;
57-
void *virt;
55+
void *virt = NULL;
5856
int i;
5957

6058
ibft_phys_addr = 0;
@@ -70,23 +68,33 @@ void __init reserve_ibft_region(void)
7068
* so skip that area */
7169
if (pos == VGA_MEM)
7270
pos += VGA_SIZE;
73-
virt = isa_bus_to_virt(pos);
71+
72+
/* Map page by page */
73+
if (offset_in_page(pos) == 0) {
74+
if (virt)
75+
early_memunmap(virt, PAGE_SIZE);
76+
virt = early_memremap_ro(pos, PAGE_SIZE);
77+
virt_pos = pos;
78+
}
7479

7580
for (i = 0; i < ARRAY_SIZE(ibft_signs); i++) {
76-
if (memcmp(virt, ibft_signs[i].sign, IBFT_SIGN_LEN) ==
77-
0) {
81+
if (memcmp(virt + (pos - virt_pos), ibft_signs[i].sign,
82+
IBFT_SIGN_LEN) == 0) {
7883
unsigned long *addr =
79-
(unsigned long *)isa_bus_to_virt(pos + 4);
84+
(unsigned long *)(virt + pos - virt_pos + 4);
8085
len = *addr;
8186
/* if the length of the table extends past 1M,
8287
* the table cannot be valid. */
8388
if (pos + len <= (IBFT_END-1)) {
8489
ibft_phys_addr = pos;
8590
memblock_reserve(ibft_phys_addr, PAGE_ALIGN(len));
8691
pr_info("iBFT found at %pa.\n", &ibft_phys_addr);
87-
return;
92+
goto out;
8893
}
8994
}
9095
}
9196
}
97+
98+
out:
99+
early_memunmap(virt, PAGE_SIZE);
92100
}

include/linux/iscsi_ibft.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,20 @@
2121
*/
2222
extern phys_addr_t ibft_phys_addr;
2323

24+
#ifdef CONFIG_ISCSI_IBFT_FIND
25+
2426
/*
2527
* Routine used to find and reserve the iSCSI Boot Format Table. The
2628
* physical address is set in the ibft_phys_addr variable.
2729
*/
28-
#ifdef CONFIG_ISCSI_IBFT_FIND
2930
void reserve_ibft_region(void);
31+
32+
/*
33+
* Physical bounds to search for the iSCSI Boot Format Table.
34+
*/
35+
#define IBFT_START 0x80000 /* 512kB */
36+
#define IBFT_END 0x100000 /* 1MB */
37+
3038
#else
3139
static inline void reserve_ibft_region(void) {}
3240
#endif

0 commit comments

Comments
 (0)