diff mbox series

[v6,03/17] hw/loongarch: Add slave cpu boot_code

Message ID 20240307164835.300412-4-gaosong@loongson.cn
State New
Headers show
Series Add boot LoongArch elf kernel with FDT | expand

Commit Message

gaosong March 7, 2024, 4:48 p.m. UTC
Signed-off-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240301093839.663947-4-gaosong@loongson.cn>
---
 hw/loongarch/boot.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

Comments

Bibo Mao March 8, 2024, 8:27 a.m. UTC | #1
On 2024/3/8 上午12:48, Song Gao wrote:
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> Message-Id: <20240301093839.663947-4-gaosong@loongson.cn>
> ---
>   hw/loongarch/boot.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 69 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
> index 149deb2e01..e560ac178a 100644
> --- a/hw/loongarch/boot.c
> +++ b/hw/loongarch/boot.c
> @@ -15,6 +15,54 @@
>   #include "sysemu/reset.h"
>   #include "sysemu/qtest.h"
>   
> +static const unsigned int slave_boot_code[] = {
> +                  /* Configure reset ebase.         */
> +    0x0400302c,   /* csrwr      $r12,0xc            */
> +
> +                  /* Disable interrupt.             */
> +    0x0380100c,   /* ori        $r12,$r0,0x4        */
> +    0x04000180,   /* csrxchg    $r0,$r12,0x0        */
> +
> +                  /* Clear mailbox.                 */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
> +    0x06481da0,   /* iocsrwr.d  $r0,$r13            */
> +
> +                  /* Enable IPI interrupt.          */
> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
> +    0x0400118c,   /* csrxchg    $r12,$r12,0x4       */
> +    0x02fffc0c,   /* addi.d     $r12,$r0,-1(0xfff)  */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038011ad,   /* ori        $r13,$r13,0x4       */
> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
> +
> +                  /* Wait for wakeup  <.L11>:       */
> +    0x06488000,   /* idle       0x0                 */
> +    0x03400000,   /* andi       $r0,$r0,0x0         */
> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
> +    0x43fff59f,   /* beqz       $r12,-12(0x7ffff4) # 48 <.L11> */
> +
> +                  /* Read and clear IPI interrupt.  */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038031ad,   /* ori        $r13,$r13,0xc       */
> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
> +
> +                  /* Disable  IPI interrupt.        */
> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
> +    0x04001180,   /* csrxchg    $r0,$r12,0x4        */
> +
> +                  /* Read mail buf and jump to specified entry */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
> +    0x06480dac,   /* iocsrrd.d  $r12,$r13           */
> +    0x00150181,   /* move       $r1,$r12            */
> +    0x4c000020,   /* jirl       $r0,$r1,0           */
> +};
> +
>   static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
>   {
>       return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
> @@ -111,8 +159,15 @@ static void loongarch_firmware_boot(LoongArchMachineState *lams,
>       fw_cfg_add_kernel_info(info, lams->fw_cfg);
>   }
>   
> +static void init_boot_rom(struct loongarch_boot_info *info, void *p)
> +{
> +    memcpy(p, &slave_boot_code, sizeof(slave_boot_code));
> +    p += sizeof(slave_boot_code);
> +}
> +
>   static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
>   {
> +    void  *p, *bp;
>       int64_t kernel_addr = 0;
>       LoongArchCPU *lacpu;
>       CPUState *cs;
> @@ -126,11 +181,24 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
>           }
>       }
>   
> +    /* Load 'boot_rom' at [0 - 1MiB] */
> +    p = g_malloc0(1 * MiB);
> +    bp = p;
> +    init_boot_rom(info, p);
> +    rom_add_blob_fixed("boot_rom", bp, 1 * MiB, 0);
> +
The secondary cpu waiting on the bootrom located memory address 
0x0-0x100000.

Is it possible that primary cpu clears the memory located at bootrom
and then wakeup the secondary cpu?

Regards
Bibo Mao

>       CPU_FOREACH(cs) {
>           lacpu = LOONGARCH_CPU(cs);
>           lacpu->env.load_elf = true;
> -        lacpu->env.elf_address = kernel_addr;
> +        if (cs == first_cpu) {
> +            lacpu->env.elf_address = kernel_addr;
> +        } else {
> +            lacpu->env.elf_address = 0;
> +        }
> +        lacpu->env.boot_info = info;
>       }
> +
> +    g_free(bp);
>   }
>   
>   void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
>
gaosong March 8, 2024, 9:36 a.m. UTC | #2
在 2024/3/8 16:27, maobibo 写道:
> 
> 
> On 2024/3/8 上午12:48, Song Gao wrote:
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> Message-Id: <20240301093839.663947-4-gaosong@loongson.cn>
>> ---
>>   hw/loongarch/boot.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 69 insertions(+), 1 deletion(-)
>>
>> diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
>> index 149deb2e01..e560ac178a 100644
>> --- a/hw/loongarch/boot.c
>> +++ b/hw/loongarch/boot.c
>> @@ -15,6 +15,54 @@
>>   #include "sysemu/reset.h"
>>   #include "sysemu/qtest.h"
>> +static const unsigned int slave_boot_code[] = {
>> +                  /* Configure reset ebase.         */
>> +    0x0400302c,   /* csrwr      $r12,0xc            */
>> +
>> +                  /* Disable interrupt.             */
>> +    0x0380100c,   /* ori        $r12,$r0,0x4        */
>> +    0x04000180,   /* csrxchg    $r0,$r12,0x0        */
>> +
>> +                  /* Clear mailbox.                 */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>> +    0x06481da0,   /* iocsrwr.d  $r0,$r13            */
>> +
>> +                  /* Enable IPI interrupt.          */
>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>> +    0x0400118c,   /* csrxchg    $r12,$r12,0x4       */
>> +    0x02fffc0c,   /* addi.d     $r12,$r0,-1(0xfff)  */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038011ad,   /* ori        $r13,$r13,0x4       */
>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>> +
>> +                  /* Wait for wakeup  <.L11>:       */
>> +    0x06488000,   /* idle       0x0                 */
>> +    0x03400000,   /* andi       $r0,$r0,0x0         */
>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>> +    0x43fff59f,   /* beqz       $r12,-12(0x7ffff4) # 48 <.L11> */
>> +
>> +                  /* Read and clear IPI interrupt.  */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038031ad,   /* ori        $r13,$r13,0xc       */
>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>> +
>> +                  /* Disable  IPI interrupt.        */
>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>> +    0x04001180,   /* csrxchg    $r0,$r12,0x4        */
>> +
>> +                  /* Read mail buf and jump to specified entry */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>> +    0x06480dac,   /* iocsrrd.d  $r12,$r13           */
>> +    0x00150181,   /* move       $r1,$r12            */
>> +    0x4c000020,   /* jirl       $r0,$r1,0           */
>> +};
>> +
>>   static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
>>   {
>>       return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
>> @@ -111,8 +159,15 @@ static void 
>> loongarch_firmware_boot(LoongArchMachineState *lams,
>>       fw_cfg_add_kernel_info(info, lams->fw_cfg);
>>   }
>> +static void init_boot_rom(struct loongarch_boot_info *info, void *p)
>> +{
>> +    memcpy(p, &slave_boot_code, sizeof(slave_boot_code));
>> +    p += sizeof(slave_boot_code);
>> +}
>> +
>>   static void loongarch_direct_kernel_boot(struct loongarch_boot_info 
>> *info)
>>   {
>> +    void  *p, *bp;
>>       int64_t kernel_addr = 0;
>>       LoongArchCPU *lacpu;
>>       CPUState *cs;
>> @@ -126,11 +181,24 @@ static void loongarch_direct_kernel_boot(struct 
>> loongarch_boot_info *info)
>>           }
>>       }
>> +    /* Load 'boot_rom' at [0 - 1MiB] */
>> +    p = g_malloc0(1 * MiB);
>> +    bp = p;
>> +    init_boot_rom(info, p);
>> +    rom_add_blob_fixed("boot_rom", bp, 1 * MiB, 0);
>> +
> The secondary cpu waiting on the bootrom located memory address 
> 0x0-0x100000.
> 
> Is it possible that primary cpu clears the memory located at bootrom
> and then wakeup the secondary cpu?
> 
I think it impossible,0-1M is ROM。

Thanks.
Song Gao
> Regards
> Bibo Mao
> 
>>       CPU_FOREACH(cs) {
>>           lacpu = LOONGARCH_CPU(cs);
>>           lacpu->env.load_elf = true;
>> -        lacpu->env.elf_address = kernel_addr;
>> +        if (cs == first_cpu) {
>> +            lacpu->env.elf_address = kernel_addr;
>> +        } else {
>> +            lacpu->env.elf_address = 0;
>> +        }
>> +        lacpu->env.boot_info = info;
>>       }
>> +
>> +    g_free(bp);
>>   }
>>   void loongarch_load_kernel(MachineState *ms, struct 
>> loongarch_boot_info *info)
>>
Bibo Mao March 11, 2024, 6:50 a.m. UTC | #3
On 2024/3/8 下午5:36, gaosong wrote:
> 
> 
> 在 2024/3/8 16:27, maobibo 写道:
>>
>>
>> On 2024/3/8 上午12:48, Song Gao wrote:
>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>> Message-Id: <20240301093839.663947-4-gaosong@loongson.cn>
>>> ---
>>>   hw/loongarch/boot.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-
>>>   1 file changed, 69 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
>>> index 149deb2e01..e560ac178a 100644
>>> --- a/hw/loongarch/boot.c
>>> +++ b/hw/loongarch/boot.c
>>> @@ -15,6 +15,54 @@
>>>   #include "sysemu/reset.h"
>>>   #include "sysemu/qtest.h"
>>> +static const unsigned int slave_boot_code[] = {
>>> +                  /* Configure reset ebase.         */
>>> +    0x0400302c,   /* csrwr      $r12,0xc            */
>>> +
>>> +                  /* Disable interrupt.             */
>>> +    0x0380100c,   /* ori        $r12,$r0,0x4        */
>>> +    0x04000180,   /* csrxchg    $r0,$r12,0x0        */
>>> +
>>> +                  /* Clear mailbox.                 */
>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>>> +    0x06481da0,   /* iocsrwr.d  $r0,$r13            */
>>> +
>>> +                  /* Enable IPI interrupt.          */
>>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>>> +    0x0400118c,   /* csrxchg    $r12,$r12,0x4       */
>>> +    0x02fffc0c,   /* addi.d     $r12,$r0,-1(0xfff)  */
>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>> +    0x038011ad,   /* ori        $r13,$r13,0x4       */
>>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>>> +
>>> +                  /* Wait for wakeup  <.L11>:       */
>>> +    0x06488000,   /* idle       0x0                 */
>>> +    0x03400000,   /* andi       $r0,$r0,0x0         */
>>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>>> +    0x43fff59f,   /* beqz       $r12,-12(0x7ffff4) # 48 <.L11> */
>>> +
>>> +                  /* Read and clear IPI interrupt.  */
>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>> +    0x038031ad,   /* ori        $r13,$r13,0xc       */
>>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>>> +
>>> +                  /* Disable  IPI interrupt.        */
>>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>>> +    0x04001180,   /* csrxchg    $r0,$r12,0x4        */
>>> +
>>> +                  /* Read mail buf and jump to specified entry */
>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>>> +    0x06480dac,   /* iocsrrd.d  $r12,$r13           */
>>> +    0x00150181,   /* move       $r1,$r12            */
>>> +    0x4c000020,   /* jirl       $r0,$r1,0           */
>>> +};
>>> +
>>>   static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t 
>>> addr)
>>>   {
>>>       return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
>>> @@ -111,8 +159,15 @@ static void 
>>> loongarch_firmware_boot(LoongArchMachineState *lams,
>>>       fw_cfg_add_kernel_info(info, lams->fw_cfg);
>>>   }
>>> +static void init_boot_rom(struct loongarch_boot_info *info, void *p)
>>> +{
>>> +    memcpy(p, &slave_boot_code, sizeof(slave_boot_code));
>>> +    p += sizeof(slave_boot_code);
>>> +}
>>> +
>>>   static void loongarch_direct_kernel_boot(struct loongarch_boot_info 
>>> *info)
>>>   {
>>> +    void  *p, *bp;
>>>       int64_t kernel_addr = 0;
>>>       LoongArchCPU *lacpu;
>>>       CPUState *cs;
>>> @@ -126,11 +181,24 @@ static void loongarch_direct_kernel_boot(struct 
>>> loongarch_boot_info *info)
>>>           }
>>>       }
>>> +    /* Load 'boot_rom' at [0 - 1MiB] */
>>> +    p = g_malloc0(1 * MiB);
>>> +    bp = p;
>>> +    init_boot_rom(info, p);
>>> +    rom_add_blob_fixed("boot_rom", bp, 1 * MiB, 0);
>>> +
>> The secondary cpu waiting on the bootrom located memory address 
>> 0x0-0x100000.
>>
>> Is it possible that primary cpu clears the memory located at bootrom
>> and then wakeup the secondary cpu?
>>
> I think it impossible,0-1M is ROM。
I am not sure whether it is ok if area between 0-1M is ROM.

For the memory map table, low memory area (0 - 256M) is still ddr ram.
And it is passed to kernel with fdt system table, rather than 
area(1-256M). Is that right?

There are some lines like this:
     /* Node0 memory */
     memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);

Regards
Bibo Mao

> 
> Thanks.
> Song Gao
>> Regards
>> Bibo Mao
>>
>>>       CPU_FOREACH(cs) {
>>>           lacpu = LOONGARCH_CPU(cs);
>>>           lacpu->env.load_elf = true;
>>> -        lacpu->env.elf_address = kernel_addr;
>>> +        if (cs == first_cpu) {
>>> +            lacpu->env.elf_address = kernel_addr;
>>> +        } else {
>>> +            lacpu->env.elf_address = 0;
>>> +        }
>>> +        lacpu->env.boot_info = info;
>>>       }
>>> +
>>> +    g_free(bp);
>>>   }
>>>   void loongarch_load_kernel(MachineState *ms, struct 
>>> loongarch_boot_info *info)
>>>
Bibo Mao March 14, 2024, 1:31 a.m. UTC | #4
On 2024/3/11 下午2:50, maobibo wrote:
> 
> 
> On 2024/3/8 下午5:36, gaosong wrote:
>>
>>
>> 在 2024/3/8 16:27, maobibo 写道:
>>>
>>>
>>> On 2024/3/8 上午12:48, Song Gao wrote:
>>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>>> Message-Id: <20240301093839.663947-4-gaosong@loongson.cn>
>>>> ---
>>>>   hw/loongarch/boot.c | 70 
>>>> ++++++++++++++++++++++++++++++++++++++++++++-
>>>>   1 file changed, 69 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
>>>> index 149deb2e01..e560ac178a 100644
>>>> --- a/hw/loongarch/boot.c
>>>> +++ b/hw/loongarch/boot.c
>>>> @@ -15,6 +15,54 @@
>>>>   #include "sysemu/reset.h"
>>>>   #include "sysemu/qtest.h"
>>>> +static const unsigned int slave_boot_code[] = {
>>>> +                  /* Configure reset ebase.         */
>>>> +    0x0400302c,   /* csrwr      $r12,0xc            */
>>>> +
>>>> +                  /* Disable interrupt.             */
>>>> +    0x0380100c,   /* ori        $r12,$r0,0x4        */
>>>> +    0x04000180,   /* csrxchg    $r0,$r12,0x0        */
>>>> +
>>>> +                  /* Clear mailbox.                 */
>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>>>> +    0x06481da0,   /* iocsrwr.d  $r0,$r13            */
>>>> +
>>>> +                  /* Enable IPI interrupt.          */
>>>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>>>> +    0x0400118c,   /* csrxchg    $r12,$r12,0x4       */
>>>> +    0x02fffc0c,   /* addi.d     $r12,$r0,-1(0xfff)  */
>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>> +    0x038011ad,   /* ori        $r13,$r13,0x4       */
>>>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>>>> +
>>>> +                  /* Wait for wakeup  <.L11>:       */
>>>> +    0x06488000,   /* idle       0x0                 */
>>>> +    0x03400000,   /* andi       $r0,$r0,0x0         */
>>>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>>>> +    0x43fff59f,   /* beqz       $r12,-12(0x7ffff4) # 48 <.L11> */
>>>> +
>>>> +                  /* Read and clear IPI interrupt.  */
>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>> +    0x038031ad,   /* ori        $r13,$r13,0xc       */
>>>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>>>> +
>>>> +                  /* Disable  IPI interrupt.        */
>>>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>>>> +    0x04001180,   /* csrxchg    $r0,$r12,0x4        */
>>>> +
>>>> +                  /* Read mail buf and jump to specified entry */
>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>>>> +    0x06480dac,   /* iocsrrd.d  $r12,$r13           */
>>>> +    0x00150181,   /* move       $r1,$r12            */
>>>> +    0x4c000020,   /* jirl       $r0,$r1,0           */
>>>> +};
>>>> +
>>>>   static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t 
>>>> addr)
>>>>   {
>>>>       return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
>>>> @@ -111,8 +159,15 @@ static void 
>>>> loongarch_firmware_boot(LoongArchMachineState *lams,
>>>>       fw_cfg_add_kernel_info(info, lams->fw_cfg);
>>>>   }
>>>> +static void init_boot_rom(struct loongarch_boot_info *info, void *p)
>>>> +{
>>>> +    memcpy(p, &slave_boot_code, sizeof(slave_boot_code));
>>>> +    p += sizeof(slave_boot_code);
>>>> +}
>>>> +
>>>>   static void loongarch_direct_kernel_boot(struct 
>>>> loongarch_boot_info *info)
>>>>   {
>>>> +    void  *p, *bp;
>>>>       int64_t kernel_addr = 0;
>>>>       LoongArchCPU *lacpu;
>>>>       CPUState *cs;
>>>> @@ -126,11 +181,24 @@ static void 
>>>> loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
>>>>           }
>>>>       }
>>>> +    /* Load 'boot_rom' at [0 - 1MiB] */
>>>> +    p = g_malloc0(1 * MiB);
>>>> +    bp = p;
>>>> +    init_boot_rom(info, p);
>>>> +    rom_add_blob_fixed("boot_rom", bp, 1 * MiB, 0);
>>>> +
>>> The secondary cpu waiting on the bootrom located memory address 
>>> 0x0-0x100000.
>>>
>>> Is it possible that primary cpu clears the memory located at bootrom
>>> and then wakeup the secondary cpu?
>>>
>> I think it impossible,0-1M is ROM。
> I am not sure whether it is ok if area between 0-1M is ROM.
> 
> For the memory map table, low memory area (0 - 256M) is still ddr ram.
> And it is passed to kernel with fdt system table, rather than 
> area(1-256M). Is that right?
> 
> There are some lines like this:
>      /* Node0 memory */
>      memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
Song,

Can the base memory address of bootrom for secondary cpus be set as base 
address of flash like bios, such as VIRT_FLASH0_BASE/VIRT_FLASH1_BASE?

And ddr memory map area is kept unchanged.

Regards
Bibo Mao

> 
> Regards
> Bibo Mao
> 
>>
>> Thanks.
>> Song Gao
>>> Regards
>>> Bibo Mao
>>>
>>>>       CPU_FOREACH(cs) {
>>>>           lacpu = LOONGARCH_CPU(cs);
>>>>           lacpu->env.load_elf = true;
>>>> -        lacpu->env.elf_address = kernel_addr;
>>>> +        if (cs == first_cpu) {
>>>> +            lacpu->env.elf_address = kernel_addr;
>>>> +        } else {
>>>> +            lacpu->env.elf_address = 0;
>>>> +        }
>>>> +        lacpu->env.boot_info = info;
>>>>       }
>>>> +
>>>> +    g_free(bp);
>>>>   }
>>>>   void loongarch_load_kernel(MachineState *ms, struct 
>>>> loongarch_boot_info *info)
>>>>
>
chen huacai March 14, 2024, 2:28 a.m. UTC | #5
Song,

On Fri, Mar 8, 2024 at 12:51 AM Song Gao <gaosong@loongson.cn> wrote:
>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> Message-Id: <20240301093839.663947-4-gaosong@loongson.cn>
> ---
>  hw/loongarch/boot.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 69 insertions(+), 1 deletion(-)
>
> diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
> index 149deb2e01..e560ac178a 100644
> --- a/hw/loongarch/boot.c
> +++ b/hw/loongarch/boot.c
> @@ -15,6 +15,54 @@
>  #include "sysemu/reset.h"
>  #include "sysemu/qtest.h"
>
> +static const unsigned int slave_boot_code[] = {
> +                  /* Configure reset ebase.         */
> +    0x0400302c,   /* csrwr      $r12,0xc            */
Use reg-names may be a little better than reg-nums.

Huacai

> +
> +                  /* Disable interrupt.             */
> +    0x0380100c,   /* ori        $r12,$r0,0x4        */
> +    0x04000180,   /* csrxchg    $r0,$r12,0x0        */
> +
> +                  /* Clear mailbox.                 */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
> +    0x06481da0,   /* iocsrwr.d  $r0,$r13            */
> +
> +                  /* Enable IPI interrupt.          */
> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
> +    0x0400118c,   /* csrxchg    $r12,$r12,0x4       */
> +    0x02fffc0c,   /* addi.d     $r12,$r0,-1(0xfff)  */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038011ad,   /* ori        $r13,$r13,0x4       */
> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
> +
> +                  /* Wait for wakeup  <.L11>:       */
> +    0x06488000,   /* idle       0x0                 */
> +    0x03400000,   /* andi       $r0,$r0,0x0         */
> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
> +    0x43fff59f,   /* beqz       $r12,-12(0x7ffff4) # 48 <.L11> */
> +
> +                  /* Read and clear IPI interrupt.  */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038031ad,   /* ori        $r13,$r13,0xc       */
> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
> +
> +                  /* Disable  IPI interrupt.        */
> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
> +    0x04001180,   /* csrxchg    $r0,$r12,0x4        */
> +
> +                  /* Read mail buf and jump to specified entry */
> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
> +    0x06480dac,   /* iocsrrd.d  $r12,$r13           */
> +    0x00150181,   /* move       $r1,$r12            */
> +    0x4c000020,   /* jirl       $r0,$r1,0           */
> +};
> +
>  static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
>  {
>      return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
> @@ -111,8 +159,15 @@ static void loongarch_firmware_boot(LoongArchMachineState *lams,
>      fw_cfg_add_kernel_info(info, lams->fw_cfg);
>  }
>
> +static void init_boot_rom(struct loongarch_boot_info *info, void *p)
> +{
> +    memcpy(p, &slave_boot_code, sizeof(slave_boot_code));
> +    p += sizeof(slave_boot_code);
> +}
> +
>  static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
>  {
> +    void  *p, *bp;
>      int64_t kernel_addr = 0;
>      LoongArchCPU *lacpu;
>      CPUState *cs;
> @@ -126,11 +181,24 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
>          }
>      }
>
> +    /* Load 'boot_rom' at [0 - 1MiB] */
> +    p = g_malloc0(1 * MiB);
> +    bp = p;
> +    init_boot_rom(info, p);
> +    rom_add_blob_fixed("boot_rom", bp, 1 * MiB, 0);
> +
>      CPU_FOREACH(cs) {
>          lacpu = LOONGARCH_CPU(cs);
>          lacpu->env.load_elf = true;
> -        lacpu->env.elf_address = kernel_addr;
> +        if (cs == first_cpu) {
> +            lacpu->env.elf_address = kernel_addr;
> +        } else {
> +            lacpu->env.elf_address = 0;
> +        }
> +        lacpu->env.boot_info = info;
>      }
> +
> +    g_free(bp);
>  }
>
>  void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
> --
> 2.34.1
>
>
gaosong March 14, 2024, 9:03 a.m. UTC | #6
在 2024/3/14 9:31, maobibo 写道:
> 
> 
> On 2024/3/11 下午2:50, maobibo wrote:
>>
>>
>> On 2024/3/8 下午5:36, gaosong wrote:
>>>
>>>
>>> 在 2024/3/8 16:27, maobibo 写道:
>>>>
>>>>
>>>> On 2024/3/8 上午12:48, Song Gao wrote:
>>>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>>>> Message-Id: <20240301093839.663947-4-gaosong@loongson.cn>
>>>>> ---
>>>>>   hw/loongarch/boot.c | 70 
>>>>> ++++++++++++++++++++++++++++++++++++++++++++-
>>>>>   1 file changed, 69 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
>>>>> index 149deb2e01..e560ac178a 100644
>>>>> --- a/hw/loongarch/boot.c
>>>>> +++ b/hw/loongarch/boot.c
>>>>> @@ -15,6 +15,54 @@
>>>>>   #include "sysemu/reset.h"
>>>>>   #include "sysemu/qtest.h"
>>>>> +static const unsigned int slave_boot_code[] = {
>>>>> +                  /* Configure reset ebase.         */
>>>>> +    0x0400302c,   /* csrwr      $r12,0xc            */
>>>>> +
>>>>> +                  /* Disable interrupt.             */
>>>>> +    0x0380100c,   /* ori        $r12,$r0,0x4        */
>>>>> +    0x04000180,   /* csrxchg    $r0,$r12,0x0        */
>>>>> +
>>>>> +                  /* Clear mailbox.                 */
>>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>>>>> +    0x06481da0,   /* iocsrwr.d  $r0,$r13            */
>>>>> +
>>>>> +                  /* Enable IPI interrupt.          */
>>>>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>>>>> +    0x0400118c,   /* csrxchg    $r12,$r12,0x4       */
>>>>> +    0x02fffc0c,   /* addi.d     $r12,$r0,-1(0xfff)  */
>>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>>> +    0x038011ad,   /* ori        $r13,$r13,0x4       */
>>>>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>>>>> +
>>>>> +                  /* Wait for wakeup  <.L11>:       */
>>>>> +    0x06488000,   /* idle       0x0                 */
>>>>> +    0x03400000,   /* andi       $r0,$r0,0x0         */
>>>>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>>>>> +    0x43fff59f,   /* beqz       $r12,-12(0x7ffff4) # 48 <.L11> */
>>>>> +
>>>>> +                  /* Read and clear IPI interrupt.  */
>>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>>> +    0x038031ad,   /* ori        $r13,$r13,0xc       */
>>>>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>>>>> +
>>>>> +                  /* Disable  IPI interrupt.        */
>>>>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>>>>> +    0x04001180,   /* csrxchg    $r0,$r12,0x4        */
>>>>> +
>>>>> +                  /* Read mail buf and jump to specified entry */
>>>>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>>>>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>>>>> +    0x06480dac,   /* iocsrrd.d  $r12,$r13           */
>>>>> +    0x00150181,   /* move       $r1,$r12            */
>>>>> +    0x4c000020,   /* jirl       $r0,$r1,0           */
>>>>> +};
>>>>> +
>>>>>   static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t 
>>>>> addr)
>>>>>   {
>>>>>       return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
>>>>> @@ -111,8 +159,15 @@ static void 
>>>>> loongarch_firmware_boot(LoongArchMachineState *lams,
>>>>>       fw_cfg_add_kernel_info(info, lams->fw_cfg);
>>>>>   }
>>>>> +static void init_boot_rom(struct loongarch_boot_info *info, void *p)
>>>>> +{
>>>>> +    memcpy(p, &slave_boot_code, sizeof(slave_boot_code));
>>>>> +    p += sizeof(slave_boot_code);
>>>>> +}
>>>>> +
>>>>>   static void loongarch_direct_kernel_boot(struct 
>>>>> loongarch_boot_info *info)
>>>>>   {
>>>>> +    void  *p, *bp;
>>>>>       int64_t kernel_addr = 0;
>>>>>       LoongArchCPU *lacpu;
>>>>>       CPUState *cs;
>>>>> @@ -126,11 +181,24 @@ static void 
>>>>> loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
>>>>>           }
>>>>>       }
>>>>> +    /* Load 'boot_rom' at [0 - 1MiB] */
>>>>> +    p = g_malloc0(1 * MiB);
>>>>> +    bp = p;
>>>>> +    init_boot_rom(info, p);
>>>>> +    rom_add_blob_fixed("boot_rom", bp, 1 * MiB, 0);
>>>>> +
>>>> The secondary cpu waiting on the bootrom located memory address 
>>>> 0x0-0x100000.
>>>>
>>>> Is it possible that primary cpu clears the memory located at bootrom
>>>> and then wakeup the secondary cpu?
>>>>
>>> I think it impossible,0-1M is ROM。
>> I am not sure whether it is ok if area between 0-1M is ROM.
>>
>> For the memory map table, low memory area (0 - 256M) is still ddr ram.
>> And it is passed to kernel with fdt system table, rather than 
>> area(1-256M). Is that right?
>>
>> There are some lines like this:
>>      /* Node0 memory */
>>      memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
> Song,
> 
> Can the base memory address of bootrom for secondary cpus be set as base 
> address of flash like bios, such as VIRT_FLASH0_BASE/VIRT_FLASH1_BASE?
>  > And ddr memory map area is kept unchanged.
>
Good suggestions, I wil do this on v7.

Thanks.
Song Gao

> Regards
> Bibo Mao
> 
>>
>> Regards
>> Bibo Mao
>>
>>>
>>> Thanks.
>>> Song Gao
>>>> Regards
>>>> Bibo Mao
>>>>
>>>>>       CPU_FOREACH(cs) {
>>>>>           lacpu = LOONGARCH_CPU(cs);
>>>>>           lacpu->env.load_elf = true;
>>>>> -        lacpu->env.elf_address = kernel_addr;
>>>>> +        if (cs == first_cpu) {
>>>>> +            lacpu->env.elf_address = kernel_addr;
>>>>> +        } else {
>>>>> +            lacpu->env.elf_address = 0;
>>>>> +        }
>>>>> +        lacpu->env.boot_info = info;
>>>>>       }
>>>>> +
>>>>> +    g_free(bp);
>>>>>   }
>>>>>   void loongarch_load_kernel(MachineState *ms, struct 
>>>>> loongarch_boot_info *info)
>>>>>
>>
gaosong March 14, 2024, 9:04 a.m. UTC | #7
在 2024/3/14 10:28, chen huacai 写道:
> Song,
> 
> On Fri, Mar 8, 2024 at 12:51 AM Song Gao <gaosong@loongson.cn> wrote:
>>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> Message-Id: <20240301093839.663947-4-gaosong@loongson.cn>
>> ---
>>   hw/loongarch/boot.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 69 insertions(+), 1 deletion(-)
>>
>> diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
>> index 149deb2e01..e560ac178a 100644
>> --- a/hw/loongarch/boot.c
>> +++ b/hw/loongarch/boot.c
>> @@ -15,6 +15,54 @@
>>   #include "sysemu/reset.h"
>>   #include "sysemu/qtest.h"
>>
>> +static const unsigned int slave_boot_code[] = {
>> +                  /* Configure reset ebase.         */
>> +    0x0400302c,   /* csrwr      $r12,0xc            */
> Use reg-names may be a little better than reg-nums.
> 
Got it.

Thanks.
Song Gao

> Huacai
> 
>> +
>> +                  /* Disable interrupt.             */
>> +    0x0380100c,   /* ori        $r12,$r0,0x4        */
>> +    0x04000180,   /* csrxchg    $r0,$r12,0x0        */
>> +
>> +                  /* Clear mailbox.                 */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>> +    0x06481da0,   /* iocsrwr.d  $r0,$r13            */
>> +
>> +                  /* Enable IPI interrupt.          */
>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>> +    0x0400118c,   /* csrxchg    $r12,$r12,0x4       */
>> +    0x02fffc0c,   /* addi.d     $r12,$r0,-1(0xfff)  */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038011ad,   /* ori        $r13,$r13,0x4       */
>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>> +
>> +                  /* Wait for wakeup  <.L11>:       */
>> +    0x06488000,   /* idle       0x0                 */
>> +    0x03400000,   /* andi       $r0,$r0,0x0         */
>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>> +    0x43fff59f,   /* beqz       $r12,-12(0x7ffff4) # 48 <.L11> */
>> +
>> +                  /* Read and clear IPI interrupt.  */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038031ad,   /* ori        $r13,$r13,0xc       */
>> +    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
>> +
>> +                  /* Disable  IPI interrupt.        */
>> +    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
>> +    0x04001180,   /* csrxchg    $r0,$r12,0x4        */
>> +
>> +                  /* Read mail buf and jump to specified entry */
>> +    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
>> +    0x038081ad,   /* ori        $r13,$r13,0x20      */
>> +    0x06480dac,   /* iocsrrd.d  $r12,$r13           */
>> +    0x00150181,   /* move       $r1,$r12            */
>> +    0x4c000020,   /* jirl       $r0,$r1,0           */
>> +};
>> +
>>   static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
>>   {
>>       return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
>> @@ -111,8 +159,15 @@ static void loongarch_firmware_boot(LoongArchMachineState *lams,
>>       fw_cfg_add_kernel_info(info, lams->fw_cfg);
>>   }
>>
>> +static void init_boot_rom(struct loongarch_boot_info *info, void *p)
>> +{
>> +    memcpy(p, &slave_boot_code, sizeof(slave_boot_code));
>> +    p += sizeof(slave_boot_code);
>> +}
>> +
>>   static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
>>   {
>> +    void  *p, *bp;
>>       int64_t kernel_addr = 0;
>>       LoongArchCPU *lacpu;
>>       CPUState *cs;
>> @@ -126,11 +181,24 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
>>           }
>>       }
>>
>> +    /* Load 'boot_rom' at [0 - 1MiB] */
>> +    p = g_malloc0(1 * MiB);
>> +    bp = p;
>> +    init_boot_rom(info, p);
>> +    rom_add_blob_fixed("boot_rom", bp, 1 * MiB, 0);
>> +
>>       CPU_FOREACH(cs) {
>>           lacpu = LOONGARCH_CPU(cs);
>>           lacpu->env.load_elf = true;
>> -        lacpu->env.elf_address = kernel_addr;
>> +        if (cs == first_cpu) {
>> +            lacpu->env.elf_address = kernel_addr;
>> +        } else {
>> +            lacpu->env.elf_address = 0;
>> +        }
>> +        lacpu->env.boot_info = info;
>>       }
>> +
>> +    g_free(bp);
>>   }
>>
>>   void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
>> --
>> 2.34.1
>>
>>
> 
>
diff mbox series

Patch

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 149deb2e01..e560ac178a 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,54 @@ 
 #include "sysemu/reset.h"
 #include "sysemu/qtest.h"
 
+static const unsigned int slave_boot_code[] = {
+                  /* Configure reset ebase.         */
+    0x0400302c,   /* csrwr      $r12,0xc            */
+
+                  /* Disable interrupt.             */
+    0x0380100c,   /* ori        $r12,$r0,0x4        */
+    0x04000180,   /* csrxchg    $r0,$r12,0x0        */
+
+                  /* Clear mailbox.                 */
+    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
+    0x038081ad,   /* ori        $r13,$r13,0x20      */
+    0x06481da0,   /* iocsrwr.d  $r0,$r13            */
+
+                  /* Enable IPI interrupt.          */
+    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
+    0x0400118c,   /* csrxchg    $r12,$r12,0x4       */
+    0x02fffc0c,   /* addi.d     $r12,$r0,-1(0xfff)  */
+    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
+    0x038011ad,   /* ori        $r13,$r13,0x4       */
+    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
+    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
+    0x038081ad,   /* ori        $r13,$r13,0x20      */
+
+                  /* Wait for wakeup  <.L11>:       */
+    0x06488000,   /* idle       0x0                 */
+    0x03400000,   /* andi       $r0,$r0,0x0         */
+    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
+    0x43fff59f,   /* beqz       $r12,-12(0x7ffff4) # 48 <.L11> */
+
+                  /* Read and clear IPI interrupt.  */
+    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
+    0x064809ac,   /* iocsrrd.w  $r12,$r13           */
+    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
+    0x038031ad,   /* ori        $r13,$r13,0xc       */
+    0x064819ac,   /* iocsrwr.w  $r12,$r13           */
+
+                  /* Disable  IPI interrupt.        */
+    0x1400002c,   /* lu12i.w    $r12,1(0x1)         */
+    0x04001180,   /* csrxchg    $r0,$r12,0x4        */
+
+                  /* Read mail buf and jump to specified entry */
+    0x1400002d,   /* lu12i.w    $r13,1(0x1)         */
+    0x038081ad,   /* ori        $r13,$r13,0x20      */
+    0x06480dac,   /* iocsrrd.d  $r12,$r13           */
+    0x00150181,   /* move       $r1,$r12            */
+    0x4c000020,   /* jirl       $r0,$r1,0           */
+};
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
     return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -111,8 +159,15 @@  static void loongarch_firmware_boot(LoongArchMachineState *lams,
     fw_cfg_add_kernel_info(info, lams->fw_cfg);
 }
 
+static void init_boot_rom(struct loongarch_boot_info *info, void *p)
+{
+    memcpy(p, &slave_boot_code, sizeof(slave_boot_code));
+    p += sizeof(slave_boot_code);
+}
+
 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
 {
+    void  *p, *bp;
     int64_t kernel_addr = 0;
     LoongArchCPU *lacpu;
     CPUState *cs;
@@ -126,11 +181,24 @@  static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
         }
     }
 
+    /* Load 'boot_rom' at [0 - 1MiB] */
+    p = g_malloc0(1 * MiB);
+    bp = p;
+    init_boot_rom(info, p);
+    rom_add_blob_fixed("boot_rom", bp, 1 * MiB, 0);
+
     CPU_FOREACH(cs) {
         lacpu = LOONGARCH_CPU(cs);
         lacpu->env.load_elf = true;
-        lacpu->env.elf_address = kernel_addr;
+        if (cs == first_cpu) {
+            lacpu->env.elf_address = kernel_addr;
+        } else {
+            lacpu->env.elf_address = 0;
+        }
+        lacpu->env.boot_info = info;
     }
+
+    g_free(bp);
 }
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)