Malban
Posts: 38
Joined: Thu Aug 01, 2019 6:16 pm
Location: Germany
Contact: Website

Bootloader - again

Thu Aug 01, 2019 6:42 pm

Hi,
(Pi Zero W) I have written a simple boot loader - following steps:

- On boot time the kernel.img (I call it boostrap) is loaded as usual
- I set up stacks (to $a00000), exception handlers,
- I setup MMU (code from: https://github.com/vanvught/rpidmx512) and cache and allow unaligned addressing, Supervisor mode is further used

- I load another "program" to $b00000 and execute it (jmp to $b00000)
- then I output to screen three other "img" filenames that can be loaded
- these files are "normal" kernel image files that can all be booted (tested) as standalone kernels
(they are compiled to be "runable" from $8000)
- these kernel images all use the same "kernel start" which is also the same as the bootstrap (e.g. they all setup mmu, stack etc) - again

- when I select kernel file 1 - it loads as expected and boots the pi and runs well (I jump from my "loader" to address $8000)
- when I select kernel file 2 - it loads as expected and boots the pi and runs well
- when I select kernel file 3 - it loads as expected and it DOES NOT RUN!
Pi hangs itself before I even get to the "main()" call.

And... before the said "main()" call EVERYTHING these 3 kernel images do is exactly the same.

I know without sources this is more a "theoretical" question. I can provide everything - only thing it is a bit much to include here.
And I sort of doubt that there is something really unexpected in those files (and the boot menu can't be see on a normal screen - I am addressing via a special device connected to the GPIOs of the Pi a retro console - a vectrex - and the boot selection is shown on that console).

My question is - "in general" - am I missing something? I tried disabling the MMU before "restarting", doing diverse memory barriers or syncing, deleted cache etc - but it always behaves more or less the same - or worse.

I noticed when disabling the MMU before jumping to the loaded img (1:1 mapping) none of the img files execute (or the pi just hangs)
This sort of took my attention to the MMU - why would "disabling" the MMU crash the execution of a "fresh" kernel - that is the state that is expected - isn't it?

The disable MMU code is the "opposite" of the enable code:

Code: Select all

#define ARM_CONTROL_MMU				(1 << 0)
#define ARM_CONTROL_STRICT_ALIGNMENT		(1 << 1)
#define ARM_CONTROL_L1_CACHE				(1 << 2)
#define ARM_CONTROL_BRANCH_PREDICTION		(1 << 11)
#define ARM_CONTROL_L1_INSTRUCTION_CACHE 	(1 << 12)

#define MMU_MODE	(  ARM_CONTROL_MMU				\
			 | ARM_CONTROL_L1_CACHE					\
			 | ARM_CONTROL_L1_INSTRUCTION_CACHE	\
			 | ARM_CONTROL_BRANCH_PREDICTION)

void mmu_disable(void) 
{
    // disable MMU
    uint32_t control;
    asm volatile ("mrc p15, 0, %0, c1, c0,  0" : "=r" (control));
    control = control & (~MMU_MODE);
    asm volatile ("mcr p15, 0, %0, c1, c0,  0" : : "r" (control) : "memory");
}
Any thoughts ?

Thanks

Malban

LdB
Posts: 1706
Joined: Wed Dec 07, 2016 2:29 pm

Re: Bootloader - again

Thu Aug 01, 2019 11:45 pm

AFAIK there is a legacy 2-instruction delay in turning off the MMU or you need the equivalent of an ARM7 isb to clear the pipelines.
Trying putting 2 "NOP"'s after you turn it off before you try to execute a real op-code as a hack.

That is what the old linux code did .. see the two nops after they did it

Code: Select all

 disable_mmu:
 	/* Disable MMU for a while */
	mrc     p15, 0, r2, c1, c0, 0
 	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
 	    CPU_CONTROL_WBUF_ENABLE)
 	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
 	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
	mcr     p15, 0, r2, c1, c0, 0
  	nop
 	nop

Malban
Posts: 38
Joined: Thu Aug 01, 2019 6:16 pm
Location: Germany
Contact: Website

Re: Bootloader - again

Fri Aug 02, 2019 6:50 am

Hi,
thank you for your insight - I'll try adding a few NOPs. (later tonight)

Thing is I don't think that's it.
Like in the good old days I have tried "printf" debugging (going to UART 1).

After I disable the MMU I print the first 8 bytes of location $8000 onwards (to ensure the "loading" part did load successfully to $8000) - and that output is coming across without error.

After that printing I jump to $8000 - and even if I immediately try to print something again - like "Ok" - the Pi seems to hang.

What I didn't try yet was to do additional debugging output in one of the exception handlers - thats what I'll try next.

Malban

Malban
Posts: 38
Joined: Thu Aug 01, 2019 6:16 pm
Location: Germany
Contact: Website

Re: Bootloader - again

Fri Aug 02, 2019 5:18 pm

Hi,

I tried your suggestion - as I tried several other thoughts - none worked.
Growing more desperate I tried "idiotic" things.

For no reason, other than it doesn't stall anymore the following works:

(You see many commented tries - what for now does the trick is: mmu_disable(); mmu_enable();
Disabling the MMU and than enabling it again - and than rebooting.
There is no reason I can concern why that should work any better than any other thing I tried... but right now I have no problems
anymore. If anyone wants to shed some more light on the subject you are welcome - I very much prefer to understand
how my own programs work.
)

Code: Select all

#define MAX_LOAD (1024*1024*100) // 100 MB
void loadAndStart(TCHAR FILE_NAME[] )
{
    void *progSpace = (void *) 0x8000; 
    printf("progSpace: $%lx:\r\n", (long unsigned )progSpace);
    FRESULT rc_rd = FR_DISK_ERR;
    FIL file_object_rd;
    rc_rd = f_open(&file_object_rd, FILE_NAME, (BYTE) FA_READ);

    if (rc_rd != FR_OK)
    {
      printf("Could not open file %s (%i) \r\n", FILE_NAME, rc_rd);
    }
    else
    {
    /*			
    FIL* fp, 	/* Pointer to the file object 
    void* buff,	/* Pointer to data buffer 
    UINT btr,	/* Number of bytes to read 
    UINT* br	/* Pointer to number of bytes read 
    */
      printf("Loading: %s \r\n", FILE_NAME);
      unsigned int fsize = MAX_LOAD;
      rc_rd = f_read(&file_object_rd, progSpace, fsize, &fsize);
      if ( rc_rd!= FR_OK)
      {
	      printf("File not loaded (size got = %i)\r\n", rc_rd);
	      f_close(&file_object_rd);
      }
      else
      {
	      f_close(&file_object_rd);
	      // file is loaded

	      printf("Starting loaded file...\r\n");

//isb() ;
//dsb();
//dmb();
mmu_disable();
mmu_enable();

//WAIT_CYCLE_NANO(1000000000);

void (*progStart)(void) = progSpace;
char *cp = (char *)(progSpace);
printf(" $%x $%x $%x $%x $%x $%x $%x $%x $%x $%x \r\n",*cp++,*cp++,*cp++,*cp++,*cp++,*cp++,*cp++,*cp++,*cp++,*cp++);
//invalidate_data_cache()	;
//invalidate_instruction_cache();
//flush_branch_target_cache();
/*
flush_branch_target_cache();
invalidate_data_cache()	;
invalidate_instruction_cache();
*/
// asm("MOV PC,#0x81d8");
 progStart();
      }
    }
}
Malban

Return to “Bare metal, Assembly language”