IP32 prom crashes due to __pa() funkiness
Initially, booting a straight git checkout on an IP32 will cause it to prom crash, usually somewhere in between init_bootmem() and init_bootmem_core(). I bisected git to trace this back to one of the inital __pa() introduction patches from commit d4df6d4 (get ride of CPHYSADDR()). It actually appears that the actual commit that broke things was 620a480 (Make __pa() aware of XKPHYS/CKSEG0 address mix for 64 bit kernels).
The [short-term] fix highlighted by Ilya is to make __pa() unconditionally be defined to "((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)"; Discovered by building IP32 with CONFIG_BUILD_ELF64=n.
Normally, this shouldn't be possible, as CONFIG_BUILD_ELF64=n was originally only allowed by using the old o64 hack, which has subsequently died and been replaced with the newer -msym32 form. As far as I know, CONFIG_BUILD_ELF64 is apparently supposed to be removed at some point in the future, since I believe it existed only for quirky 64bit-in-32bit kernels for IP22 and more commonly, IP32. From 2.6.17 onwards, I've been building IP32 kernels with CONFIG_BUILD_ELF64=y and using gcc-4, and haven't had problems up until now.
Anyways, I'm not sure if this is an IP32-specific oddity or not (probably is), but it needs the define highlighted above to work properly. Plain PAGE_OFFSET won't work for these machines. Given the same trick os -msym32 is used for the rare IP22 64bit kernel, I would not be surprised if the same problem and fix both occur and work for those machines as well. Something to maybe test later, I suppose.
But for now, anyone got thoughts as to a sane workaround for this? Perhaps some conditional tweaks in mach-ip32/*.h files somewheres, would it be simpler to just switch to:
#if defined(CONFIG_64BIT) && (!defined(CONFIG_BUILD_ELF64) || defined(CONFIG_SGI_IP32))
(assuming that IP22 doesn't need it; I'll find out later)
--Kumba
Signature · 3 lines
Gentoo/MIPS Team Lead "Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
Quoted 7 lines · Kumba
Initially, booting a straight git checkout on an IP32 will cause it to prom crash, usually somewhere in between
init_bootmem()andinit_bootmem_core(). I bisected git to trace this back to one of the inital__pa()introduction patches from commit d4df6d4 (get ride ofCPHYSADDR()). It actually appears that the actual commit that broke things was 620a480 (Make__pa()aware of XKPHYS/CKSEG0 address mix for 64 bit kernels).The [short-term] fix highlighted by Ilya is to make
__pa()unconditionally be defined to "((unsigned long)(x) < CKSEG0 ?PAGE_OFFSET: CKSEG0)"; Discovered by building IP32 withCONFIG_BUILD_ELF64=n.Normally, this shouldn't be possible, as
CONFIG_BUILD_ELF64=nwas originally only allowed by using the old o64 hack, which has subsequently died and been replaced with the newer -msym32 form. As far as I know,CONFIG_BUILD_ELF64is apparently supposed to be removed at some point in the future, since I believe it existed only for quirky 64bit-in-32bit kernels for IP22 and more commonly, IP32. From 2.6.17 onwards, I've been building IP32 kernels withCONFIG_BUILD_ELF64=yand using gcc-4, and haven't had problems up until now.
Quoted 7 lines
Anyways, I'm not sure if this is an IP32-specific oddity or not (probably is), but it needs the define highlighted above to work properly. Plain
PAGE_OFFSETwon't work for these machines. Given the same trick os -msym32 is used for the rare IP22 64bit kernel, I would not be surprised if the same problem and fix both occur and work for those machines as well. Something to maybe test later, I suppose.But for now, anyone got thoughts as to a sane workaround for this? Perhaps some conditional tweaks in mach-ip32/*.h files somewheres, would it be simpler to just switch to:
#if
defined(CONFIG_64BIT)&& (!defined(CONFIG_BUILD_ELF64) ||defined(CONFIG_SGI_IP32))(assuming that IP22 doesn't need it; I'll find out later)
"Re-verify range to target, One ping only."
So, anyone got thoughts on this?
I've actually built and booted an SGI IP32 kernel using this logic in include/asm-mips/page.h, Line 135:
#if defined(CONFIG_64BIT) && (!defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_SGI_IP32) || defined(CONFIG_SGI_IP22)))
--Kumba
Signature · 3 lines
Gentoo/MIPS Team Lead "Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
Hi,
Quoted 9 lines · Kumba
Initially, booting a straight git checkout on an IP32 will cause it to prom crash, usually somewhere in between
init_bootmem()andinit_bootmem_core(). I bisected git to trace this back to one of the inital__pa()introduction patches from commit d4df6d4 (get ride ofCPHYSADDR()). It actually appears that the actual commit that broke things was 620a480 (Make__pa()aware of XKPHYS/CKSEG0 address mix for 64 bit kernels).
Quoted 5 lines
The [short-term] fix highlighted by Ilya is to make
__pa()unconditionally be defined to "((unsigned long)(x) < CKSEG0 ?PAGE_OFFSET: CKSEG0)"; Discovered by building IP32 withCONFIG_BUILD_ELF64=n.
Well, it means that you previously used CONFIG_BUILD_ELF64=y (this implied that PAGE_OFFSET is in XKPHYS) whereas your kernel has CKSEG load address (symbols need PAGE_OFFSET in CKSEG for address translation).
So the question is why can't you use CONFIG_BUILD_ELF64=n (and reagarding the current definition of CONFIG_BUILD_ELF64).
Quoted 5 lines
Normally, this shouldn't be possible, as
CONFIG_BUILD_ELF64=nwas originally only allowed by using the old o64 hack, which has subsequently died and been replaced with the newer -msym32 form. As far as I know,CONFIG_BUILD_ELF64is apparently supposed to be removed at some point in the future, since I believe it existed only for quirky
It makes me think that I posted a patch for that a couple of weeks ago:
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480225936&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480126802&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154587014827&w=2
Basically this patch removes CONFIG_BUILD_ELF64 and makes Kbuild to use '-msym32' switch if you really need it. Kbuild makes its choice according the load address of your kernel image.
Could you give it a try ? This patch was based on 2.6.20 but it should apply fine on a 2.6.21-rc[12].
Signature · 1 line
Franck
PATCH 1/1 , Re: IP32 prom crashes due to __pa() funkiness
Hi !
Watching the discussion about __pa(), CPHYSADDR and related stuff, with about a hundred e-mails last October, and rising again several times recently (see below), i wonder why we must cling so firmly to the "x - page_offset" algorithm, the least capable one. AFAIK this method is taken over unaltered from the i386 arch (yes, i know, the majority of archs did this), where we have a situation quite different from MIPS:
A (preferably simple) mapping must be invented for kernel-memory with some, more or less deliberately chosen, "page-offset". There exist no addresses beside this mapping, no hardware "kernel-mappings" with (un)cached regions, cached-attributes, unmapped spaces, etc. and "x - page_offset" is necessary and sufficient to handle all addresses.
On the MIPS-side there isn't really something like "the" page-offset, and the processor architecture already defines kernel spaces with respective address-syntax. In other words, the definitions in asm-mips/addrspace.h properly describe the virtual/physical conversions and masking, not some subtracting, is the natural way to go.
Since __pa() and virt_to_phys() are currently "under construction" anyway, i think it's time to submit robust versions (with kernel_physaddr() stolen from the IP30 patch) for both, that handle any pitfall in one place and may be used without pain throughout the kernel. I don't know, which one to prefer, 29 drivers are using __pa(), 60 are using virt_to_phys(), the uses in arch/mips files are about equal.
Having a robust __pa()/virt_to_phys() avoids the need for local fixes, like in sgiwd93.c and sgiseeq.c, which have to cope with at least one uncached (usu. 0x9000...) address-type and at least one cached type (usu. 0xa800...) in xkphys, and where virt_to_phys() blew up nicely. In some situation there may be need to handle a ckseg0/1 address additionaly.
Quoted 24 lines · Franck Bui-Huu
Date: Thu, 1 Mar 2007 10:39:08 +0100
From: Franck Bui-Huu <[email protected]>
To: Kumba <[email protected]>
Cc: Linux MIPS List <[email protected]>
Subject: Re: IP32 prom crashes due to__pa()funkinessHi,
Quoted 9 lines · Kumba
Initially, booting a straight git checkout on an IP32 will cause it to prom crash, usually somewhere in between
init_bootmem()andinit_bootmem_core(). I bisected git to trace this back to one of the inital__pa()introduction patches from commit d4df6d4 (get ride ofCPHYSADDR()). It actually appears that the actual commit that broke things was 620a480 (Make__pa()aware of XKPHYS/CKSEG0 address mix for 64 bit kernels).Quoted 5 lines
The [short-term] fix highlighted by Ilya is to make
__pa()unconditionally be defined to "((unsigned long)(x) < CKSEG0 ?PAGE_OFFSET: CKSEG0)"; Discovered by building IP32 withCONFIG_BUILD_ELF64=n.
Quoted 6 lines
Well, it means that you previously used
CONFIG_BUILD_ELF64=y(this implied thatPAGE_OFFSETis in XKPHYS) whereas your kernel has CKSEG load address (symbols needPAGE_OFFSETin CKSEG for address translation)....
========================================================================
include/asm-mips/addrspace.h +11 -0
@@ -54,6 +54,17 @@#define XPHYSADDR (a) ((_ACAST64_(a)) & \ _CONST64_(0x000000ffffffffff)) +static inline unsigned long kernel_physaddr (unsigned long kva) +{ +#ifdef CONFIG_64BIT +if ((kva &0xffffffff80000000UL ) ==0xffffffff80000000UL ) +return CPHYSADDR (kva); +return XPHYSADDR (kva); +#else +return CPHYSADDR (kva); +#endif +} +#ifdef CONFIG_64BIT /*
include/asm-mips/io.h +1 -1
@@ -116,7 +116,7 @@ static inline void set_io_port_base(unsi*/ static inline unsigned long virt_to_phys (volatile const void *address) { -return (unsigned long )address -PAGE_OFFSET +PHYS_OFFSET ; +return kernel_physaddr ((unsigned long )address); }/*
include/asm-mips/page.h +1 -1
@@ -154,7 +154,7 @@ typedef struct { unsigned long pgprot; }#else #define __pa_page_offset (x) PAGE_OFFSET#endif -#define __pa (x) ((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET) +#define __pa (x) kernel_physaddr((unsigned long)(x))#define __va (x) ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))#define __pa_symbol (x) __pa(RELOC_HIDE((unsigned long)(x),0))
========================================================================
(whoops, reply didn't send to the ML, sorry Frank!)
Quoted 2 lines · Franck Bui-Huu
Hi,
[snip]
Quoted 9 lines
Well, it means that you previously used
CONFIG_BUILD_ELF64=y(this implied thatPAGE_OFFSETis in XKPHYS) whereas your kernel has CKSEG load address (symbols needPAGE_OFFSETin CKSEG for address translation).So the question is why can't you use
CONFIG_BUILD_ELF64=n(and reagarding the current definition ofCONFIG_BUILD_ELF64).
[snip]
Quoted 7 lines
It makes me think that I posted a patch for that a couple of weeks ago:
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480225936&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480126802&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154587014827&w=2
Quoted 6 lines
Basically this patch removes
CONFIG_BUILD_ELF64and makesKbuildto use '-msym32' switch if you really need it.Kbuildmakes its choice according the load address of your kernel image.Could you give it a try ? This patch was based on 2.6.20 but it should apply fine on a 2.6.21-rc[12].
Tested, and it still failed.
And I didn't always use CONFIG_BUILD_ELF64. In fact, for the longest time (up until 2.6.17) I built IP32 and 64bit IP22 kernels without CONFIG_BUILD_eLF64, passing -mabi=o64 (a.k.a., the binutils hack). This let me use the plain 'vmlinux' target w/o the need for an objcopy to boot these systems. After 2.6.17, the nature of o64 was mostly neutered, so I switched to using CONFIG_BUILD_ELF64 and the 'vmlinux.32' target, as this is apparently the way Debian builds their IP32 kernels (and was the way geoman/spbecker said I should've been using all along).
So with the changes brought in by __pa(), I suppose a new, RightWay(TM) to build IP32 (and conversely, 64bit IP22) kernels needs to be found. These two systems are particularly wacky, hence why they need a bit more special care than more traditional, proper, 64bit systems like Origin and Octane.
Also, Peter raises a good point in this case. It sounds like a re-thinking of how all this address stuff is handled will fix not only special cases like IP32/IP22, but the really weird systems, like IP28, as well. Which would be a big plus in my opinion.
--Kumba
Signature · 3 lines
Gentoo/MIPS Team Lead "Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
Quoted 3 lines · Kumba
So with the changes brought in by
__pa(), I suppose a new, RightWay(TM) to build IP32 (and conversely, 64bit IP22) kernels needs to be found.
I don't know if it is the RightWay(TM), but I am running here a fresh IP32 kernel (l.m.o git updated yesterday). It was compiled with CONFIG_BUILD_ELF64=n, and I am using vmlinux.
$ file /boot/vmlinux-2.6.21-rc3-g839fd555 /boot/vmlinux-2.6.21-rc3-g839fd555: ELF 64-bit MSB executable, MIPS, MIPS-IV version 1 (SYSV), statically linked, not stripped
If it makes a difference, I am using arcboot.
Arnaud
Quoted 8 lines · Arnaud Giersch
I don't know if it is the RightWay(TM), but I am running here a fresh IP32 kernel (l.m.o git updated yesterday). It was compiled with
CONFIG_BUILD_ELF64=n, and I am using vmlinux.$ file /boot/vmlinux-2.6.21-rc3-g839fd555 /boot/vmlinux-2.6.21-rc3-g839fd555: ELF 64-bit MSB executable, MIPS, MIPS-IV version 1 (SYSV), statically linked, not strippedIf it makes a difference, I am using arcboot.
I suppose then the question is, which is better for IP32? CONFIG_BUILD_ELF64=y or CONFIG_BUILD_ELF64=n. The reason the o64 hack used to exist, if my memory serves me correctly, was that someone once said that when built and run as a pure 64bit binary converted to 32bit via objcopy, 6 extra insns were run every cycle (I think), introducing unneeded slowdown. This changed to 2 insns by going the o64 route, which involved CONFIG_BUILD_ELF64=n. So 4 less insns technically resulted in a quicker kernel, though the layman might not notice such. I believe that all changed at some point, which is why CONFIG_BUILD_ELF64=y was an A-OK thing prior to the __pa() introduction.
Now I guess we're back to CONFIG_BUILD_ELF64=n? I guess the real question is, which way is the OneWay(TM), RightWay(TM) and OnlyWay(TM)?
Cheers,
--Kumba
Signature · 3 lines
Gentoo/MIPS Team Lead "Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
Quoted 6 lines · Kumba
Quoted 5 lines · Arnaud Giersch
I don't know if it is the RightWay(TM), but I am running here a fresh IP32 kernel (l.m.o git updated yesterday). It was compiled with
CONFIG_BUILD_ELF64=n, and I am using vmlinux.
Quoted 7 lines
Quoted 5 lines
$ file /boot/vmlinux-2.6.21-rc3-g839fd555 /boot/vmlinux-2.6.21-rc3-g839fd555: ELF 64-bit MSB executable, MIPS, MIPS-IV version 1 (SYSV), statically linked, not strippedIf it makes a difference, I am using arcboot.
I suppose then the question is, which is better for IP32?
That's the question I was wondering during my first reply to your initial post...
Quoted 5 lines
CONFIG_BUILD_ELF64=yorCONFIG_BUILD_ELF64=n. The reason the o64 hack used to exist, if my memory serves me correctly, was that someone once said that when built and run as a pure 64bit binary converted to 32bit via objcopy, 6 extra insns were run every cycle (I think), introducing unneeded slowdown. This changed to 2 insns by going the o64 route,
OK that's the reason why the last patch you applied has no effect. If you're using 'objcopy' your kernel can still be miss configured.
BTW, does your gcc support '-sym32' switch ?
Quoted 5 lines
which involved
CONFIG_BUILD_ELF64=n. So 4 less insns technically resulted in a quicker kernel, though the layman might not notice such. I believe that all changed at some point, which is whyCONFIG_BUILD_ELF64=ywas an A-OK thing prior to the__pa()introduction.
My current feeling is that __pa() introduction now breaks configs which were initialy _broken_, IMHO. CPHYSADDR() hide them because it can happily convert any virutal address form both CKSEG0 or XKPHYS.
It may be a good thing to crash at this point. CONFIG_BUILD_ELF64 is used in some others places, where it can introduce some others bugs harder to find (if miss configured of course). The sad thing is that the kernel does not report any useful messages. That's why I think adding some specific sanity checks for 64 bit kernels in boot mem init code may be usefull.
Quoted 3 lines
Now I guess we're back to
CONFIG_BUILD_ELF64=n? I guess the real question is, which way is the OneWay(TM), RightWay(TM) and OnlyWay(TM)?
Now it's clear that CONFIG_BUILD_ELF64 is really confusing. I would say that whatever the value of CONFIG_BUILD_ELF64, your kernel should run fine. BUT it really depends on your kernel load address:
if CONFIG_BUILD_ELF64=y then kernel load address must be in XKPHYS if CONFIG_BUILD_ELF64=n then kernel load address must be in CKSEG0
All others configs (I think) are buggy...
That's said, it seems that IPxx kernels are really special beasts. Take from MIPS makefile:
"""
Some machines like the Indy need 32-bit ELF binaries for booting purposes.
"""
So I dunno if this statement is still correct but it sounds that you have no other choice thatn CONFIG_BUILD_ELF64=n and load address in CKSEG0.
I'm sorry but my IPxx background is 0 ;)
Franck
Franck Bui-Huu wrote:
[snip]
Quoted 11 lines
Quoted 2 lines
Now I guess we're back to
CONFIG_BUILD_ELF64=n? I guess the real question is, which way is the OneWay(TM), RightWay(TM) and OnlyWay(TM)?Now it's clear that
CONFIG_BUILD_ELF64is really confusing. I would say that whatever the value ofCONFIG_BUILD_ELF64, your kernel should run fine. BUT it really depends on your kernel load address:if
CONFIG_BUILD_ELF64=ythen kernel load address must be in XKPHYS ifCONFIG_BUILD_ELF64=nthen kernel load address must be in CKSEG0All others configs (I think) are buggy...
Why? A ELF64 kernel for CKSEG0 should be fine, at least in principle, even if it doesn't work wih the current codebase.
Quoted 7 lines
That's said, it seems that IPxx kernels are really special beasts. Take from MIPS makefile:
"""
Some machines like the Indy need 32-bit ELF binaries for booting purposes.
"""
This is true for netbooting via firmware. For booting from disk the bootloaders support AFAIR ELF64-for-CKSEG0.
Thiemo
Quoted 4 lines · Thiemo Seufer
Why? A ELF64 kernel for CKSEG0 should be fine, at least in principle, even if it doesn't work wih the current codebase.
Yes you're right. I just replied to my self to say that.
Thanks
Signature · 1 line
Franck
Quoted 6 lines · Franck Bui-Huu
Now it's clear that
CONFIG_BUILD_ELF64is really confusing. I would say that whatever the value ofCONFIG_BUILD_ELF64, your kernel should run fine. BUT it really depends on your kernel load address:if
CONFIG_BUILD_ELF64=ythen kernel load address must be in XKPHYS ifCONFIG_BUILD_ELF64=nthen kernel load address must be in CKSEG0
to be more accurate, the following other config:
CONFIG_BUILD_ELF64=y and kernel load address in CKSEG0
should theoretically work but currently doesn't because of __pa() introduction.
This config should not be used because it's normally not interesting for normal user. It's only interesting for testing purpose if I recall correctly. And the patch that automatically set CONFIG_BUILD_ELF64 should fix this.
BTW, you should take a look at:
http://marc.info/?l=linux-mips&m=117019833420946&w=2
this thread clearly state that current config of IP32 kernel is broken. Sorry for remembering so lately...
Signature · 1 line
Franck
Quoted 4 lines · Franck Bui-Huu
OK that's the reason why the last patch you applied has no effect. If you're using 'objcopy' your kernel can still be miss configured.
BTW, does your gcc support '-sym32' switch ?
I'll have to re-try some runs w/ the straight 64bit vmlinux later on then, but AFAICT, __pa() braks IP32 because of the assumption I highlighted. This, cobalt, and IP22 are a bit "special" in their needs, I guess. Anyone got a short yellow bus?
Quoted 10 lines
My current feeling is that
__pa()introduction now breaks configs which were initialy _broken_, IMHO.CPHYSADDR()hide them because it can happily convert any virutal address form both CKSEG0 or XKPHYS.It may be a good thing to crash at this point.
CONFIG_BUILD_ELF64is used in some others places, where it can introduce some others bugs harder to find (if miss configured of course). The sad thing is that the kernel does not report any useful messages. That's why I think adding some specific sanity checks for 64 bit kernels in boot mem init code may be usefull.
A good idea to crash at this point? Not for users. Up until this point, I've never really seen any bugs produced by CONFIG_BUILD_ELF64, granted I avoided using it until ~2.6.17 (when o64 died). If there were bugs, they were subtle and didn't appear to affect the day-to-day running of the system. At minimum, __pa() should recreate this effect, and then we can trace down the bugs and hammer them to death later.
Quoted 12 lines
Now it's clear that
CONFIG_BUILD_ELF64is really confusing. I would say that whatever the value ofCONFIG_BUILD_ELF64, your kernel should run fine. BUT it really depends on your kernel load address:if
CONFIG_BUILD_ELF64=ythen kernel load address must be in XKPHYS ifCONFIG_BUILD_ELF64=nthen kernel load address must be in CKSEG0All others configs (I think) are buggy...
That's said, it seems that IPxx kernels are really special beasts. Take from MIPS makefile:
Quoted 8 lines
"""
Some machines like the Indy need 32-bit ELF binaries for booting purposes.
"""So I dunno if this statement is still correct but it sounds that you have no other choice thatn
CONFIG_BUILD_ELF64=nand load address in CKSEG0.
Most of this is because IP22 (Indy/Idigo2 R4xx) and IP32 (O2 R5xxx), while supporting 64bit kernels (same for cobalt, since it's a mips4-level CPU), we had to "trick" them into accepting 64bit code. IP32 at one point ran 32bit kernels only, but it was later converted to supporting only 64bit kernels, hence the hackery involved. We describe it as wrapping 64bit code into a 32bit object, because their proms will only recognize 32bit objects (specifically, IP22 will only boot 32bit objects; crash on 64bit; IP32 will take both, but likes 32bit better).
So really, CONFIG_BUILD_ELF64 was probably part of this "magic" to stuff 64bit code into a candy-coated 32bit wrapper for the Indy (And later the O2) to suck down w/o complaint. Hence, __pa() probably needs to replicate this support, or we all need to brainstorm a proper way to get these systems to boot.
Octane, Origin, IP28 (Indigo2 R10000). et al, don't complain, and don't need this hacker, because their proms boot proper 64bit binaries only (they reject all else).
So probably the following is true (someone correct me if not)
if (CONFIG_BUILD_ELF64=y and (!CONFIG_SGI_IP22 or !CONFIG_SGI_IP32 or !CONFIG_COBALT)) then kernel load address must be in XKPHYS else load address must be in CKSEG0
if CONFIG_BUILD_ELF64=n then kernel load address must be in CKSEG0
Quoted 1 line
I'm sorry but my IPxx background is 0 ;)
Time to buy an O2 :)
--Kumba
Signature · 3 lines
Gentoo/MIPS Team Lead "Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
Quoted 10 lines · Kumba
Most of this is because IP22 (Indy/Idigo2 R4xx) and IP32 (O2 R5xxx), while supporting 64bit kernels (same for cobalt, since it's a mips4-level CPU), we had to "trick" them into accepting 64bit code. IP32 at one point ran 32bit kernels only, but it was later converted to supporting only 64bit kernels, hence the hackery involved. We describe it as wrapping 64bit code into a 32bit object, because their proms will only recognize 32bit objects (specifically, IP22 will only boot 32bit objects; crash on 64bit; IP32 will take both, but likes 32bit better).
Quoted 5 lines
So really,
CONFIG_BUILD_ELF64was probably part of this "magic" to stuff 64bit code into a candy-coated 32bit wrapper for the Indy (And later the O2) to suck down w/o complaint. Hence,__pa()probably needs to replicate this support, or we all need to brainstorm a proper way to get these systems to boot.
The "magic" is CONFIG_BOOT_ELF32 and CONFIG_BOOT_ELF64, isn't it? CONFIG_BUILD_ELF64 is not irrelevant to ELF format.
I feel there are some confusions about this issue on this discussion...
---
Atsushi Nemoto
Kumba wrote:
[snip]
Quoted 9 lines
Most of this is because IP22 (Indy/Idigo2 R4xx) and IP32 (O2 R5xxx), while supporting 64bit kernels (same for cobalt, since it's a mips4-level CPU), we had to "trick" them into accepting 64bit code. IP32 at one point ran 32bit kernels only, but it was later converted to supporting only 64bit kernels, hence the hackery involved. We describe it as wrapping 64bit code into a 32bit object, because their proms will only recognize 32bit objects (specifically, IP22 will only boot 32bit objects; crash on 64bit; IP32 will take both, but likes 32bit better).
Quoted 5 lines
So really,
CONFIG_BUILD_ELF64was probably part of this "magic" to stuff 64bit code into a candy-coated 32bit wrapper for the Indy (And later the O2) to suck down w/o complaint. Hence,__pa()probably needs to replicate this support, or we all need to brainstorm a proper way to get these systems to boot.
BUILD_ELF64 + -sym32 + objcopy into a ELF32 file is supposed to be the full replacement for the old o64-in-o32 hack.
Quoted 10 lines
Octane, Origin, IP28 (Indigo2 R10000). et al, don't complain, and don't need this hacker, because their proms boot proper 64bit binaries only (they reject all else).
So probably the following is true (someone correct me if not)
if (
CONFIG_BUILD_ELF64=yand (!CONFIG_SGI_IP22 or !CONFIG_SGI_IP32 or !CONFIG_COBALT)) then kernel load address must be in XKPHYS else load address must be in CKSEG0
ifCONFIG_BUILD_ELF64=nthen kernel load address must be in CKSEG0
The 64/64 configs can do both:
| BUILD_ELF64 | BUILD_ELF32 --------------------------------------------------- 64bit firmware loader | CKSEG0/XKPHYS | CKSEG0 32bit firmware loader | CKSEG0 | CKSEG0
Thiemo
Quoted 10 lines · Kumba
Most of this is because IP22 (Indy/Idigo2 R4xx) and IP32 (O2 R5xxx), while supporting 64bit kernels (same for cobalt, since it's a mips4-level CPU), we had to "trick" them into accepting 64bit code. IP32 at one point ran 32bit kernels only, but it was later converted to supporting only 64bit kernels, hence the hackery involved. We describe it as wrapping 64bit code into a 32bit object, because their proms will only recognize 32bit objects (specifically, IP22 will only boot 32bit objects; crash on 64bit; IP32 will take both, but likes 32bit better).
Quoted 5 lines
So really,
CONFIG_BUILD_ELF64was probably part of this "magic" to stuff 64bit code into a candy-coated 32bit wrapper for the Indy (And later the O2) to suck down w/o complaint. Hence,__pa()probably needs to replicate this support, or we all need to brainstorm a proper way to get these systems to boot.
I'm really not confident with all your tricks you described. Maybe a config that I believed to be uninsteresting and useless should be supported still.
Can you try the attached patch with a plain linux-mips kernel ? This patch restore CPHYSADDR() for 64 bits kernels _only_. I guess it's ok because we won't need to support mapped kernels on 64 bits machines...
Could others give their opinions ?
Quoted 4 lines
Quoted 1 line
I'm sorry but my IPxx background is 0 ;)
Time to buy an O2 :)
As soon as it will work with a plain linux-mips without hackery ;)
Signature · 1 line
Franck
include/asm-mips/page.h +4 -4
@@ -149,12 +149,12 @@ typedef struct { unsigned long pgprot; } pgprot_t;/* * __pa()/__va() should be used only during mem init. */ -#if defined(CONFIG_64BIT ) && !defined(CONFIG_BUILD_ELF64 ) -#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0) +#ifdef CONFIG_64BIT +#define __pa (x) ((unsigned long)(x) < CKSEG0 ? XPHYSADDR((unsigned long)(x))\ + : CPHYSADDR((unsigned long)(x)))#else -#define __pa_page_offset (x) PAGE_OFFSET +#define __pa (x) ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)#endif -#define __pa (x) ((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET)#define __va (x) ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))#define __pa_symbol (x) __pa(RELOC_HIDE((unsigned long)(x),0))
Quoted 10 lines · Franck Bui-Huu
I'm really not confident with all your tricks you described. Maybe a config that I believed to be uninsteresting and useless should be supported still.
Can you try the attached patch with a plain linux-mips kernel ? This patch restore
CPHYSADDR()for 64 bits kernels _only_. I guess it's ok because we won't need to support mapped kernels on 64 bits machines...Could others give their opinions ?
After going through all the fun to get rid of CPHYSADDR, I see no point really to bring it back. Plus that patch unnecessarily complicates those defines. As I highlighted in my original mail, O2 doesn't need CPHYSADDR added to __pa(), it just needs the conditional define for __pa_page_offset to be a little bit more flexible.
Since only three machines, O2 R5xx, Indy/Indigo2 R4xx, and Cobalt will exhibit similar issues (the latter two when booting 64bit kernels), a saner method in my opinion is to introduce a flag of sorts into the conditional for __pa_page_offset to determine whether to define it strictly to PAGE_OFFSET or to the other value listed in the code. The only thing is, I'm not sure which method of the two I've thought up is cleaner.
The first introduces a hidden Kconfig value, CONFIG_SYS_LOADS_IN_CKSEG0, that only turns on when BUILD_ELF64 && (SGI_IP22 || (SGI_IP32 && (CPU_R5000 || CPU_NEVADA || CPU_RM7000)) || MIPS_COBALT), and then we test for this flag in include/asm-mips/page.h when setting the value of __pa_page_offset.
The other way is to define a similar flag in a new header file, memmap.h, in include/asm-mips/mach-{ip22,ip32,cobalt}/* called MIPS_USES_CKSEG0, and similarly, test for that flag in the same spot as above. With this method, though, I'm not sure where exactly to pull in the memmap.h header, so the patch for it is incomplete (but included for reference).
I've tested the first patch (kconfig one), and it works fine. The second one will also work, provided I find a nice spot to pull in memmap.h, but from a semantics perspective, which one do you guys like better?
--Kumba
Signature · 3 lines
Gentoo/MIPS Team Lead "Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
arch/mips/Kconfig +5 -0
@@ -1659,6 +1659,11 @@ config SB1_PASS_2_1_WORKAROUNDS depends on CPU_SB1 && CPU_SB1_PASS_2 default y +config SYS_LOADS_IN_CKSEG0 + bool + depends on BUILD_ELF64 && (SGI_IP22 || (SGI_IP32 && (CPU_R5000 || CPU_NEVADA || CPU_RM7000)) || MIPS_COBALT) + default y + config 64BIT_PHYS_ADDR bool "Support for 64-bit physical address space" depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32 || CPU_MIPS64) && 32BIT
include/asm-mips/page.h +1 -1
@@ -149,7 +149,7 @@ typedef struct { unsigned long pgprot; }/* * __pa()/__va() should be used only during mem init. */ -#if defined(CONFIG_64BIT ) && !defined(CONFIG_BUILD_ELF64 ) +#if defined(CONFIG_64BIT ) && (!defined(CONFIG_BUILD_ELF64 ) || defined(CONFIG_SYS_LOADS_IN_CKSEG0 ))#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)#else #define __pa_page_offset (x) PAGE_OFFSET
include/asm-mips/mach-cobalt/memmap.h +9 -0
@@ -0,0 +1,9 @@ +#ifndef __ASM_MACH_IP32_MEMMAP_H +#define __ASM_MACH_IP32_MEMMAP_H + + +#ifdef CONFIG_64BIT +#define MIPS_USES_CKSEG0 1 +#endif + +#endif /* __ASM_MACH_IP32_MEMMAP_H */
include/asm-mips/mach-ip22/memmap.h +9 -0
@@ -0,0 +1,9 @@ +#ifndef __ASM_MACH_IP32_MEMMAP_H +#define __ASM_MACH_IP32_MEMMAP_H + + +#ifdef CONFIG_64BIT +#define MIPS_USES_CKSEG0 1 +#endif + +#endif /* __ASM_MACH_IP32_MEMMAP_H */
include/asm-mips/mach-ip32/memmap.h +9 -0
@@ -0,0 +1,9 @@ +#ifndef __ASM_MACH_IP32_MEMMAP_H +#define __ASM_MACH_IP32_MEMMAP_H + + +#if defined(CONFIG_CPU_R5000 ) || defined(CONFIG_CPU_NEVADA ) || defined (CONFIG_CPU_RM7000 ) +#define MIPS_USES_CKSEG0 1 +#endif + +#endif /* __ASM_MACH_IP32_MEMMAP_H */
include/asm-mips/page.h +1 -1
@@ -149,7 +149,7 @@ typedef struct { unsigned long pgprot; }/* * __pa()/__va() should be used only during mem init. */ -#if defined(CONFIG_64BIT ) && !defined(CONFIG_BUILD_ELF64 ) +#if defined(CONFIG_64BIT ) && (!defined(CONFIG_BUILD_ELF64 ) || defined(MIPS_USES_CKSEG0 ))#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)#else #define __pa_page_offset (x) PAGE_OFFSET
Quoted 3 lines · Kumba
After going through all the fun to get rid of CPHYSADDR, I see no point really to bring it back.
The patch restores CPHYSADDR() but in __pa()'s _implementation_. It makes a huge difference.
I think CPHYSADDR() is not that bad for 64 bits kernels. With such beasts we need to handle two PAGE_OFFSET values if we stick with the current implementation of __pa(). Magically using CPHYSADDR() removes this need. OTOH, CPHYSADDR() is quite bad for mapped kernels.
But do we really care in 64 bits world ?
Quoted 5 lines
Plus that patch unnecessarily complicates those defines. As I
highlighted in my original mail, O2 doesn't need CPHYSADDR added to__pa(), it just needs the conditional define for__pa_page_offsetto be a little bit more flexible.
I don't see why the patch complicates those defines. It actually gets rid of CONFIG_BUILD_ELF64 and __pa_page_offset(). OK I could have written it a little bit more readable:
#ifdef CONFIG_64BIT
#define __pa(x) \
({ \
unsigned long __x = (unsigned long)(x); \
__x < CKSEG0 ? XPHYSADDR(__x) : CPHYSADDR(__x); \
})#else
#define __pa(x) \
((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
#endif
Yes, it actually increases size code for CONFIG_64BIT because we always test if the virtual address is from XKPHYS or CKSEG0. But how much ? I would say not a lot, and it maybe worths it since we get rid of an obscure config option.
Franck
Signature · 1 line
Franck
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hi!
Did you try to use PHYS_OFFSET > 0 ? __pa() ist still (as of d3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7) defined as (casts omitted):
#define __pa(x) (x - (x < CKSEG0 ? PAGE_OFFSET:CKSEG0) + PHYS_OFFSET)
This gives __pa(CKSEG0) == PHYS_OFFSET, which will never work for PHYS_OFFSET > 0. A quick fix (assuming this was the cause for failure) could be:
========================================================================
include/asm-mips/page.h +1 -1
@@ -150,7 +150,7 @@ typedef struct { unsigned long pgprot; }* __pa()/__va() should be used only during mem init. */ #if defined(CONFIG_64BIT ) && !defined(CONFIG_BUILD_ELF64 ) -#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0) +#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0+PHYS_OFFSET)#else #define __pa_page_offset (x) PAGE_OFFSET#endif
========================================================================
Of course, "#define PAGE_OFFSET (CAC_BASE + PHYS_OFFSET)" is also needed.
kind regards
peter
Quoted 65 lines · Kumba
Date: Sat, 17 Mar 2007 14:53:23 -0400
From: Kumba <[email protected]>
To: Franck Bui-Huu <[email protected]>
Cc: peter fuerst <[email protected]>
Subject: Re: IP32 prom crashes due to__pa()funkinessQuoted 2 lines · Franck Bui-Huu
Hi,
[snip]
Quoted 9 lines
Well, it means that you previously used
CONFIG_BUILD_ELF64=y(this implied thatPAGE_OFFSETis in XKPHYS) whereas your kernel has CKSEG load address (symbols needPAGE_OFFSETin CKSEG for address translation).So the question is why can't you use
CONFIG_BUILD_ELF64=n(and reagarding the current definition ofCONFIG_BUILD_ELF64).[snip]
Quoted 7 lines
It makes me think that I posted a patch for that a couple of weeks ago:
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480225936&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480126802&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154587014827&w=2Quoted 6 lines
Basically this patch removes
CONFIG_BUILD_ELF64and makesKbuildto use '-msym32' switch if you really need it.Kbuildmakes its choice according the load address of your kernel image.Could you give it a try ? This patch was based on 2.6.20 but it should apply fine on a 2.6.21-rc[12].
Tested, and it still failed.
And I didn't always use
CONFIG_BUILD_ELF64. In fact, for the longest time (up until 2.6.17) I built IP32 and 64bit IP22 kernels withoutCONFIG_BUILD_eLF64, passing -mabi=o64 (a.k.a., the binutils hack). This let me use the plain 'vmlinux' target w/o the need for an objcopy to boot these systems. After 2.6.17, the nature of o64 was mostly neutered, so I switched to usingCONFIG_BUILD_ELF64and the 'vmlinux.32' target, as this is apparently the way Debian builds their IP32 kernels (and was the way geoman/spbecker said I should've been using all along).So with the changes brought in by
__pa(), I suppose a new, RightWay(TM) to build IP32 (and conversely, 64bit IP22) kernels needs to be found. These two systems are particularly wacky, hence why they need a bit more special care than more traditional, proper, 64bit systems like Origin and Octane.Also, Peter raises a good point in this case. It sounds like a re-thinking of how all this address stuff is handled will fix not only special cases like IP32/IP22, but the really weird systems, like IP28, as well. Which would be a big plus in my opinion.
--Kumba
--
Gentoo/MIPS Team Lead"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
Quoted 28 lines · peter fuerst
Hi!
Did you try to use
PHYS_OFFSET> 0 ?__pa()ist still (as ofd3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7) defined as (casts omitted):#define
__pa(x)(x - (x < CKSEG0 ? PAGE_OFFSET:CKSEG0) +PHYS_OFFSET)This gives
__pa(CKSEG0)==PHYS_OFFSET, which will never work forPHYS_OFFSET> 0. A quick fix (assuming this was the cause for failure) could be:========================================================================
include/asm-mips/page.h +1
-1@@ -150,7 +150,7 @@ typedef struct { unsigned long pgprot; }* __pa()/__va() should be used only during mem init. */ #if defined(CONFIG_64BIT ) && !defined(CONFIG_BUILD_ELF64 ) -#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0) +#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0+PHYS_OFFSET)#else #define __pa_page_offset (x) PAGE_OFFSET#endif Signed-off-by peter fuerst <[email protected]>
Quoted 7 lines
========================================================================
Of course, "#define
PAGE_OFFSET(CAC_BASE+PHYS_OFFSET)" is also needed.kind regards
peter
Hmm, I can't find where PHYS_OFFSET is defined for mips. A grep shows it mostly existing for the arm arch. Is there an alternative macro available, or is this something that needs porting over?
--Kumba
Signature · 3 lines
Gentoo/MIPS Team Lead "Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
Quoted 36 lines · Kumba
Quoted 35 lines · peter fuerst
Hi!
Did you try to use
PHYS_OFFSET> 0 ?__pa()ist still (as ofd3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7) defined as (casts omitted):#define
__pa(x)(x - (x < CKSEG0 ? PAGE_OFFSET:CKSEG0) +PHYS_OFFSET)This gives
__pa(CKSEG0)==PHYS_OFFSET, which will never work forPHYS_OFFSET> 0. A quick fix (assuming this was the cause for failure) could be:========================================================================
---d3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7/include/asm-mips/page.hSat Mar 10 08:43:17 2007
+++quickfix/include/asm-mips/page.hSun Mar 18 10:24:34 2007include/asm-mips/page.h +1
-1@@ -150,7 +150,7 @@ typedef struct { unsigned long pgprot; }* __pa()/__va() should be used only during mem init. */ #if defined(CONFIG_64BIT ) && !defined(CONFIG_BUILD_ELF64 ) -#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0) +#define __pa_page_offset(x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0+PHYS_OFFSET) #else#define
__pa_page_offset(x)PAGE_OFFSET
#endifSigned-off-by peter fuerst <[email protected]>========================================================================
Of course, "#define
PAGE_OFFSET(CAC_BASE+PHYS_OFFSET)" is also needed.
Quoted 8 lines
Quoted 3 lines
kind regards
peter
Hmm, I can't find where
PHYS_OFFSETis defined for mips. A grep shows it mostly existing for the arm arch. Is there an alternative macro available, or is this something that needs porting over?--Kumba
Ah, duh. PHYS_OFFSET was introduced post-2.6.20, so I won't be able to leverage this w/o backporting.
--Kumba
Signature · 3 lines
Gentoo/MIPS Team Lead "Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
Quoted 28 lines · peter fuerst
Hi!
Did you try to use
PHYS_OFFSET> 0 ?__pa()ist still (as ofd3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7) defined as (casts omitted):#define
__pa(x)(x - (x < CKSEG0 ? PAGE_OFFSET:CKSEG0) +PHYS_OFFSET)This gives
__pa(CKSEG0)==PHYS_OFFSET, which will never work forPHYS_OFFSET> 0. A quick fix (assuming this was the cause for failure) could be:========================================================================
include/asm-mips/page.h +1
-1@@ -150,7 +150,7 @@ typedef struct { unsigned long pgprot; }* __pa()/__va() should be used only during mem init. */ #if defined(CONFIG_64BIT ) && !defined(CONFIG_BUILD_ELF64 ) -#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0) +#define __pa_page_offset (x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0+PHYS_OFFSET)#else #define __pa_page_offset (x) PAGE_OFFSET#endif Signed-off-by peter fuerst <[email protected]>
Quoted 7 lines
========================================================================
Of course, "#define
PAGE_OFFSET(CAC_BASE+PHYS_OFFSET)" is also needed.kind regards
peter
Backported the patches that bring in PHYS_OFFSET and tried both with and without Frank's patches to remove CONFIG_BUILD_ELF64 from the Makefile, plus this change, and still no go. W/o CONFIG_BUILD_ELF64, both the vmlinux and vmlinux.32 targets just silently hang. With CONFIG_BUILD_ELF64 in the Makefile, the same Prom crash.
--Kumba
Signature · 3 lines
Gentoo/MIPS Team Lead "Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
Quoted 7 lines · Kumba
Backported the patches that bring in
PHYS_OFFSETand tried both with and without Frank's patches to removeCONFIG_BUILD_ELF64from theMakefile, plus this change, and still no go. W/oCONFIG_BUILD_ELF64, both the vmlinux and vmlinux.32 targets just silently hang. WithCONFIG_BUILD_ELF64in theMakefile, the same Prom crash.
wait wait wait. PHYS_OFFSET has nothing to do in this case. You are obvioulsy not using it by default.
Signature · 1 line
Franck