diff --git a/meta/recipes-kernel/linux/linux-yocto/0001-Fix-qemux86-pat-issue.patch b/meta/recipes-kernel/linux/linux-yocto/0001-Fix-qemux86-pat-issue.patch new file mode 100644 index 0000000000..367d9b4ace --- /dev/null +++ b/meta/recipes-kernel/linux/linux-yocto/0001-Fix-qemux86-pat-issue.patch @@ -0,0 +1,100 @@ +From 9bfb2c711f66fc8eb6482f5ca6ea33c2ec1d792f Mon Sep 17 00:00:00 2001 +From: Richard Purdie +Date: Sat, 13 Feb 2016 17:36:23 +0000 +Subject: [PATCH] Fix qemux86 pat issue + +on qemux86, X doesn't start and there is +a backtrace in the logs: + +x86/PAT: Xorg:705 map pfn expected mapping type uncached-minus for [mem 0xfd000000-0xfdffffff], got write-combining +------------[ cut here ]------------ +WARNING: CPU: 0 PID: 705 at /media/build1/poky/build/tmp/work-shared/qemux86/kernel-source/arch/x86/mm/pat.c:985 untrack_pfn+0xaf/0xc0() +Modules linked in: uvesafb +CPU: 0 PID: 705 Comm: Xorg Not tainted 4.4.1-yocto-standard #1 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014 + 00000000 00000000 cf14dd78 c1397ab2 00000000 cf14dda8 c1051477 c1aa4f6c + 00000000 000002c1 c1a9fa4c 000003d9 c104b98f c104b98f cf244000 b6355000 + 00000000 cf14ddb8 c1051552 00000009 00000000 cf14dde0 c104b98f cf14ddd0 +Call Trace: + [] dump_stack+0x4b/0x79 + [] warn_slowpath_common+0x87/0xc0 + [] ? untrack_pfn+0xaf/0xc0 + [] ? untrack_pfn+0xaf/0xc0 + [] warn_slowpath_null+0x22/0x30 + [] untrack_pfn+0xaf/0xc0 + [] ? kmap_atomic_prot+0x3c/0xf0 + [] unmap_single_vma+0x4ef/0x500 + [] unmap_vmas+0x37/0x50 + [] exit_mmap+0x5f/0xf0 + [] mmput+0x2d/0xb0 + [] copy_process+0xd2c/0x13c0 + [] _do_fork+0x82/0x340 + [] ? SyS_rt_sigaction+0x51/0xa0 + [] SyS_clone+0x2c/0x30 + [] do_syscall_32_irqs_on+0x53/0xb0 + [] entry_INT80_32+0x2a/0x2a +---[ end trace be3e0a61097feddc ]--- +x86/PAT: Xorg:705 map pfn expected mapping type uncached-minus for [mem 0xfd000000-0xfdffffff], got write-combining + +The entry in question is setup by uvesafb which in its +uvesafb_ioremap() function calls ioremap_wc(). + +It appears that Xorg mmaps this from userspace, then later does a +fork() to execute a utility. At this point, when creating the vmas for +the new process, the pat code says "eeek!" as the protection mode for +the new vmas don't match the old one, returns -EINVAL, the process dies +and X goes with it. + +There are a few hammers we can hit this with, we can boot with "nopat" +option which makes the problem go away, or turn off CONFIG_X86_PAT. No +surprises there. Changing uvesafb to use mtrr=0 doesn't help since the +ioremap_wc call still happens. + +The real issue is the "expected mapping type uncached-minus for got +write-combining" message, it all goes wrong from there. + +Upon looking at the code and scratching my head for a long while, I +notice that there are two ways of representing the protection mode +data, "enum page_cache_mode" and "pgprot_t & _PAGE_CACHE_MASK". + +The exact meaning of pgprot_t depends on which CPU you're running, +older CPUs have errata meaning only a small number of bits can be used. +The exact mapping table is determined by __cachemode2pte_tbl and is +updated at boot by calls from update_cache_mode_entry(). + +The result of this if you map enum -> pgprot_t, then try to do pgprot_t +-> enum, you can get different values since its not a 1:1 mapping. + +This means the comparison in reserve_pfn_range() where it does "pcm != +want_pcm" isn't correct and can trigger even in cases where there isn't +a problem. + +This can be "fixed" by doing cachemode2protval(pcm) != +cachemode2protval(want_pcm) and checking whether the protection bits +match, rather than the enum values, since in reality this is what we +really care about. With that change, X boots up just fine. + +We don't see this on qemux86-64 since that has more PAT bits working +and hence the values map correctly. + +Signed-off-by: Richard Purdie +--- + arch/x86/mm/pat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c +index 031782e..11064fb 100644 +--- a/arch/x86/mm/pat.c ++++ b/arch/x86/mm/pat.c +@@ -833,7 +833,7 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot, + if (ret) + return ret; + +- if (pcm != want_pcm) { ++ if (cachemode2protval(pcm) != cachemode2protval(want_pcm)) { + if (strict_prot || + !is_new_memtype_allowed(paddr, size, want_pcm, pcm)) { + free_memtype(paddr, paddr + size); +-- +2.5.0 + diff --git a/meta/recipes-kernel/linux/linux-yocto_4.4.bb b/meta/recipes-kernel/linux/linux-yocto_4.4.bb index 1beeea6698..c0edcf13c3 100644 --- a/meta/recipes-kernel/linux/linux-yocto_4.4.bb +++ b/meta/recipes-kernel/linux/linux-yocto_4.4.bb @@ -40,3 +40,5 @@ KERNEL_FEATURES_append_qemuall=" cfg/virtio.scc" KERNEL_FEATURES_append_qemux86=" cfg/sound.scc cfg/paravirt_kvm.scc" KERNEL_FEATURES_append_qemux86-64=" cfg/sound.scc cfg/paravirt_kvm.scc" KERNEL_FEATURES_append = " ${@bb.utils.contains("TUNE_FEATURES", "mx32", " cfg/x32.scc", "" ,d)}" + +SRC_URI_append = " file://0001-Fix-qemux86-pat-issue.patch" diff --git a/scripts/runqemu-internal b/scripts/runqemu-internal index ad854d108d..ebed2bdd01 100755 --- a/scripts/runqemu-internal +++ b/scripts/runqemu-internal @@ -434,7 +434,7 @@ if [ "$MACHINE" = "qemux86" ]; then fi # Currently oprofile's event based interrupt mode doesn't work(Bug #828) in # qemux86 and qemux86-64. We can use timer interrupt mode for now. - KERNCMDLINE="$KERNCMDLINE oprofile.timer=1 nopat" + KERNCMDLINE="$KERNCMDLINE oprofile.timer=1" fi if [ "$MACHINE" = "qemux86-64" ]; then