* [PATCH RESEND v2 0/2] Fix loading of platform ROM from 32-bit EFI
@ 2020-03-13 22:22 Mikel Rychliski
2020-03-13 22:22 ` [PATCH RESEND v2 1/2] drm/radeon: Stop directly referencing iomem Mikel Rychliski
2020-03-13 22:22 ` [PATCH RESEND v2 2/2] PCI: Use ioremap(), not phys_to_virt() for platform ROM Mikel Rychliski
0 siblings, 2 replies; 6+ messages in thread
From: Mikel Rychliski @ 2020-03-13 22:22 UTC (permalink / raw)
To: amd-gfx, linux-pci, nouveau
Cc: Alex Deucher, Christian König, David (ChunMing) Zhou,
Bjorn Helgaas, Matthew Garrett, Ben Skeggs, Mikel Rychliski
This patch series fixes an oops when loading the radeon driver on old Macs
with a 32-bit EFI implementation.
Tested on a MacPro 1,1 with a Radeon X1900 XT card and 32-bit kernel.
Changes in v2:
- Add iounmap() call in nouveau
- Update function comment for pci_platform_rom()
- Minor changes to commit messages
Mikel Rychliski (2):
drm/radeon: Stop directly referencing iomem
PCI: Use ioremap(), not phys_to_virt() for platform ROM
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 1 +
drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c | 11 ++++++++++-
drivers/gpu/drm/radeon/radeon_bios.c | 12 ++++++++----
drivers/pci/rom.c | 9 ++++++---
4 files changed, 25 insertions(+), 8 deletions(-)
--
2.13.7
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH RESEND v2 1/2] drm/radeon: Stop directly referencing iomem
2020-03-13 22:22 [PATCH RESEND v2 0/2] Fix loading of platform ROM from 32-bit EFI Mikel Rychliski
@ 2020-03-13 22:22 ` Mikel Rychliski
2020-03-13 22:22 ` [PATCH RESEND v2 2/2] PCI: Use ioremap(), not phys_to_virt() for platform ROM Mikel Rychliski
1 sibling, 0 replies; 6+ messages in thread
From: Mikel Rychliski @ 2020-03-13 22:22 UTC (permalink / raw)
To: amd-gfx, linux-pci, nouveau
Cc: Alex Deucher, Christian König, David (ChunMing) Zhou,
Bjorn Helgaas, Matthew Garrett, Ben Skeggs, Mikel Rychliski
pci_platform_rom() returns an __iomem pointer which should not be
accessed directly. Change radeon_read_platform_bios() to use
memcpy_fromio() instead of calling kmemdup() on the __iomem pointer.
Signed-off-by: Mikel Rychliski <mikel@mikelr.com>
---
drivers/gpu/drm/radeon/radeon_bios.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index c42f73fad3e3..c3ae4c92a115 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -118,11 +118,14 @@ static bool radeon_read_platform_bios(struct radeon_device *rdev)
return false;
}
- if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ rdev->bios = kzalloc(size, GFP_KERNEL);
+ if (!rdev->bios)
return false;
- }
- rdev->bios = kmemdup(bios, size, GFP_KERNEL);
- if (rdev->bios == NULL) {
+
+ memcpy_fromio(rdev->bios, bios, size);
+
+ if (size == 0 || rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
+ kfree(rdev->bios);
return false;
}
--
2.13.7
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH RESEND v2 2/2] PCI: Use ioremap(), not phys_to_virt() for platform ROM
2020-03-13 22:22 [PATCH RESEND v2 0/2] Fix loading of platform ROM from 32-bit EFI Mikel Rychliski
2020-03-13 22:22 ` [PATCH RESEND v2 1/2] drm/radeon: Stop directly referencing iomem Mikel Rychliski
@ 2020-03-13 22:22 ` Mikel Rychliski
2020-03-17 14:47 ` Christoph Hellwig
1 sibling, 1 reply; 6+ messages in thread
From: Mikel Rychliski @ 2020-03-13 22:22 UTC (permalink / raw)
To: amd-gfx, linux-pci, nouveau
Cc: Alex Deucher, Christian König, David (ChunMing) Zhou,
Bjorn Helgaas, Matthew Garrett, Ben Skeggs, Mikel Rychliski
On some EFI systems, the video BIOS is provided by the EFI firmware. The
boot stub code stores the physical address of the ROM image in pdev->rom.
Currently we attempt to access this pointer using phys_to_virt(), which
doesn't work with CONFIG_HIGHMEM.
On these systems, attempting to load the radeon module on a x86_32 kernel
can result in the following:
BUG: unable to handle page fault for address: 3e8ed03c
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
*pde = 00000000
Oops: 0000 [#1] PREEMPT SMP
CPU: 0 PID: 317 Comm: systemd-udevd Not tainted 5.6.0-rc3-next-20200228 #2
Hardware name: Apple Computer, Inc. MacPro1,1/Mac-F4208DC8, BIOS MP11.88Z.005C.B08.0707021221 07/02/07
EIP: radeon_get_bios+0x5ed/0xe50 [radeon]
Code: 00 00 84 c0 0f 85 12 fd ff ff c7 87 64 01 00 00 00 00 00 00 8b 47 08 8b 55 b0 e8 1e 83 e1 d6 85 c0 74 1a 8b 55 c0 85 d2 74 13 <80> 38 55 75 0e 80 78 01 aa 0f 84 a4 03 00 00 8d 74 26 00 68 dc 06
EAX: 3e8ed03c EBX: 00000000 ECX: 3e8ed03c EDX: 00010000
ESI: 00040000 EDI: eec04000 EBP: eef3fc60 ESP: eef3fbe0
DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 EFLAGS: 00010206
CR0: 80050033 CR2: 3e8ed03c CR3: 2ec77000 CR4: 000006d0
Call Trace:
? register_client+0x34/0xe0
? register_client+0xab/0xe0
r520_init+0x26/0x240 [radeon]
radeon_device_init+0x533/0xa50 [radeon]
radeon_driver_load_kms+0x80/0x220 [radeon]
drm_dev_register+0xa7/0x180 [drm]
radeon_pci_probe+0x10f/0x1a0 [radeon]
pci_device_probe+0xd4/0x140
really_probe+0x13d/0x3b0
driver_probe_device+0x56/0xd0
device_driver_attach+0x49/0x50
__driver_attach+0x79/0x130
? device_driver_attach+0x50/0x50
bus_for_each_dev+0x5b/0xa0
driver_attach+0x19/0x20
? device_driver_attach+0x50/0x50
bus_add_driver+0x117/0x1d0
? pci_bus_num_vf+0x20/0x20
driver_register+0x66/0xb0
? 0xf80f4000
__pci_register_driver+0x3d/0x40
radeon_init+0x82/0x1000 [radeon]
do_one_initcall+0x42/0x200
? kvfree+0x25/0x30
? __vunmap+0x206/0x230
? kmem_cache_alloc_trace+0x16f/0x220
? do_init_module+0x21/0x220
do_init_module+0x50/0x220
load_module+0x1f26/0x2200
sys_init_module+0x12d/0x160
do_fast_syscall_32+0x82/0x250
entry_SYSENTER_32+0xa5/0xf8
Fix the issue by using ioremap() instead of phys_to_virt() in
pci_platform_rom().
Now that pci_platform_rom() creates a new mapping to access the ROM
image, update all callers to remove this mapping after extracting the
BIOS.
Signed-off-by: Mikel Rychliski <mikel@mikelr.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 1 +
drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c | 11 ++++++++++-
drivers/gpu/drm/radeon/radeon_bios.c | 1 +
drivers/pci/rom.c | 9 ++++++---
4 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index 50dff69a0f6e..ea6a1fa98ad9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -207,6 +207,7 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
return false;
memcpy_fromio(adev->bios, bios, size);
+ iounmap(bios);
if (!check_atom_bios(adev->bios, size)) {
kfree(adev->bios);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c
index 9b91da09dc5f..8a60a0db7b14 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c
@@ -111,11 +111,20 @@ platform_init(struct nvkm_bios *bios, const char *name)
return ERR_PTR(ret);
}
+static void
+platform_fini(void *data)
+{
+ struct priv *priv = data;
+
+ iounmap(priv->rom);
+ kfree(priv);
+}
+
const struct nvbios_source
nvbios_platform = {
.name = "PLATFORM",
.init = platform_init,
- .fini = (void(*)(void *))kfree,
+ .fini = platform_fini,
.read = pcirom_read,
.rw = true,
};
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index c3ae4c92a115..712b88d88957 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -123,6 +123,7 @@ static bool radeon_read_platform_bios(struct radeon_device *rdev)
return false;
memcpy_fromio(rdev->bios, bios, size);
+ iounmap(bios);
if (size == 0 || rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
kfree(rdev->bios);
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 137bf0cee897..b38257d23e6e 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -197,16 +197,19 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
EXPORT_SYMBOL(pci_unmap_rom);
/**
- * pci_platform_rom - provides a pointer to any ROM image provided by the
- * platform
+ * pci_platform_rom - ioremap() the ROM image provided by the platform
* @pdev: pointer to pci device struct
* @size: pointer to receive size of pci window over ROM
+ *
+ * Return: kernel virtual pointer to image of ROM
+ *
+ * The caller is responsible for removing the mapping with iounmap()
*/
void __iomem *pci_platform_rom(struct pci_dev *pdev, size_t *size)
{
if (pdev->rom && pdev->romlen) {
*size = pdev->romlen;
- return phys_to_virt((phys_addr_t)pdev->rom);
+ return ioremap(pdev->rom, pdev->romlen);
}
return NULL;
--
2.13.7
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH RESEND v2 2/2] PCI: Use ioremap(), not phys_to_virt() for platform ROM
2020-03-13 22:22 ` [PATCH RESEND v2 2/2] PCI: Use ioremap(), not phys_to_virt() for platform ROM Mikel Rychliski
@ 2020-03-17 14:47 ` Christoph Hellwig
2020-03-18 1:34 ` Mikel Rychliski
0 siblings, 1 reply; 6+ messages in thread
From: Christoph Hellwig @ 2020-03-17 14:47 UTC (permalink / raw)
To: Mikel Rychliski
Cc: amd-gfx, linux-pci, nouveau, Alex Deucher, Christian König,
David (ChunMing) Zhou, Bjorn Helgaas, Matthew Garrett,
Ben Skeggs
On Fri, Mar 13, 2020 at 06:22:58PM -0400, Mikel Rychliski wrote:
> /**
> + * pci_platform_rom - ioremap() the ROM image provided by the platform
> * @pdev: pointer to pci device struct
> * @size: pointer to receive size of pci window over ROM
> + *
> + * Return: kernel virtual pointer to image of ROM
> + *
> + * The caller is responsible for removing the mapping with iounmap()
> */
> void __iomem *pci_platform_rom(struct pci_dev *pdev, size_t *size)
> {
> if (pdev->rom && pdev->romlen) {
> *size = pdev->romlen;
> - return phys_to_virt((phys_addr_t)pdev->rom);
> + return ioremap(pdev->rom, pdev->romlen);
> }
What is the value of this helper over just open coding an ioremap
of pdev->rom in the callers?
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH RESEND v2 2/2] PCI: Use ioremap(), not phys_to_virt() for platform ROM
2020-03-17 14:47 ` Christoph Hellwig
@ 2020-03-18 1:34 ` Mikel Rychliski
2020-03-18 6:51 ` Christoph Hellwig
0 siblings, 1 reply; 6+ messages in thread
From: Mikel Rychliski @ 2020-03-18 1:34 UTC (permalink / raw)
To: Christoph Hellwig
Cc: amd-gfx, linux-pci, nouveau, Alex Deucher, Christian König,
David (ChunMing) Zhou, Bjorn Helgaas, Matthew Garrett,
Ben Skeggs
Hi Christoph,
Thanks for your comments. I'm also replying here to your comments on the
previous series.
On Tuesday, March 17, 2020 10:28:35 AM EDT Christoph Hellwig wrote:
> Any reason drivers can't just use pci_map_rom insteadἅ which already
> does the right thing?
Some machines don't expose the video BIOS in the PCI BAR and instead only make
it available via EFI boot services calls. So drivers need to be able to use
the ROM provided by EFI calls, but only if they can't find a valid one anywhere
else.
At one point, the EFI provided ROM in pdev->rom *was* exposed via
pci_map_rom(). However it had to be split out into a separate function so that
drivers could have more control over which sources were preferred.
On Tuesday, March 17, 2020 10:29:13 AM EDT Christoph Hellwig wrote:
> This and the next patch really need to be folded into the previous
> one to avoid regressions (assuming my other suggestion doesn't work
> for some reason).
Addressed in v2
On Tuesday, March 17, 2020 10:47:31 AM EDT Christoph Hellwig wrote:
> What is the value of this helper over just open coding an ioremap
> of pdev->rom in the callers?
I think the direct access to pdev->rom you suggest makes sense, especially
because users of the pci_platform_rom() are exposed to the fact that it just
calls ioremap().
I decided against wrapping the iounmap() with a pci_unmap_platform_rom(), but
I didn't apply the same consideration to the existing function.
How about something like this (with pci_platform_rom() removed)?
static bool radeon_read_platform_bios(struct radeon_device *rdev)
{
phys_addr_t rom = rdev->pdev->rom;
size_t romlen = rdev->pdev->romlen;
void __iomem *bios;
rdev->bios = NULL;
if (!rom || romlen == 0)
return false;
rdev->bios = kzalloc(romlen, GFP_KERNEL);
if (!rdev->bios)
return false;
bios = ioremap(rom, romlen);
if (!bios)
goto free_bios;
memcpy_fromio(rdev->bios, bios, romlen);
iounmap(bios);
if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa)
goto free_bios;
return true;
free_bios:
kfree(rdev->bios);
return false;
}
If this is preferred, I'll send an updated series. I'm assuming that the
removal of pci_platform_rom() and updating of all the callers should be
combined into this patch.
Thanks,
Mikel
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH RESEND v2 2/2] PCI: Use ioremap(), not phys_to_virt() for platform ROM
2020-03-18 1:34 ` Mikel Rychliski
@ 2020-03-18 6:51 ` Christoph Hellwig
0 siblings, 0 replies; 6+ messages in thread
From: Christoph Hellwig @ 2020-03-18 6:51 UTC (permalink / raw)
To: Mikel Rychliski
Cc: Christoph Hellwig, amd-gfx, linux-pci, nouveau, Alex Deucher,
Christian König, David (ChunMing) Zhou, Bjorn Helgaas,
Matthew Garrett, Ben Skeggs
On Tue, Mar 17, 2020 at 09:34:33PM -0400, Mikel Rychliski wrote:
> I think the direct access to pdev->rom you suggest makes sense, especially
> because users of the pci_platform_rom() are exposed to the fact that it just
> calls ioremap().
>
> I decided against wrapping the iounmap() with a pci_unmap_platform_rom(), but
> I didn't apply the same consideration to the existing function.
>
> How about something like this (with pci_platform_rom() removed)?
That looks sensible to me.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2020-03-18 6:51 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-13 22:22 [PATCH RESEND v2 0/2] Fix loading of platform ROM from 32-bit EFI Mikel Rychliski
2020-03-13 22:22 ` [PATCH RESEND v2 1/2] drm/radeon: Stop directly referencing iomem Mikel Rychliski
2020-03-13 22:22 ` [PATCH RESEND v2 2/2] PCI: Use ioremap(), not phys_to_virt() for platform ROM Mikel Rychliski
2020-03-17 14:47 ` Christoph Hellwig
2020-03-18 1:34 ` Mikel Rychliski
2020-03-18 6:51 ` Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).