This patchset contains some minor SPARC32 fixups, as well as clearing all physical RAM on startup. This fixes rebooting under Solaris which evidently doesn't clear memory for some key internal memory structures before attempting to use them at boot.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
Mark Cave-Ayland (4): SPARC32: minor tidy-up for boot.c SPARC32: fix initialisation of L1 page table SPARC32: make pre-loaded kernel image memory as being in use SPARC32: clear unused physical memory upon startup
openbios-devel/arch/sparc32/boot.c | 5 +---- openbios-devel/arch/sparc32/boot.h | 1 + openbios-devel/arch/sparc32/lib.c | 13 ++++++++++++- openbios-devel/arch/sparc32/openbios.c | 19 +++++++++++++++++-- 4 files changed, 31 insertions(+), 7 deletions(-)
This commit doesn't have any functional changes but removes some debugging printks accidentally included by a previous commit, plus adds a +1 offset back onto the size of tail prommap entry to ensure that it is correctly aligned.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc32/boot.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/openbios-devel/arch/sparc32/boot.c b/openbios-devel/arch/sparc32/boot.c index c309891..49ec4cf 100644 --- a/openbios-devel/arch/sparc32/boot.c +++ b/openbios-devel/arch/sparc32/boot.c @@ -147,9 +147,6 @@ static void setup_romvec(void) (**pp).start_adr = (char *)intprop_ptr[1]; (**pp).num_bytes = intprop_ptr[2];
- printk("start_adr: %x\n", (int)(**pp).start_adr); - printk("num_bytes: %x\n", (**pp).num_bytes); - intprop_ptr += 3; }
@@ -180,7 +177,7 @@ static void setup_romvec(void) (**pp).num_bytes = (intprop_ptr[4] + intprop_ptr[5]) - (intprop_ptr[1] + intprop_ptr[2]); } else { /* Tail (size from top of virtual memory) */ - (**pp).num_bytes = 0xffffffffUL - (intprop_ptr[1] + intprop_ptr[2]); + (**pp).num_bytes = 0xffffffffUL - (intprop_ptr[1] + intprop_ptr[2]) + 1; }
intprop_ptr += 3;
Since l1 is a pointer to an array of longs, the increment size should be 1 (element) and not 4 (bytes). While this shouldn't have an effect when booting an image from fresh, it meant that the L1 page table contained old entries after a reboot.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc32/lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/openbios-devel/arch/sparc32/lib.c b/openbios-devel/arch/sparc32/lib.c index af1812d..d27b604 100644 --- a/openbios-devel/arch/sparc32/lib.c +++ b/openbios-devel/arch/sparc32/lib.c @@ -367,7 +367,7 @@ init_mmu_swift(void) for (i = 1; i < NCTX_SWIFT; i++) { context_table[i] = SRMMU_ET_INVALID; } - for (i = 0; i < 256; i += 4) { + for (i = 0; i < 256; i++) { l1[i] = SRMMU_ET_INVALID; }
This is in preparation to enable us to clear physical memory on boot. However if a kernel image is supplied then we need to know this region is in use in order to prevent it being cleared by accident.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc32/openbios.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/openbios-devel/arch/sparc32/openbios.c b/openbios-devel/arch/sparc32/openbios.c index 32255b6..6f4ee45 100644 --- a/openbios-devel/arch/sparc32/openbios.c +++ b/openbios-devel/arch/sparc32/openbios.c @@ -865,9 +865,14 @@ arch_init( void ) romvec = init_openprom();
kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE); - if (kernel_size) + if (kernel_size) { kernel_image = fw_cfg_read_i32(FW_CFG_KERNEL_ADDR);
+ /* Mark the kernel memory as in use */ + ofmem_claim_phys(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0); + ofmem_claim_virt(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0); + } + kernel_cmdline = (const char *) fw_cfg_read_i32(FW_CFG_KERNEL_CMDLINE); if (kernel_cmdline) { cmdline = strdup(kernel_cmdline);
This is to work around a bug in Solaris which appears not to explicitly clear some of its internal kmem structures (particularly its pagelists) on boot. The result of this is that Solaris will initially boot fine, until a reboot/reset is initiated.
When this occurs, the kmem structures contain whatever junk was previously left in memory during initialisation causing a panic. The fix is to clear physical memory on startup (as OBP appears to do) so that the kmem intialisation code behaves correctly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc32/boot.h | 1 + openbios-devel/arch/sparc32/lib.c | 11 +++++++++++ openbios-devel/arch/sparc32/openbios.c | 12 +++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/openbios-devel/arch/sparc32/boot.h b/openbios-devel/arch/sparc32/boot.h index 55e391a..d099241 100644 --- a/openbios-devel/arch/sparc32/boot.h +++ b/openbios-devel/arch/sparc32/boot.h @@ -39,3 +39,4 @@ extern struct linux_mlist_v0 *ptavail;
void ob_init_mmu(void); void init_mmu_swift(void); +void clear_memory(unsigned long start, unsigned long end); diff --git a/openbios-devel/arch/sparc32/lib.c b/openbios-devel/arch/sparc32/lib.c index d27b604..08b8133 100644 --- a/openbios-devel/arch/sparc32/lib.c +++ b/openbios-devel/arch/sparc32/lib.c @@ -283,6 +283,17 @@ static void ignore_dfault_addr(void) PUSH(pointer2cell(&ignore_dfault)); }
+/* Clear all physical memory between start and end */ +void clear_memory(unsigned long start, unsigned long end) +{ + unsigned long addr; + + for (addr = start; addr < end; addr+=4) { + __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : + "r" (addr), "i" (ASI_M_BYPASS)); + } +} + void ob_init_mmu(void) { diff --git a/openbios-devel/arch/sparc32/openbios.c b/openbios-devel/arch/sparc32/openbios.c index 6f4ee45..7273b6a 100644 --- a/openbios-devel/arch/sparc32/openbios.c +++ b/openbios-devel/arch/sparc32/openbios.c @@ -814,7 +814,9 @@ arch_init( void ) uint32_t temp; uint16_t machine_id; char buf[256]; - unsigned long mem_size; + unsigned long mem_size, start; + ofmem_t *ofmem = ofmem_arch_get_private(); + range_t *r;
fw_cfg_init();
@@ -882,6 +884,14 @@ arch_init( void ) } qemu_cmdline = (uint32_t)cmdline;
+ printk("Initialising memory..."); + start = 0; + for (r = ofmem->phys_range; r->next; r = r->next) { + clear_memory(start, r->start - start); + start = r->start + r->size; + } + printk(" done\n"); + /* Setup nvram variables */ push_str("/options"); fword("find-device");