diff mbox series

[v1,5/5] xen/riscv: map FDT

Message ID 7e492df051c949744755a221c0448c740d2c681b.1720002425.git.oleksii.kurochko@gmail.com (mailing list archive)
State Superseded
Headers show
Series RISCV device tree mapping | expand

Commit Message

Oleksii Kurochko July 3, 2024, 10:42 a.m. UTC
Except mapping of FDT, it is also printing command line passed by
a DTB and initialize bootinfo from a DTB.

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
 xen/arch/riscv/riscv64/head.S |  3 +++
 xen/arch/riscv/setup.c        | 21 +++++++++++++++++++++
 2 files changed, 24 insertions(+)

Comments

Jan Beulich July 10, 2024, 12:38 p.m. UTC | #1
On 03.07.2024 12:42, Oleksii Kurochko wrote:
> Except mapping of FDT, it is also printing command line passed by
> a DTB and initialize bootinfo from a DTB.

I'm glad the description isn't empty here. However, ...

> --- a/xen/arch/riscv/riscv64/head.S
> +++ b/xen/arch/riscv/riscv64/head.S
> @@ -41,6 +41,9 @@ FUNC(start)
>  
>          jal     setup_initial_pagetables
>  
> +        mv      a0, s1
> +        jal     fdt_map
> +
>          /* Calculate proper VA after jump from 1:1 mapping */
>          la      a0, .L_primary_switched
>          sub     a0, a0, s2

... it could do with clarifying why this needs calling from assembly
code. Mapping the FDT clearly looks like something that wants doing
from start_xen(), i.e. from C code.

> @@ -33,15 +35,34 @@ static void test_macros_from_bug_h(void)
>      printk("WARN is most likely working\n");
>  }
>  
> +void __init fdt_map(paddr_t dtb_addr)
> +{
> +    device_tree_flattened = early_fdt_map(dtb_addr);
> +    if ( !device_tree_flattened )
> +    {
> +        printk("wrong FDT\n");
> +        die();
> +    }
> +}
> +
>  void __init noreturn start_xen(unsigned long bootcpu_id,
>                                 paddr_t dtb_addr)
>  {
> +    size_t fdt_size;
> +    const char *cmdline;
> +
>      remove_identity_mapping();
>  
>      trap_init();
>  
>      test_macros_from_bug_h();
>  
> +    fdt_size = boot_fdt_info(device_tree_flattened, dtb_addr);

You don't use the return value anywhere below. What use is the local var
then?

Jan

> +    cmdline = boot_fdt_cmdline(device_tree_flattened);
> +    printk("Command line: %s\n", cmdline);
> +    cmdline_parse(cmdline);
> +
>      printk("All set up\n");
>  
>      for ( ;; )
Oleksii Kurochko July 11, 2024, 9:40 a.m. UTC | #2
On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
> On 03.07.2024 12:42, Oleksii Kurochko wrote:
> > Except mapping of FDT, it is also printing command line passed by
> > a DTB and initialize bootinfo from a DTB.
> 
> I'm glad the description isn't empty here. However, ...
> 
> > --- a/xen/arch/riscv/riscv64/head.S
> > +++ b/xen/arch/riscv/riscv64/head.S
> > @@ -41,6 +41,9 @@ FUNC(start)
> >  
> >          jal     setup_initial_pagetables
> >  
> > +        mv      a0, s1
> > +        jal     fdt_map
> > +
> >          /* Calculate proper VA after jump from 1:1 mapping */
> >          la      a0, .L_primary_switched
> >          sub     a0, a0, s2
> 
> ... it could do with clarifying why this needs calling from assembly
> code. Mapping the FDT clearly looks like something that wants doing
> from start_xen(), i.e. from C code.
fdt_map() expected to work while MMU is off as it is using
setup_initial_mapping() which is working with physical address.

> 
> > @@ -33,15 +35,34 @@ static void test_macros_from_bug_h(void)
> >      printk("WARN is most likely working\n");
> >  }
> >  
> > +void __init fdt_map(paddr_t dtb_addr)
> > +{
> > +    device_tree_flattened = early_fdt_map(dtb_addr);
> > +    if ( !device_tree_flattened )
> > +    {
> > +        printk("wrong FDT\n");
> > +        die();
> > +    }
> > +}
> > +
> >  void __init noreturn start_xen(unsigned long bootcpu_id,
> >                                 paddr_t dtb_addr)
> >  {
> > +    size_t fdt_size;
> > +    const char *cmdline;
> > +
> >      remove_identity_mapping();
> >  
> >      trap_init();
> >  
> >      test_macros_from_bug_h();
> >  
> > +    fdt_size = boot_fdt_info(device_tree_flattened, dtb_addr);
> 
> You don't use the return value anywhere below. What use is the local
> var
> then?
I returned just for debug ( to see what is the fdt size ), it can be
dropped now.

~ Oleksii

> 
> Jan
> 
> > +    cmdline = boot_fdt_cmdline(device_tree_flattened);
> > +    printk("Command line: %s\n", cmdline);
> > +    cmdline_parse(cmdline);
> > +
> >      printk("All set up\n");
> >  
> >      for ( ;; )
>
Jan Beulich July 11, 2024, 9:54 a.m. UTC | #3
On 11.07.2024 11:40, Oleksii wrote:
> On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
>> On 03.07.2024 12:42, Oleksii Kurochko wrote:
>>> Except mapping of FDT, it is also printing command line passed by
>>> a DTB and initialize bootinfo from a DTB.
>>
>> I'm glad the description isn't empty here. However, ...
>>
>>> --- a/xen/arch/riscv/riscv64/head.S
>>> +++ b/xen/arch/riscv/riscv64/head.S
>>> @@ -41,6 +41,9 @@ FUNC(start)
>>>  
>>>          jal     setup_initial_pagetables
>>>  
>>> +        mv      a0, s1
>>> +        jal     fdt_map
>>> +
>>>          /* Calculate proper VA after jump from 1:1 mapping */
>>>          la      a0, .L_primary_switched
>>>          sub     a0, a0, s2
>>
>> ... it could do with clarifying why this needs calling from assembly
>> code. Mapping the FDT clearly looks like something that wants doing
>> from start_xen(), i.e. from C code.
> fdt_map() expected to work while MMU is off as it is using
> setup_initial_mapping() which is working with physical address.

Hmm, interesting. When the MMU is off, what does "map" mean? Yet then
it feels I'm misunderstanding what you're meaning to tell me ...

Jan
Oleksii Kurochko July 11, 2024, 10:26 a.m. UTC | #4
On Thu, 2024-07-11 at 11:54 +0200, Jan Beulich wrote:
> On 11.07.2024 11:40, Oleksii wrote:
> > On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
> > > On 03.07.2024 12:42, Oleksii Kurochko wrote:
> > > > Except mapping of FDT, it is also printing command line passed
> > > > by
> > > > a DTB and initialize bootinfo from a DTB.
> > > 
> > > I'm glad the description isn't empty here. However, ...
> > > 
> > > > --- a/xen/arch/riscv/riscv64/head.S
> > > > +++ b/xen/arch/riscv/riscv64/head.S
> > > > @@ -41,6 +41,9 @@ FUNC(start)
> > > >  
> > > >          jal     setup_initial_pagetables
> > > >  
> > > > +        mv      a0, s1
> > > > +        jal     fdt_map
> > > > +
> > > >          /* Calculate proper VA after jump from 1:1 mapping */
> > > >          la      a0, .L_primary_switched
> > > >          sub     a0, a0, s2
> > > 
> > > ... it could do with clarifying why this needs calling from
> > > assembly
> > > code. Mapping the FDT clearly looks like something that wants
> > > doing
> > > from start_xen(), i.e. from C code.
> > fdt_map() expected to work while MMU is off as it is using
> > setup_initial_mapping() which is working with physical address.
> 
> Hmm, interesting. When the MMU is off, what does "map" mean? Yet then
> it feels I'm misunderstanding what you're meaning to tell me ...
Let's look at examples of the code:
1. The first thing issue will be here:
   void* __init early_fdt_map(paddr_t fdt_paddr)
   {
       unsigned long dt_phys_base = fdt_paddr;
       unsigned long dt_virt_base;
       unsigned long dt_virt_size;
   
       BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
       if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN || fdt_paddr % SZ_2M 
   ||
             fdt_totalsize(fdt_paddr) > BOOT_FDT_VIRT_SIZE )
MMU doesn't now about virtual address of fdt_paddr as fdt_paddr wasn't
mapped.

2. In setup_initial_mapping() we have HANDLE_PGTBL() where pgtbl is a
pointer to physical address ( which also  should be mapped in MMU if we
want to access it after MMU is enabled ):
   #define HANDLE_PGTBL(curr_lvl_num)                                    
   \
       index = pt_index(curr_lvl_num, page_addr);                        
   \
       if ( pte_is_valid(pgtbl[index]) )                                 
   \
       {                                                                 
   \
           /* Find L{ 0-3 } table */                                     
   \
           pgtbl = (pte_t *)pte_to_paddr(pgtbl[index]);                  
   \
       }                                                                 
   \
       else                                                              
   \
       {                                                                 
   \
           /* Allocate new L{0-3} page table */                          
   \
           if ( mmu_desc->pgtbl_count == PGTBL_INITIAL_COUNT )           
   \
           {                                                             
   \
               early_printk("(XEN) No initial table available\n");       
   \
               /* panic(), BUG() or ASSERT() aren't ready now. */        
   \
               die();                                                    
   \
           }                                                             
   \
           mmu_desc->pgtbl_count++;                                      
   \
           pgtbl[index] = paddr_to_pte((unsigned long)mmu_desc-
   >next_pgtbl,    \
                                       PTE_VALID);                       
   \
           pgtbl = mmu_desc->next_pgtbl;                                 
   \
           mmu_desc->next_pgtbl += PAGETABLE_ENTRIES;                    
   \
       }
   
So we can't use setup_initial_mapping() when MMU is enabled as there is
a part of the code which uses physical address which are not mapped.

We have only mapping for for liner_start <-> load_start and the small
piece of code in text section ( _ident_start ):
    setup_initial_mapping(&mmu_desc,
                          linker_start,
                          linker_end,
                          load_start);

    if ( linker_start == load_start )
        return;

    ident_start = (unsigned long)turn_on_mmu &XEN_PT_LEVEL_MAP_MASK(0);
    ident_end = ident_start + PAGE_SIZE;

    setup_initial_mapping(&mmu_desc,
                          ident_start,
                          ident_end,
                          ident_start);

We can use setup_initial_mapping() when MMU is enabled only in case
when linker_start is equal to load_start.

As an option we can consider for as a candidate for identaty mapping
also section .bss.page_aligned where root and nonroot page tables are
located.

Does it make sense now?

~ Oleksii
Jan Beulich July 11, 2024, 10:50 a.m. UTC | #5
On 11.07.2024 12:26, Oleksii wrote:
> On Thu, 2024-07-11 at 11:54 +0200, Jan Beulich wrote:
>> On 11.07.2024 11:40, Oleksii wrote:
>>> On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
>>>> On 03.07.2024 12:42, Oleksii Kurochko wrote:
>>>>> Except mapping of FDT, it is also printing command line passed
>>>>> by
>>>>> a DTB and initialize bootinfo from a DTB.
>>>>
>>>> I'm glad the description isn't empty here. However, ...
>>>>
>>>>> --- a/xen/arch/riscv/riscv64/head.S
>>>>> +++ b/xen/arch/riscv/riscv64/head.S
>>>>> @@ -41,6 +41,9 @@ FUNC(start)
>>>>>  
>>>>>          jal     setup_initial_pagetables
>>>>>  
>>>>> +        mv      a0, s1
>>>>> +        jal     fdt_map
>>>>> +
>>>>>          /* Calculate proper VA after jump from 1:1 mapping */
>>>>>          la      a0, .L_primary_switched
>>>>>          sub     a0, a0, s2
>>>>
>>>> ... it could do with clarifying why this needs calling from
>>>> assembly
>>>> code. Mapping the FDT clearly looks like something that wants
>>>> doing
>>>> from start_xen(), i.e. from C code.
>>> fdt_map() expected to work while MMU is off as it is using
>>> setup_initial_mapping() which is working with physical address.
>>
>> Hmm, interesting. When the MMU is off, what does "map" mean? Yet then
>> it feels I'm misunderstanding what you're meaning to tell me ...
> Let's look at examples of the code:
> 1. The first thing issue will be here:
>    void* __init early_fdt_map(paddr_t fdt_paddr)
>    {
>        unsigned long dt_phys_base = fdt_paddr;
>        unsigned long dt_virt_base;
>        unsigned long dt_virt_size;
>    
>        BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
>        if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN || fdt_paddr % SZ_2M 
>    ||
>              fdt_totalsize(fdt_paddr) > BOOT_FDT_VIRT_SIZE )
> MMU doesn't now about virtual address of fdt_paddr as fdt_paddr wasn't
> mapped.
> 
> 2. In setup_initial_mapping() we have HANDLE_PGTBL() where pgtbl is a
> pointer to physical address ( which also  should be mapped in MMU if we
> want to access it after MMU is enabled ):
>    #define HANDLE_PGTBL(curr_lvl_num)                                    
>    \
>        index = pt_index(curr_lvl_num, page_addr);                        
>    \
>        if ( pte_is_valid(pgtbl[index]) )                                 
>    \
>        {                                                                 
>    \
>            /* Find L{ 0-3 } table */                                     
>    \
>            pgtbl = (pte_t *)pte_to_paddr(pgtbl[index]);                  
>    \
>        }                                                                 
>    \
>        else                                                              
>    \
>        {                                                                 
>    \
>            /* Allocate new L{0-3} page table */                          
>    \
>            if ( mmu_desc->pgtbl_count == PGTBL_INITIAL_COUNT )           
>    \
>            {                                                             
>    \
>                early_printk("(XEN) No initial table available\n");       
>    \
>                /* panic(), BUG() or ASSERT() aren't ready now. */        
>    \
>                die();                                                    
>    \
>            }                                                             
>    \
>            mmu_desc->pgtbl_count++;                                      
>    \
>            pgtbl[index] = paddr_to_pte((unsigned long)mmu_desc-
>    >next_pgtbl,    \
>                                        PTE_VALID);                       
>    \
>            pgtbl = mmu_desc->next_pgtbl;                                 
>    \
>            mmu_desc->next_pgtbl += PAGETABLE_ENTRIES;                    
>    \
>        }
>    
> So we can't use setup_initial_mapping() when MMU is enabled as there is
> a part of the code which uses physical address which are not mapped.
> 
> We have only mapping for for liner_start <-> load_start and the small
> piece of code in text section ( _ident_start ):
>     setup_initial_mapping(&mmu_desc,
>                           linker_start,
>                           linker_end,
>                           load_start);
> 
>     if ( linker_start == load_start )
>         return;
> 
>     ident_start = (unsigned long)turn_on_mmu &XEN_PT_LEVEL_MAP_MASK(0);
>     ident_end = ident_start + PAGE_SIZE;
> 
>     setup_initial_mapping(&mmu_desc,
>                           ident_start,
>                           ident_end,
>                           ident_start);
> 
> We can use setup_initial_mapping() when MMU is enabled only in case
> when linker_start is equal to load_start.
> 
> As an option we can consider for as a candidate for identaty mapping
> also section .bss.page_aligned where root and nonroot page tables are
> located.
> 
> Does it make sense now?

I think so, yet at the same time it only changes the question: Why is it
that you absolutely need to use setup_initial_mapping()? Surely down the
road there are going to be more thing that need mapping relatively early,
but after the MMU was enabled.

Jan
Julien Grall July 11, 2024, 10:50 a.m. UTC | #6
Hi,

On 11/07/2024 10:40, Oleksii wrote:
> On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
>> On 03.07.2024 12:42, Oleksii Kurochko wrote:
>>> Except mapping of FDT, it is also printing command line passed by
>>> a DTB and initialize bootinfo from a DTB.
>>
>> I'm glad the description isn't empty here. However, ...
>>
>>> --- a/xen/arch/riscv/riscv64/head.S
>>> +++ b/xen/arch/riscv/riscv64/head.S
>>> @@ -41,6 +41,9 @@ FUNC(start)
>>>   
>>>           jal     setup_initial_pagetables
>>>   
>>> +        mv      a0, s1
>>> +        jal     fdt_map
>>> +
>>>           /* Calculate proper VA after jump from 1:1 mapping */
>>>           la      a0, .L_primary_switched
>>>           sub     a0, a0, s2
>>
>> ... it could do with clarifying why this needs calling from assembly
>> code. Mapping the FDT clearly looks like something that wants doing
>> from start_xen(), i.e. from C code.
> fdt_map() expected to work while MMU is off as it is using
> setup_initial_mapping() which is working with physical address.

Somewhat related to what Jan is asking. You only seem to part the FDT in 
start_xen(). So why do you need to call fdt_map() that early?

Cheers,
Oleksii Kurochko July 11, 2024, 11:28 a.m. UTC | #7
Add Julien as he asked basically the same question in another thread.

On Thu, 2024-07-11 at 12:50 +0200, Jan Beulich wrote:
> On 11.07.2024 12:26, Oleksii wrote:
> > On Thu, 2024-07-11 at 11:54 +0200, Jan Beulich wrote:
> > > On 11.07.2024 11:40, Oleksii wrote:
> > > > On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
> > > > > On 03.07.2024 12:42, Oleksii Kurochko wrote:
> > > > > > Except mapping of FDT, it is also printing command line
> > > > > > passed
> > > > > > by
> > > > > > a DTB and initialize bootinfo from a DTB.
> > > > > 
> > > > > I'm glad the description isn't empty here. However, ...
> > > > > 
> > > > > > --- a/xen/arch/riscv/riscv64/head.S
> > > > > > +++ b/xen/arch/riscv/riscv64/head.S
> > > > > > @@ -41,6 +41,9 @@ FUNC(start)
> > > > > >  
> > > > > >          jal     setup_initial_pagetables
> > > > > >  
> > > > > > +        mv      a0, s1
> > > > > > +        jal     fdt_map
> > > > > > +
> > > > > >          /* Calculate proper VA after jump from 1:1 mapping
> > > > > > */
> > > > > >          la      a0, .L_primary_switched
> > > > > >          sub     a0, a0, s2
> > > > > 
> > > > > ... it could do with clarifying why this needs calling from
> > > > > assembly
> > > > > code. Mapping the FDT clearly looks like something that wants
> > > > > doing
> > > > > from start_xen(), i.e. from C code.
> > > > fdt_map() expected to work while MMU is off as it is using
> > > > setup_initial_mapping() which is working with physical address.
> > > 
> > > Hmm, interesting. When the MMU is off, what does "map" mean? Yet
> > > then
> > > it feels I'm misunderstanding what you're meaning to tell me ...
> > Let's look at examples of the code:
> > 1. The first thing issue will be here:
> >    void* __init early_fdt_map(paddr_t fdt_paddr)
> >    {
> >        unsigned long dt_phys_base = fdt_paddr;
> >        unsigned long dt_virt_base;
> >        unsigned long dt_virt_size;
> >    
> >        BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
> >        if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN || fdt_paddr %
> > SZ_2M 
> >    ||
> >              fdt_totalsize(fdt_paddr) > BOOT_FDT_VIRT_SIZE )
> > MMU doesn't now about virtual address of fdt_paddr as fdt_paddr
> > wasn't
> > mapped.
> > 
> > 2. In setup_initial_mapping() we have HANDLE_PGTBL() where pgtbl is
> > a
> > pointer to physical address ( which also  should be mapped in MMU
> > if we
> > want to access it after MMU is enabled ):
> >    #define
> > HANDLE_PGTBL(curr_lvl_num)                                    
> >    \
> >        index = pt_index(curr_lvl_num,
> > page_addr);                        
> >    \
> >        if ( pte_is_valid(pgtbl[index])
> > )                                 
> >    \
> >       
> > {                                                                 
> >    \
> >            /* Find L{ 0-3 } table
> > */                                     
> >    \
> >            pgtbl = (pte_t
> > *)pte_to_paddr(pgtbl[index]);                  
> >    \
> >       
> > }                                                                 
> >    \
> >       
> > else                                                              
> >    \
> >       
> > {                                                                 
> >    \
> >            /* Allocate new L{0-3} page table
> > */                          
> >    \
> >            if ( mmu_desc->pgtbl_count == PGTBL_INITIAL_COUNT
> > )           
> >    \
> >           
> > {                                                             
> >    \
> >                early_printk("(XEN) No initial table
> > available\n");       
> >    \
> >                /* panic(), BUG() or ASSERT() aren't ready now.
> > */        
> >    \
> >               
> > die();                                                    
> >    \
> >           
> > }                                                             
> >    \
> >            mmu_desc-
> > >pgtbl_count++;                                      
> >    \
> >            pgtbl[index] = paddr_to_pte((unsigned long)mmu_desc-
> >    >next_pgtbl,    \
> >                                       
> > PTE_VALID);                       
> >    \
> >            pgtbl = mmu_desc-
> > >next_pgtbl;                                 
> >    \
> >            mmu_desc->next_pgtbl +=
> > PAGETABLE_ENTRIES;                    
> >    \
> >        }
> >    
> > So we can't use setup_initial_mapping() when MMU is enabled as
> > there is
> > a part of the code which uses physical address which are not
> > mapped.
> > 
> > We have only mapping for for liner_start <-> load_start and the
> > small
> > piece of code in text section ( _ident_start ):
> >     setup_initial_mapping(&mmu_desc,
> >                           linker_start,
> >                           linker_end,
> >                           load_start);
> > 
> >     if ( linker_start == load_start )
> >         return;
> > 
> >     ident_start = (unsigned long)turn_on_mmu
> > &XEN_PT_LEVEL_MAP_MASK(0);
> >     ident_end = ident_start + PAGE_SIZE;
> > 
> >     setup_initial_mapping(&mmu_desc,
> >                           ident_start,
> >                           ident_end,
> >                           ident_start);
> > 
> > We can use setup_initial_mapping() when MMU is enabled only in case
> > when linker_start is equal to load_start.
> > 
> > As an option we can consider for as a candidate for identaty
> > mapping
> > also section .bss.page_aligned where root and nonroot page tables
> > are
> > located.
> > 
> > Does it make sense now?
> 
> I think so, yet at the same time it only changes the question: Why is
> it
> that you absolutely need to use setup_initial_mapping()?
There is no strict requirement to use setup_initial_mapping(). That
function is available to me at the moment, and I haven't found a better
option other than reusing what I currently have.

If not to use setup_initial_mapping() then it is needed to introduce
xen_{un}map_table(), create_xen_table(), xen_pt_next_level(),
xen_pt_update{_entry}(), map_pages_to_xen(). What I did a little bit
later here:
https://gitlab.com/xen-project/people/olkur/xen/-/commit/a4619d0902e0a012ac2f709d31621a8d499bca97
Am I confusing something?

Could you please recommend me how to better?



> Surely down the
> road there are going to be more thing that need mapping relatively
> early,
> but after the MMU was enabled.
For sure, but for mapping other things it would be introduced
setup_mm() and necessary functions to implementinitialization and
handling of mm.

~ Oleksii
Oleksii Kurochko July 11, 2024, 11:31 a.m. UTC | #8
On Thu, 2024-07-11 at 11:50 +0100, Julien Grall wrote:
> Hi,
Hi Julien,

> 
> On 11/07/2024 10:40, Oleksii wrote:
> > On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
> > > On 03.07.2024 12:42, Oleksii Kurochko wrote:
> > > > Except mapping of FDT, it is also printing command line passed
> > > > by
> > > > a DTB and initialize bootinfo from a DTB.
> > > 
> > > I'm glad the description isn't empty here. However, ...
> > > 
> > > > --- a/xen/arch/riscv/riscv64/head.S
> > > > +++ b/xen/arch/riscv/riscv64/head.S
> > > > @@ -41,6 +41,9 @@ FUNC(start)
> > > >   
> > > >           jal     setup_initial_pagetables
> > > >   
> > > > +        mv      a0, s1
> > > > +        jal     fdt_map
> > > > +
> > > >           /* Calculate proper VA after jump from 1:1 mapping */
> > > >           la      a0, .L_primary_switched
> > > >           sub     a0, a0, s2
> > > 
> > > ... it could do with clarifying why this needs calling from
> > > assembly
> > > code. Mapping the FDT clearly looks like something that wants
> > > doing
> > > from start_xen(), i.e. from C code.
> > fdt_map() expected to work while MMU is off as it is using
> > setup_initial_mapping() which is working with physical address.
> 
> Somewhat related to what Jan is asking. You only seem to part the FDT
> in 
> start_xen(). So why do you need to call fdt_map() that early?
Let's continue our discussion in another thread ( I added you there ).

But the answer on your question is here:
https://lore.kernel.org/xen-devel/cover.1720002425.git.oleksii.kurochko@gmail.com/T/#m2890200a53c6ea2101e0f9e9ea77f589bd187e26

And
here:https://lore.kernel.org/xen-devel/cover.1720002425.git.oleksii.kurochko@gmail.com/T/#m4e20792121b97465db7081cc4c1e27bdb15cdd51

Let me know if the link above answers your question.

~ Oleksii
Julien Grall July 11, 2024, 11:54 a.m. UTC | #9
Hi,

On 11/07/2024 12:28, Oleksii wrote:
> Add Julien as he asked basically the same question in another thread.

Thanks!

> 
> On Thu, 2024-07-11 at 12:50 +0200, Jan Beulich wrote:
>> On 11.07.2024 12:26, Oleksii wrote:
>>> On Thu, 2024-07-11 at 11:54 +0200, Jan Beulich wrote:
>>>> On 11.07.2024 11:40, Oleksii wrote:
>>>>> On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
>>>>>> On 03.07.2024 12:42, Oleksii Kurochko wrote:
>>> Does it make sense now?
>>
>> I think so, yet at the same time it only changes the question: Why is
>> it
>> that you absolutely need to use setup_initial_mapping()?
> There is no strict requirement to use setup_initial_mapping(). That
> function is available to me at the moment, and I haven't found a better
> option other than reusing what I currently have.

I am not very familiar with the code base for RISC-V, but looking at the 
context in the patch, it seems you will still have the identity mapping 
mapped until start_xen().

I assume we don't exactly know where the loader will put Xen in memory. 
Which means that the region may clash with your defined runtime regions 
(such as the FDT). Did I misunderstand anything?

That's one of the reason on Arm we are trying to enable the MMU very 
early. The only thing we setup is a mapping for Xen (and earlyprintk) 
all the rest will be mapped once the MMU is on.

With that, the only thing you need to take care off the runtime Xen 
address overlapping with the identity mapping.

Cheers,
Oleksii Kurochko July 11, 2024, 12:29 p.m. UTC | #10
On Thu, 2024-07-11 at 12:54 +0100, Julien Grall wrote:
> Hi,
> 
> On 11/07/2024 12:28, Oleksii wrote:
> > Add Julien as he asked basically the same question in another
> > thread.
> 
> Thanks!
> 
> > 
> > On Thu, 2024-07-11 at 12:50 +0200, Jan Beulich wrote:
> > > On 11.07.2024 12:26, Oleksii wrote:
> > > > On Thu, 2024-07-11 at 11:54 +0200, Jan Beulich wrote:
> > > > > On 11.07.2024 11:40, Oleksii wrote:
> > > > > > On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
> > > > > > > On 03.07.2024 12:42, Oleksii Kurochko wrote:
> > > > Does it make sense now?
> > > 
> > > I think so, yet at the same time it only changes the question:
> > > Why is
> > > it
> > > that you absolutely need to use setup_initial_mapping()?
> > There is no strict requirement to use setup_initial_mapping(). That
> > function is available to me at the moment, and I haven't found a
> > better
> > option other than reusing what I currently have.
> 
> I am not very familiar with the code base for RISC-V, but looking at
> the 
> context in the patch, it seems you will still have the identity
> mapping 
> mapped until start_xen().
We have identity mapping only for a small piece of .text section:
        . = ALIGN(IDENT_AREA_SIZE);
        _ident_start = .;
        *(.text.ident)
        _ident_end = .;

All other will be identically mapped only in case of linker address is
equal to load address.

> 
> I assume we don't exactly know where the loader will put Xen in
> memory. 
> Which means that the region may clash with your defined runtime
> regions 
> (such as the FDT). Did I misunderstand anything?
I am not really get what is the issue here.

If we are speaking about physical regions then loader will guarantee
that Xen and FDT regions don't overlap.

If we are speaking about virtual regions then Xen will check that
nothing is overlaped. And the virtual regions are mapped so high so I
am not sure that loader will put something there. ( FDT in Xen is
mapped to 0xffffffffc0200000 ).

Could you please clarify what I am missing?

> 
> That's one of the reason on Arm we are trying to enable the MMU very 
> early. The only thing we setup is a mapping for Xen (and earlyprintk)
> all the rest will be mapped once the MMU is on.
It makes sense. Then I have to introduce map_pages_to_xen() first and
then early_fdt_map().

~ Oleksii

> 
> With that, the only thing you need to take care off the runtime Xen 
> address overlapping with the identity mapping.
Julien Grall July 11, 2024, 12:44 p.m. UTC | #11
Hi Oleksii,

On 11/07/2024 13:29, Oleksii wrote:
> On Thu, 2024-07-11 at 12:54 +0100, Julien Grall wrote:
>> Hi,
>>
>> On 11/07/2024 12:28, Oleksii wrote:
>>> Add Julien as he asked basically the same question in another
>>> thread.
>>
>> Thanks!
>>
>>>
>>> On Thu, 2024-07-11 at 12:50 +0200, Jan Beulich wrote:
>>>> On 11.07.2024 12:26, Oleksii wrote:
>>>>> On Thu, 2024-07-11 at 11:54 +0200, Jan Beulich wrote:
>>>>>> On 11.07.2024 11:40, Oleksii wrote:
>>>>>>> On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
>>>>>>>> On 03.07.2024 12:42, Oleksii Kurochko wrote:
>>>>> Does it make sense now?
>>>>
>>>> I think so, yet at the same time it only changes the question:
>>>> Why is
>>>> it
>>>> that you absolutely need to use setup_initial_mapping()?
>>> There is no strict requirement to use setup_initial_mapping(). That
>>> function is available to me at the moment, and I haven't found a
>>> better
>>> option other than reusing what I currently have.
>>
>> I am not very familiar with the code base for RISC-V, but looking at
>> the
>> context in the patch, it seems you will still have the identity
>> mapping
>> mapped until start_xen().
> We have identity mapping only for a small piece of .text section:
>          . = ALIGN(IDENT_AREA_SIZE);
>          _ident_start = .;
>          *(.text.ident)
>          _ident_end = .;
> 
> All other will be identically mapped only in case of linker address is
> equal to load address.
> 
>>
>> I assume we don't exactly know where the loader will put Xen in
>> memory.
>> Which means that the region may clash with your defined runtime
>> regions
>> (such as the FDT). Did I misunderstand anything?
> I am not really get what is the issue here.
> 
> If we are speaking about physical regions then loader will guarantee
> that Xen and FDT regions don't overlap.

Sure. But I was referring to...

> 
> If we are speaking about virtual regions then Xen will check that
> nothing is overlaped. 

... this part. The more regions you mapped with MMU off, the more work 
you have to do to ensure nothing will clash.

> And the virtual regions are mapped so high so I
> am not sure that loader will put something there. ( FDT in Xen is
> mapped to 0xffffffffc0200000 )
Never say never :). On Arm, some 64-bit HW (such as ADLink AVA platform) 
has the RAM starting very high and load Xen around 8TB. For Arm, we 
still decided to put a limit (10TB) where Xen can be loaded but this is 
mainly done for convenience (otherwise it is a bit more complicated to 
get off the identity mapping).

We still have a check in place to ensure that Xen is not loaded above 
10TB. If you map the FDT within the same L1.

Cheers,
Oleksii Kurochko July 11, 2024, 1:14 p.m. UTC | #12
On Thu, 2024-07-11 at 13:44 +0100, Julien Grall wrote:
> Hi Oleksii,
Hi Julien,

> 
> On 11/07/2024 13:29, Oleksii wrote:
> > On Thu, 2024-07-11 at 12:54 +0100, Julien Grall wrote:
> > > Hi,
> > > 
> > > On 11/07/2024 12:28, Oleksii wrote:
> > > > Add Julien as he asked basically the same question in another
> > > > thread.
> > > 
> > > Thanks!
> > > 
> > > > 
> > > > On Thu, 2024-07-11 at 12:50 +0200, Jan Beulich wrote:
> > > > > On 11.07.2024 12:26, Oleksii wrote:
> > > > > > On Thu, 2024-07-11 at 11:54 +0200, Jan Beulich wrote:
> > > > > > > On 11.07.2024 11:40, Oleksii wrote:
> > > > > > > > On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
> > > > > > > > > On 03.07.2024 12:42, Oleksii Kurochko wrote:
> > > > > > Does it make sense now?
> > > > > 
> > > > > I think so, yet at the same time it only changes the
> > > > > question:
> > > > > Why is
> > > > > it
> > > > > that you absolutely need to use setup_initial_mapping()?
> > > > There is no strict requirement to use setup_initial_mapping().
> > > > That
> > > > function is available to me at the moment, and I haven't found
> > > > a
> > > > better
> > > > option other than reusing what I currently have.
> > > 
> > > I am not very familiar with the code base for RISC-V, but looking
> > > at
> > > the
> > > context in the patch, it seems you will still have the identity
> > > mapping
> > > mapped until start_xen().
> > We have identity mapping only for a small piece of .text section:
> >          . = ALIGN(IDENT_AREA_SIZE);
> >          _ident_start = .;
> >          *(.text.ident)
> >          _ident_end = .;
> > 
> > All other will be identically mapped only in case of linker address
> > is
> > equal to load address.
> > 
> > > 
> > > I assume we don't exactly know where the loader will put Xen in
> > > memory.
> > > Which means that the region may clash with your defined runtime
> > > regions
> > > (such as the FDT). Did I misunderstand anything?
> > I am not really get what is the issue here.
> > 
> > If we are speaking about physical regions then loader will
> > guarantee
> > that Xen and FDT regions don't overlap.
> 
> Sure. But I was referring to...
> 
> > 
> > If we are speaking about virtual regions then Xen will check that
> > nothing is overlaped. 
> 
> ... this part. The more regions you mapped with MMU off, the more
> work 
> you have to do to ensure nothing will clash.
Yes, agree here. Then I have to look at what I need now to introduce
map_pages_to_xen().

Thanks for clarifying.

> 
> > And the virtual regions are mapped so high so I
> > am not sure that loader will put something there. ( FDT in Xen is
> > mapped to 0xffffffffc0200000 )
> Never say never :). On Arm, some 64-bit HW (such as ADLink AVA
> platform) 
> has the RAM starting very high and load Xen around 8TB. For Arm, we 
> still decided to put a limit (10TB) where Xen can be loaded but this
> is 
> mainly done for convenience (otherwise it is a bit more complicated
> to 
> get off the identity mapping).
Oh, it is very high. I couldn't even expect.

~ Oleksii

> 
> We still have a check in place to ensure that Xen is not loaded above
> 10TB. If you map the FDT within the same L1.
> 
> Cheers,
>
Jan Beulich July 11, 2024, 2:37 p.m. UTC | #13
On 11.07.2024 13:28, Oleksii wrote:
> On Thu, 2024-07-11 at 12:50 +0200, Jan Beulich wrote:
>> On 11.07.2024 12:26, Oleksii wrote:
>>> On Thu, 2024-07-11 at 11:54 +0200, Jan Beulich wrote:
>>>> On 11.07.2024 11:40, Oleksii wrote:
>>>>> On Wed, 2024-07-10 at 14:38 +0200, Jan Beulich wrote:
>>>>>> On 03.07.2024 12:42, Oleksii Kurochko wrote:
>>>>>>> Except mapping of FDT, it is also printing command line
>>>>>>> passed
>>>>>>> by
>>>>>>> a DTB and initialize bootinfo from a DTB.
>>>>>>
>>>>>> I'm glad the description isn't empty here. However, ...
>>>>>>
>>>>>>> --- a/xen/arch/riscv/riscv64/head.S
>>>>>>> +++ b/xen/arch/riscv/riscv64/head.S
>>>>>>> @@ -41,6 +41,9 @@ FUNC(start)
>>>>>>>  
>>>>>>>          jal     setup_initial_pagetables
>>>>>>>  
>>>>>>> +        mv      a0, s1
>>>>>>> +        jal     fdt_map
>>>>>>> +
>>>>>>>          /* Calculate proper VA after jump from 1:1 mapping
>>>>>>> */
>>>>>>>          la      a0, .L_primary_switched
>>>>>>>          sub     a0, a0, s2
>>>>>>
>>>>>> ... it could do with clarifying why this needs calling from
>>>>>> assembly
>>>>>> code. Mapping the FDT clearly looks like something that wants
>>>>>> doing
>>>>>> from start_xen(), i.e. from C code.
>>>>> fdt_map() expected to work while MMU is off as it is using
>>>>> setup_initial_mapping() which is working with physical address.
>>>>
>>>> Hmm, interesting. When the MMU is off, what does "map" mean? Yet
>>>> then
>>>> it feels I'm misunderstanding what you're meaning to tell me ...
>>> Let's look at examples of the code:
>>> 1. The first thing issue will be here:
>>>    void* __init early_fdt_map(paddr_t fdt_paddr)
>>>    {
>>>        unsigned long dt_phys_base = fdt_paddr;
>>>        unsigned long dt_virt_base;
>>>        unsigned long dt_virt_size;
>>>    
>>>        BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
>>>        if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN || fdt_paddr %
>>> SZ_2M 
>>>    ||
>>>              fdt_totalsize(fdt_paddr) > BOOT_FDT_VIRT_SIZE )
>>> MMU doesn't now about virtual address of fdt_paddr as fdt_paddr
>>> wasn't
>>> mapped.
>>>
>>> 2. In setup_initial_mapping() we have HANDLE_PGTBL() where pgtbl is
>>> a
>>> pointer to physical address ( which also  should be mapped in MMU
>>> if we
>>> want to access it after MMU is enabled ):
>>>    #define
>>> HANDLE_PGTBL(curr_lvl_num)                                    
>>>    \
>>>        index = pt_index(curr_lvl_num,
>>> page_addr);                        
>>>    \
>>>        if ( pte_is_valid(pgtbl[index])
>>> )                                 
>>>    \
>>>       
>>> {                                                                 
>>>    \
>>>            /* Find L{ 0-3 } table
>>> */                                     
>>>    \
>>>            pgtbl = (pte_t
>>> *)pte_to_paddr(pgtbl[index]);                  
>>>    \
>>>       
>>> }                                                                 
>>>    \
>>>       
>>> else                                                              
>>>    \
>>>       
>>> {                                                                 
>>>    \
>>>            /* Allocate new L{0-3} page table
>>> */                          
>>>    \
>>>            if ( mmu_desc->pgtbl_count == PGTBL_INITIAL_COUNT
>>> )           
>>>    \
>>>           
>>> {                                                             
>>>    \
>>>                early_printk("(XEN) No initial table
>>> available\n");       
>>>    \
>>>                /* panic(), BUG() or ASSERT() aren't ready now.
>>> */        
>>>    \
>>>               
>>> die();                                                    
>>>    \
>>>           
>>> }                                                             
>>>    \
>>>            mmu_desc-
>>>> pgtbl_count++;                                      
>>>    \
>>>            pgtbl[index] = paddr_to_pte((unsigned long)mmu_desc-
>>>    >next_pgtbl,    \
>>>                                       
>>> PTE_VALID);                       
>>>    \
>>>            pgtbl = mmu_desc-
>>>> next_pgtbl;                                 
>>>    \
>>>            mmu_desc->next_pgtbl +=
>>> PAGETABLE_ENTRIES;                    
>>>    \
>>>        }
>>>    
>>> So we can't use setup_initial_mapping() when MMU is enabled as
>>> there is
>>> a part of the code which uses physical address which are not
>>> mapped.
>>>
>>> We have only mapping for for liner_start <-> load_start and the
>>> small
>>> piece of code in text section ( _ident_start ):
>>>     setup_initial_mapping(&mmu_desc,
>>>                           linker_start,
>>>                           linker_end,
>>>                           load_start);
>>>
>>>     if ( linker_start == load_start )
>>>         return;
>>>
>>>     ident_start = (unsigned long)turn_on_mmu
>>> &XEN_PT_LEVEL_MAP_MASK(0);
>>>     ident_end = ident_start + PAGE_SIZE;
>>>
>>>     setup_initial_mapping(&mmu_desc,
>>>                           ident_start,
>>>                           ident_end,
>>>                           ident_start);
>>>
>>> We can use setup_initial_mapping() when MMU is enabled only in case
>>> when linker_start is equal to load_start.
>>>
>>> As an option we can consider for as a candidate for identaty
>>> mapping
>>> also section .bss.page_aligned where root and nonroot page tables
>>> are
>>> located.
>>>
>>> Does it make sense now?
>>
>> I think so, yet at the same time it only changes the question: Why is
>> it
>> that you absolutely need to use setup_initial_mapping()?
> There is no strict requirement to use setup_initial_mapping(). That
> function is available to me at the moment, and I haven't found a better
> option other than reusing what I currently have.
> 
> If not to use setup_initial_mapping() then it is needed to introduce
> xen_{un}map_table(), create_xen_table(), xen_pt_next_level(),
> xen_pt_update{_entry}(), map_pages_to_xen(). What I did a little bit
> later here:
> https://gitlab.com/xen-project/people/olkur/xen/-/commit/a4619d0902e0a012ac2f709d31621a8d499bca97
> Am I confusing something?
> 
> Could you please recommend me how to better?

I think you've sorted this for yourself already, judging from subsequent
communication on this thread, where you indicate you'll introduce
map_pages_to_xen() first. That's the way I'd have expected you to go.

Jan
diff mbox series

Patch

diff --git a/xen/arch/riscv/riscv64/head.S b/xen/arch/riscv/riscv64/head.S
index 3261e9fce8..22fb36a861 100644
--- a/xen/arch/riscv/riscv64/head.S
+++ b/xen/arch/riscv/riscv64/head.S
@@ -41,6 +41,9 @@  FUNC(start)
 
         jal     setup_initial_pagetables
 
+        mv      a0, s1
+        jal     fdt_map
+
         /* Calculate proper VA after jump from 1:1 mapping */
         la      a0, .L_primary_switched
         sub     a0, a0, s2
diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c
index 4f06203b46..b346956e06 100644
--- a/xen/arch/riscv/setup.c
+++ b/xen/arch/riscv/setup.c
@@ -1,7 +1,9 @@ 
 /* SPDX-License-Identifier: GPL-2.0-only */
 
+#include <xen/bootfdt.h>
 #include <xen/bug.h>
 #include <xen/compile.h>
+#include <xen/device_tree.h>
 #include <xen/init.h>
 #include <xen/mm.h>
 
@@ -33,15 +35,34 @@  static void test_macros_from_bug_h(void)
     printk("WARN is most likely working\n");
 }
 
+void __init fdt_map(paddr_t dtb_addr)
+{
+    device_tree_flattened = early_fdt_map(dtb_addr);
+    if ( !device_tree_flattened )
+    {
+        printk("wrong FDT\n");
+        die();
+    }
+}
+
 void __init noreturn start_xen(unsigned long bootcpu_id,
                                paddr_t dtb_addr)
 {
+    size_t fdt_size;
+    const char *cmdline;
+
     remove_identity_mapping();
 
     trap_init();
 
     test_macros_from_bug_h();
 
+    fdt_size = boot_fdt_info(device_tree_flattened, dtb_addr);
+
+    cmdline = boot_fdt_cmdline(device_tree_flattened);
+    printk("Command line: %s\n", cmdline);
+    cmdline_parse(cmdline);
+
     printk("All set up\n");
 
     for ( ;; )