remove BAT mappings
PATCH 1/1 remove BAT mappings
This patch removes the use of BAT registers to perform virtual memory translations. BATs are a convenient way to avoid dealing with page tables, however, there are two problems:
- Old World Macs apparently do not consider the BAT registers when performing /chosen/mmu "translate" calls. The Linux kernel requires that the "translate" result be accurate.
(Given that New World Macs seem to have been booting ok without this, I can only assume that New World firmware was fixed.)
- BATs have been removed from POWER4 and POWER5 processors, used in pSeries servers.
Instead of performing large one-time mappings, we map what we need. We do this by calling the "map" method of /chosen/mmu (after claiming the space first).
I have tested this patch on Old World and New World Macintosh. With this patch applied, Old World can successfully boot into Linux. :)
-Hollis
2004-10-15 Hollis Blanchard <[email protected]>
* boot/powerpc/ieee1275/cmain.c (cmain): Remove asm statements which initialized BAT registers.
* boot/powerpc/ieee1275/ieee1275.c (IEEE1275_CALL_ENTRY_FN): Move to include/grub/powerpc/ieee1275/ieee1275.h. (grub_ieee1275_common_hdr): Likewise. (INIT_IEEE1275_COMMON): Likewise.
* include/grub/powerpc/ieee1275/ieee1275.h (IEEE1275_CALL_ENTRY_FN):
Move from boot/powerpc/ieee1275/ieee1275.c. (grub_ieee1275_common_hdr): Likewise. (INIT_IEEE1275_COMMON): Likewise.
* kern/powerpc/ieee1275/openfw.c (grub_map): New function. (grub_mapclaim): Likewise.
* loader/powerpc/ieee1275/linux.c (grub_load_linux): Use grub_mapclaim instead of grub_ieee1275_claim. Assign linux_addr by hand.
Index: boot/powerpc/ieee1275/cmain.c
===================================================================
RCS file: /cvsroot/grub/grub2/boot/powerpc/ieee1275/cmain.c,v retrieving revision 1.3
powerpc/ieee1275/cmain.c +0 -22
@@ -55,7 +55,6 @@ cmain (uint32_t r3, uint32_t r4 __attribchar **argv, args[256 ];grub_ieee1275_phandle_t chosen;int argc =0 , actual; -long batl, batu;if (r5 ==0xdeadbeef ) {
@@ -81,27 +80,6 @@ cmain (uint32_t r3, uint32_t r4 __attrib grub_ieee1275_entry_fn = (intptr_t (*)(void *)) r5; } -/* Initialize BAT registers to unmapped to not generate overlapping -mappings below. */ - asmvolatile ("mtibatu 0,%0" ::"r" (0 )); - asmvolatile ("mtibatu 1,%0" ::"r" (0 )); - asmvolatile ("mtibatu 2,%0" ::"r" (0 )); - asmvolatile ("mtibatu 3,%0" ::"r" (0 )); - asmvolatile ("mtdbatu 0,%0" ::"r" (0 )); - asmvolatile ("mtdbatu 1,%0" ::"r" (0 )); - asmvolatile ("mtdbatu 2,%0" ::"r" (0 )); - asmvolatile ("mtdbatu 3,%0" ::"r" (0 )); - -/* Set up initial BAT table to only map the lowest 256 MB area. */ - batl =0x00000000 |0x10 |0x02 ; - batu =0x00000000 |0x1ffc |0x02 ; - -/* IBAT0 used for initial 256 MB segment */ - asmvolatile ("mtibatl 3,%0; mtibatu 3,%1" ::"r" (batl),"r" (batu)); -/* DBAT0 used similar */ - asmvolatile ("mtdbatl 3,%0; mtdbatu 3,%1" ::"r" (batl),"r" (batu)); - asm ("isync" ); -/* If any argument was passed to the kernel (us), they are put in the bootargs property of /chosen. The string can be null (just the nul-character), so check that the size
Index: boot/powerpc/ieee1275/ieee1275.c
===================================================================
RCS file: /cvsroot/grub/grub2/boot/powerpc/ieee1275/ieee1275.c,v retrieving revision 1.7
powerpc/ieee1275/ieee1275.c +0 -19
@@ -26,25 +26,6 @@intptr_t (*grub_ieee1275_entry_fn) (void *); -#ifndef IEEE1275_CALL_ENTRY_FN -#define IEEE1275_CALL_ENTRY_FN (args) (*grub_ieee1275_entry_fn) (args) -#endif - -/* All backcalls to the firmware is done by calling an entry function -which was passed to us from the bootloader. When doing the backcall, -a structure is passed which specifies what the firmware should do. -NAME is the requested service. NR_INS and NR_OUTS is the number of -passed arguments and the expected number of return values, resp. */ -struct grub_ieee1275_common_hdr -{ -char *name; -int nr_ins; -int nr_outs; -}; - -#define INIT_IEEE1275_COMMON (p, xname, xins, xouts) \ - (p)->name = xname; (p)->nr_ins = xins; (p)->nr_outs = xouts -/* FIXME is this function needed? */ grub_uint32_t grub_ieee1275_decode_int_4 (unsigned char *p)
Index: include/grub/powerpc/ieee1275/ieee1275.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/powerpc/ieee1275/ieee1275.h,v retrieving revision 1.8
grub/powerpc/ieee1275/ieee1275.h +22 -0
@@ -39,6 +39,27 @@ struct grub_ieee1275_mem_regionunsigned int size; }; +extern intptr_t (*grub_ieee1275_entry_fn) (void *); + +#ifndef IEEE1275_CALL_ENTRY_FN +#define IEEE1275_CALL_ENTRY_FN (args) (*grub_ieee1275_entry_fn) (args) +#endif + +/* All backcalls to the firmware is done by calling an entry function +which was passed to us from the bootloader. When doing the backcall, +a structure is passed which specifies what the firmware should do. +NAME is the requested service. NR_INS and NR_OUTS is the number of +passed arguments and the expected number of return values, resp. */ +struct grub_ieee1275_common_hdr +{ +char *name; +int nr_ins; +int nr_outs; +}; + +#define INIT_IEEE1275_COMMON (p, xname, xins, xouts) \ + (p)->name = xname; (p)->nr_ins = xins; (p)->nr_outs = xouts +/* FIXME jrydberg: is this correct cell types? */ typedef intptr_t grub_ieee1275_ihandle_t ;typedef intptr_t grub_ieee1275_phandle_t ;
@@ -103,6 +124,7 @@ grub_err_t EXPORT_FUNC(grub_devalias_ite (int (*hook) (struct grub_ieee1275_devalias *alias));grub_err_t EXPORT_FUNC (grub_children_iterate ) (char *devpath,int (*hook) (struct grub_ieee1275_devalias *alias)); +int EXPORT_FUNC (grub_claimmap ) (grub_addr_t addr,grub_size_t size);void EXPORT_FUNC (abort ) (void );
Index: kern/powerpc/ieee1275/openfw.c
===================================================================
RCS file: /cvsroot/grub/grub2/kern/powerpc/ieee1275/openfw.c,v retrieving revision 1.3
powerpc/ieee1275/openfw.c +54 -0
57 lines not on this page · raw message
Index: loader/powerpc/ieee1275/linux.c
===================================================================
RCS file: /cvsroot/grub/grub2/loader/powerpc/ieee1275/linux.c,v retrieving revision 1.3
powerpc/ieee1275/linux.c +3 -2
@@ -188,12 +188,13 @@ grub_load_linux (int argc, char *argv[])/* Reserve memory for the kernel. */ linux_size +=0x100000 ; -if (grub_ieee1275_claim (entry, linux_size,0 , &linux_addr) ==-1 ) +if (grub_claimmap (entry, linux_size) ==-1 ) {grub_error (GRUB_ERR_OUT_OF_MEMORY ,"Can not claim memory" ); goto fail; } - + linux_addr = entry; +/* Load every loadable segment in memory. */ for (i =0 ; i < ehdr.e_phnum; i++) {
Any comments on this patch?
Quoted 258 lines · Hollis Blanchard
This patch removes the use of BAT registers to perform virtual memory translations. BATs are a convenient way to avoid dealing with page tables, however, there are two problems:
- Old World Macs apparently do not consider the BAT registers when performing /chosen/mmu "translate" calls. The Linux kernel requires that the "translate" result be accurate.
(Given that New World Macs seem to have been booting ok without
this, I
can only assume that New World firmware was fixed.)
- BATs have been removed from POWER4 and POWER5 processors, used in pSeries servers.Instead of performing large one-time mappings, we map what we need. We do this by calling the "map" method of /chosen/mmu (after claiming the space first).
I have tested this patch on Old World and New World Macintosh. With this patch applied, Old World can successfully boot into Linux. :)
-Hollis
2004-10-15 Hollis Blanchard <[email protected]>
*
boot/powerpc/ieee1275/cmain.c(cmain): Remove asm statements which initialized BAT registers.
*boot/powerpc/ieee1275/ieee1275.c(IEEE1275_CALL_ENTRY_FN): Move toinclude/grub/powerpc/ieee1275/ieee1275.h. (grub_ieee1275_common_hdr): Likewise. (INIT_IEEE1275_COMMON): Likewise.
*include/grub/powerpc/ieee1275/ieee1275.h(IEEE1275_CALL_ENTRY_FN):
Move fromboot/powerpc/ieee1275/ieee1275.c. (grub_ieee1275_common_hdr): Likewise. (INIT_IEEE1275_COMMON): Likewise.
*kern/powerpc/ieee1275/openfw.c(grub_map): New function. (grub_mapclaim): Likewise.
*loader/powerpc/ieee1275/linux.c(grub_load_linux): Usegrub_mapclaiminstead ofgrub_ieee1275_claim. Assignlinux_addrby hand.Index:
boot/powerpc/ieee1275/cmain.c
===================================================================
RCS file: /cvsroot/grub/grub2/boot/powerpc/ieee1275/cmain.c,v retrieving revision 1.3
diff -u -p -r1.3cmain.cpowerpc/ieee1275/cmain.c +0
-22@@ -55,7 +55,6 @@ cmain (uint32_t r3, uint32_t r4 __attribchar **argv, args[256 ];grub_ieee1275_phandle_t chosen;int argc =0 , actual; -long batl, batu;if (r5 ==0xdeadbeef ) {@@ -81,27 +80,6 @@ cmain (uint32_t r3, uint32_t r4 __attrib grub_ieee1275_entry_fn = (intptr_t (*)(void *)) r5; } -/* Initialize BAT registers to unmapped to not generate overlapping -mappings below. */ - asmvolatile ("mtibatu 0,%0" ::"r" (0 )); - asmvolatile ("mtibatu 1,%0" ::"r" (0 )); - asmvolatile ("mtibatu 2,%0" ::"r" (0 )); - asmvolatile ("mtibatu 3,%0" ::"r" (0 )); - asmvolatile ("mtdbatu 0,%0" ::"r" (0 )); - asmvolatile ("mtdbatu 1,%0" ::"r" (0 )); - asmvolatile ("mtdbatu 2,%0" ::"r" (0 )); - asmvolatile ("mtdbatu 3,%0" ::"r" (0 )); - -/* Set up initial BAT table to only map the lowest 256 MB area. */ - batl =0x00000000 |0x10 |0x02 ; - batu =0x00000000 |0x1ffc |0x02 ; - -/* IBAT0 used for initial 256 MB segment */ - asmvolatile ("mtibatl 3,%0; mtibatu 3,%1" ::"r" (batl),"r" (batu)); -/* DBAT0 used similar */ - asmvolatile ("mtdbatl 3,%0; mtdbatu 3,%1" ::"r" (batl),"r" (batu)); - asm ("isync" ); -/* If any argument was passed to the kernel (us), they are put in the bootargs property of /chosen. The string can be null (just the nul-character), so check that the size
Index:boot/powerpc/ieee1275/ieee1275.c
===================================================================
RCS file: /cvsroot/grub/grub2/boot/powerpc/ieee1275/ieee1275.c,v retrieving revision 1.7
diff -u -p -r1.7ieee1275.cpowerpc/ieee1275/ieee1275.c +0
-19@@ -26,25 +26,6 @@intptr_t (*grub_ieee1275_entry_fn) (void *); -#ifndef IEEE1275_CALL_ENTRY_FN -#define IEEE1275_CALL_ENTRY_FN (args) (*grub_ieee1275_entry_fn) (args) -#endif - -/* All backcalls to the firmware is done by calling an entry function -which was passed to us from the bootloader. When doing the backcall, -a structure is passed which specifies what the firmware should do. -NAME is the requested service. NR_INS and NR_OUTS is the number of -passed arguments and the expected number of return values, resp. */ -struct grub_ieee1275_common_hdr -{ -char *name; -int nr_ins; -int nr_outs; -}; - -#define INIT_IEEE1275_COMMON (p, xname, xins, xouts) \ - (p)->name = xname; (p)->nr_ins = xins; (p)->nr_outs = xouts -/* FIXME is this function needed? */ grub_uint32_t
grub_ieee1275_decode_int_4(unsigned char *p)
Index:include/grub/powerpc/ieee1275/ieee1275.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/powerpc/ieee1275/ieee1275.h,v retrieving revision 1.8
diff -u -p -r1.8ieee1275.h
---include/grub/powerpc/ieee1275/ieee1275.h15 Oct 2004 02:29:11
-0000 1.8
+++include/grub/powerpc/ieee1275/ieee1275.h15 Oct 2004 22:19:54 -0000powerpc/ieee1275/ieee1275.c +21
-0@@ -39,6 +39,27 @@ struct grub_ieee1275_mem_regionunsigned int size; }; +extern intptr_t (*grub_ieee1275_entry_fn) (void *); + +#ifndef IEEE1275_CALL_ENTRY_FN +#define IEEE1275_CALL_ENTRY_FN (args) (*grub_ieee1275_entry_fn) (args) +#endif + +/* All backcalls to the firmware is done by calling an entry function +which was passed to us from the bootloader. When doing the backcall, +a structure is passed which specifies what the firmware should do. +NAME is the requested service. NR_INS and NR_OUTS is the number of +passed arguments and the expected number of return values, resp. */ +struct grub_ieee1275_common_hdr +{ +char *name; +int nr_ins; +int nr_outs; +}; + +#define INIT_IEEE1275_COMMON (p, xname, xins, xouts) \ + (p)->name = xname; (p)->nr_ins = xins; (p)->nr_outs = xouts +/* FIXME jrydberg: is this correct cell types? */ typedef intptr_t grub_ieee1275_ihandle_t ;typedef
intptr_tgrub_ieee1275_phandle_t;powerpc/ieee1275/ieee1275.c +1
-0@@ -103,6 +124,7 @@ grub_err_t EXPORT_FUNC(grub_devalias_ite (int (*hook) (struct grub_ieee1275_devalias *alias));grub_err_t EXPORT_FUNC (grub_children_iterate ) (char *devpath,int (*hook) (struct grub_ieee1275_devalias *alias)); +int EXPORT_FUNC (grub_claimmap ) (grub_addr_t addr,grub_size_t size);void EXPORT_FUNC (abort ) (void );Index:
kern/powerpc/ieee1275/openfw.c
===================================================================
RCS file: /cvsroot/grub/grub2/kern/powerpc/ieee1275/openfw.c,v retrieving revision 1.3
diff -u -p -r1.3openfw.cpowerpc/ieee1275/openfw.c +54
-0@@ -137,3 +137,57 @@ grub_devalias_iterate (int (*hook) (strureturn 0 ; } + +/* Call the "map" method of /chosen/mmu. */ +int +grub_map (grub_addr_t phys,grub_addr_t virt,grub_uint32_t size, +grub_uint8_t mode) +{ +struct map_args { +struct grub_ieee1275_common_hdr common; +char *method; +grub_ieee1275_ihandle_t ihandle; +grub_uint32_t mode; +grub_uint32_t size; +grub_uint32_t virt; +grub_uint32_t phys; +int catch_result; + } args; +grub_ieee1275_ihandle_t mmu; +grub_ieee1275_ihandle_t chosen; +int len; + +grub_ieee1275_finddevice ("/chosen" , &chosen); +if (chosen ==0 ) +return -1 ; + +grub_ieee1275_get_property (chosen,"mmu" , &mmu,sizeof mmu, &len); +if (len !=sizeof mmu) +return -1 ; + +INIT_IEEE1275_COMMON (&args.common,"call-method" ,6 ,1 ); + args.method ="map" ; + args.ihandle = mmu; + args.phys = phys; + args.virt = virt; + args.size = size; + args.mode = mode;/* Format is WIMG0PP. */ + +if (IEEE1275_CALL_ENTRY_FN (&args) ==-1 ) +return -1 ; + +return args.catch_result; +} + +int +grub_claimmap (grub_addr_t addr,grub_size_t size) +{ +if (grub_ieee1275_claim (addr, size,0 ,0 )) +return -1 ; +if (grub_map (addr, addr, size,0x00 )) + { +grub_ieee1275_release (addr, size); +return -1 ; + } +return 0 ; +}Index:
loader/powerpc/ieee1275/linux.c
===================================================================
RCS file: /cvsroot/grub/grub2/loader/powerpc/ieee1275/linux.c,v retrieving revision 1.3
diff -u -p -r1.3linux.cpowerpc/ieee1275/linux.c +3
-2@@ -188,12 +188,13 @@ grub_load_linux (int argc, char *argv[])/* Reserve memory for the kernel. */ linux_size +=0x100000 ; -if (grub_ieee1275_claim (entry, linux_size,0 , &linux_addr) ==-1 ) +if (grub_claimmap (entry, linux_size) ==-1 ) {grub_error (GRUB_ERR_OUT_OF_MEMORY ,"Can not claim memory" ); goto fail; } - + linux_addr = entry; +/* Load every loadable segment in memory. */ for (i =0 ; i < ehdr.e_phnum; i++) {_______________________________________________
Grub-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/grub-devel
Quoted 1 line · Hollis Blanchard
Any comments on this patch?
I hope Johan can tell us more about this, he wrote this code.
--
Marco
Quoted 5 lines · Marco Gerards
Quoted 1 line · Hollis Blanchard
Any comments on this patch?
I hope Johan can tell us more about this, he wrote this code.
No, I do not have any comments. I just added the mappings to have a known state when entering my OS (where the code originally came from.)
If removing them enables us to boot Linux? Good. Make them go away.
~j