All of lore.kernel.org
 help / color / mirror / Atom feed
From: Palmer Dabbelt <palmer@dabbelt.com>
To: alex@ghiti.fr
Cc: Christoph Hellwig <hch@infradead.org>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	aou@eecs.berkeley.edu, jszhang@kernel.org, zong.li@sifive.com,
	anup@brainfault.org, linux-riscv@lists.infradead.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2] riscv: Map the kernel with correct permissions the first time
Date: Sat, 29 May 2021 13:38:09 -0700 (PDT)	[thread overview]
Message-ID: <mhng-7da55144-a2f6-458b-9e47-235391855832@palmerdabbelt-glaptop> (raw)
In-Reply-To: <fe6fe4ba-00df-4695-c31e-7078bd77be50@ghiti.fr>

On Fri, 28 May 2021 01:24:43 PDT (-0700), alex@ghiti.fr wrote:
> Hi Christoph,
>
> Le 27/05/2021 à 08:35, Christoph Hellwig a écrit :
>> On Wed, May 26, 2021 at 03:41:10PM +0200, Alexandre Ghiti wrote:
>>>   #ifdef CONFIG_64BIT
>>> +#define is_kernel_mapping(x)	((x) >= kernel_virt_addr && (x) < (kernel_virt_addr + load_sz))
>>> +#define is_linear_mapping(x)	((x) >= PAGE_OFFSET && (x) < kernel_virt_addr)
>>> +
>>
>> Overly long lines.  Independ of that complex macros are generally much
>> more readable if they are written more function-like, that is the name
>> and paramtes are kept on a line of their own:
>>
>> #define is_kernel_mapping(x) \
>> 	((x) >= kernel_virt_addr && (x) < (kernel_virt_addr + load_sz))
>>
>> But what is the reason to not make them type-safe inline functions
>> anyway?
>
> No reason. I will then make those macros inline functions and send
> another patchset to make the below macro an inline function too.
>
>>
>>>   #define __va_to_pa_nodebug(x)	({						\
>>>   	unsigned long _x = x;							\
>>> -	(_x < kernel_virt_addr) ?						\
>>> +	is_linear_mapping(_x) ?							\
>>>   		linear_mapping_va_to_pa(_x) : kernel_mapping_va_to_pa(_x);	\
>>>   	})
>>
>> ... especially for something complex like this.
>>
>>> +static inline bool is_va_kernel_lm_alias_text(uintptr_t va)
>>> +{
>>> +	return (va >= (uintptr_t)lm_alias(_start) && va < (uintptr_t)lm_alias(__init_text_begin));
>>
>> Overly long line as well.  And useless braces.
>
> Ok.
>
>>
>>> +static inline bool is_va_kernel_init_text(uintptr_t va)
>>> +{
>>> +	return (va >= (uintptr_t)__init_text_begin && va < (uintptr_t)__init_data_begin);
>>> +}
>>
>> Same here.
>
> checkpatch does not complain about those lines which are under 100
> characters, what's the point in breaking them on multiple lines?
>
>>
>>> +#ifdef CONFIG_STRICT_KERNEL_RWX
>>> +static __init pgprot_t pgprot_from_va(uintptr_t va)
>>> +{
>>> +#ifdef CONFIG_64BIT
>>> +	if (is_va_kernel_text(va) || is_va_kernel_init_text(va))
>>> +		return PAGE_KERNEL_READ_EXEC;
>>> +
>>> +	/*
>>> +	 * We must mark only text as read-only as init text will get freed later
>>> +	 * and rodata section is marked readonly in mark_rodata_ro.
>>> +	 */
>>> +	if (is_va_kernel_lm_alias_text(va))
>>> +		return PAGE_KERNEL_READ;
>>> +
>>> +	return PAGE_KERNEL;
>>> +#else
>>> +	if (is_va_kernel_text(va))
>>> +		return PAGE_KERNEL_READ_EXEC;
>>> +
>>> +	if (is_va_kernel_init_text(va))
>>> +		return PAGE_KERNEL_EXEC;
>>> +
>>> +	return PAGE_KERNEL;
>>> +#endif /* CONFIG_64BIT */
>>> +}
>>
>> If the entire function is different for config symbols please just
>> split it into two separate functions.  But to make the difference more
>> clear IS_ENABLED might fit better here:
>>
>> static __init pgprot_t pgprot_from_va(uintptr_t va)
>> {
>> 	if (is_va_kernel_text(va))
>> 		return PAGE_KERNEL_READ_EXEC;
>> 	if (is_va_kernel_init_text(va))
>> 		return IS_ENABLED(CONFIG_64BIT) ?
>> 			PAGE_KERNEL_READ_EXEC : PAGE_KERNEL_EXEC;
>> 	if (IS_ENABLED(CONFIG_64BIT) && is_va_kernel_lm_alias_text(va))
>> 		return PAGE_KERNEL_READ;
>> 	return PAGE_KERNEL;
>> }
>>
>> Preferable with comments explaining the 32-bit vs 64-bit difference.
>
> Ok this is more compact, I'll do that with the comment.
>
>>
>>> +void mark_rodata_ro(void)
>>> +{
>>> +	unsigned long rodata_start = (unsigned long)__start_rodata;
>>> +	unsigned long data_start = (unsigned long)_data;
>>> +	unsigned long __maybe_unused lm_rodata_start = (unsigned long)lm_alias(__start_rodata);
>>> +	unsigned long __maybe_unused lm_data_start = (unsigned long)lm_alias(_data);
>>> +
>>> +	set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
>>> +#ifdef CONFIG_64BIT
>>> +	set_memory_ro(lm_rodata_start, (lm_data_start - lm_rodata_start) >> PAGE_SHIFT);
>>> +#endif
>>
>> Lots of unreadable overly lone lines.  Why not add a helper and do
>> something like:
>>
>> static void set_kernel_memory_ro(char *startp, char *endp)
>> {
>>          unsigned long start = (unsigned long)startp;
>> 	unsigned long end = (unsigned long)endp;
>>
>> 	set_memory_ro(start, (start - end) >> PAGE_SHIFT);
>> }
>>
>>          set_kernel_memory_ro(_start_rodata, _data);
>> 	if (IS_ENABLED(CONFIG_64BIT))
>> 		set_kernel_memory_ro(lm_alias(__start_rodata), lm_alias(_data));
>>
>>
>
> Ok, that's better indeed. I will do something like that instead, to
> avoid multiple versions of this helper:
>
> int set_kernel_memory(char *startp, char *endp,
>
>                        int (*set_memory)(unsigned long start, int
> num_pages))
>
>>> +static __init pgprot_t pgprot_from_va(uintptr_t va)
>>> +{
>>> +#ifdef CONFIG_64BIT
>>> +	if (is_kernel_mapping(va))
>>> +		return PAGE_KERNEL_EXEC;
>>> +
>>> +	if (is_linear_mapping(va))
>>> +		return PAGE_KERNEL;
>>> +
>>> +	return PAGE_KERNEL;
>>> +#else
>>> +	return PAGE_KERNEL_EXEC;
>>> +#endif /* CONFIG_64BIT */
>>> +}
>>> +#endif /* CONFIG_STRICT_KERNEL_RWX */
>>> +
>>
>> Same comment as for the other version.  This could become:
>>
>> static __init pgprot_t pgprot_from_va(uintptr_t va)
>> {
>> 	if (IS_ENABLED(CONFIG_64BIT) && !is_kernel_mapping(va))
>> 		return PAGE_KERNEL;
>> 	return PAGE_KERNEL_EXEC;
>> }
>
> Ok I'll do that.
>
>>
>>> -static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size)
>>> +static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size, bool early)
>>
>> Overly long line.
>>
>>>   	for (va = kernel_virt_addr; va < end_va; va += map_size)
>>>   		create_pgd_mapping(pgdir, va,
>>>   				   load_pa + (va - kernel_virt_addr),
>>> -				   map_size, PAGE_KERNEL_EXEC);
>>> +				   map_size, early ? PAGE_KERNEL_EXEC : pgprot_from_va(va));
>>
>> Same here.  But why not pass in a "pgprot_t ram_pgprot" instead of the
>> bool, which would be self-documenting.
>
> This function is used to map the kernel mapping, the pgprot_t is then
> different in create_kernel_page_table depending on the virtual address
> so I can't pass a single pgprot_t for that or I would need a dummy
> pgprot_t to test anyway.

Thanks.  I've got a riscv-wx-mappings branch with the fix on it, I'll 
take this on there when we have something ready to go and then merge 
both into for-next so we can avoid merge conflicts.

>
> Thank you for your review,
>
> Alex
>
>>
>> _______________________________________________
>> linux-riscv mailing list
>> linux-riscv@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-riscv
>>

WARNING: multiple messages have this Message-ID (diff)
From: Palmer Dabbelt <palmer@dabbelt.com>
To: alex@ghiti.fr
Cc: Christoph Hellwig <hch@infradead.org>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	 aou@eecs.berkeley.edu, jszhang@kernel.org, zong.li@sifive.com,
	anup@brainfault.org,  linux-riscv@lists.infradead.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2] riscv: Map the kernel with correct permissions the first time
Date: Sat, 29 May 2021 13:38:09 -0700 (PDT)	[thread overview]
Message-ID: <mhng-7da55144-a2f6-458b-9e47-235391855832@palmerdabbelt-glaptop> (raw)
In-Reply-To: <fe6fe4ba-00df-4695-c31e-7078bd77be50@ghiti.fr>

On Fri, 28 May 2021 01:24:43 PDT (-0700), alex@ghiti.fr wrote:
> Hi Christoph,
>
> Le 27/05/2021 à 08:35, Christoph Hellwig a écrit :
>> On Wed, May 26, 2021 at 03:41:10PM +0200, Alexandre Ghiti wrote:
>>>   #ifdef CONFIG_64BIT
>>> +#define is_kernel_mapping(x)	((x) >= kernel_virt_addr && (x) < (kernel_virt_addr + load_sz))
>>> +#define is_linear_mapping(x)	((x) >= PAGE_OFFSET && (x) < kernel_virt_addr)
>>> +
>>
>> Overly long lines.  Independ of that complex macros are generally much
>> more readable if they are written more function-like, that is the name
>> and paramtes are kept on a line of their own:
>>
>> #define is_kernel_mapping(x) \
>> 	((x) >= kernel_virt_addr && (x) < (kernel_virt_addr + load_sz))
>>
>> But what is the reason to not make them type-safe inline functions
>> anyway?
>
> No reason. I will then make those macros inline functions and send
> another patchset to make the below macro an inline function too.
>
>>
>>>   #define __va_to_pa_nodebug(x)	({						\
>>>   	unsigned long _x = x;							\
>>> -	(_x < kernel_virt_addr) ?						\
>>> +	is_linear_mapping(_x) ?							\
>>>   		linear_mapping_va_to_pa(_x) : kernel_mapping_va_to_pa(_x);	\
>>>   	})
>>
>> ... especially for something complex like this.
>>
>>> +static inline bool is_va_kernel_lm_alias_text(uintptr_t va)
>>> +{
>>> +	return (va >= (uintptr_t)lm_alias(_start) && va < (uintptr_t)lm_alias(__init_text_begin));
>>
>> Overly long line as well.  And useless braces.
>
> Ok.
>
>>
>>> +static inline bool is_va_kernel_init_text(uintptr_t va)
>>> +{
>>> +	return (va >= (uintptr_t)__init_text_begin && va < (uintptr_t)__init_data_begin);
>>> +}
>>
>> Same here.
>
> checkpatch does not complain about those lines which are under 100
> characters, what's the point in breaking them on multiple lines?
>
>>
>>> +#ifdef CONFIG_STRICT_KERNEL_RWX
>>> +static __init pgprot_t pgprot_from_va(uintptr_t va)
>>> +{
>>> +#ifdef CONFIG_64BIT
>>> +	if (is_va_kernel_text(va) || is_va_kernel_init_text(va))
>>> +		return PAGE_KERNEL_READ_EXEC;
>>> +
>>> +	/*
>>> +	 * We must mark only text as read-only as init text will get freed later
>>> +	 * and rodata section is marked readonly in mark_rodata_ro.
>>> +	 */
>>> +	if (is_va_kernel_lm_alias_text(va))
>>> +		return PAGE_KERNEL_READ;
>>> +
>>> +	return PAGE_KERNEL;
>>> +#else
>>> +	if (is_va_kernel_text(va))
>>> +		return PAGE_KERNEL_READ_EXEC;
>>> +
>>> +	if (is_va_kernel_init_text(va))
>>> +		return PAGE_KERNEL_EXEC;
>>> +
>>> +	return PAGE_KERNEL;
>>> +#endif /* CONFIG_64BIT */
>>> +}
>>
>> If the entire function is different for config symbols please just
>> split it into two separate functions.  But to make the difference more
>> clear IS_ENABLED might fit better here:
>>
>> static __init pgprot_t pgprot_from_va(uintptr_t va)
>> {
>> 	if (is_va_kernel_text(va))
>> 		return PAGE_KERNEL_READ_EXEC;
>> 	if (is_va_kernel_init_text(va))
>> 		return IS_ENABLED(CONFIG_64BIT) ?
>> 			PAGE_KERNEL_READ_EXEC : PAGE_KERNEL_EXEC;
>> 	if (IS_ENABLED(CONFIG_64BIT) && is_va_kernel_lm_alias_text(va))
>> 		return PAGE_KERNEL_READ;
>> 	return PAGE_KERNEL;
>> }
>>
>> Preferable with comments explaining the 32-bit vs 64-bit difference.
>
> Ok this is more compact, I'll do that with the comment.
>
>>
>>> +void mark_rodata_ro(void)
>>> +{
>>> +	unsigned long rodata_start = (unsigned long)__start_rodata;
>>> +	unsigned long data_start = (unsigned long)_data;
>>> +	unsigned long __maybe_unused lm_rodata_start = (unsigned long)lm_alias(__start_rodata);
>>> +	unsigned long __maybe_unused lm_data_start = (unsigned long)lm_alias(_data);
>>> +
>>> +	set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
>>> +#ifdef CONFIG_64BIT
>>> +	set_memory_ro(lm_rodata_start, (lm_data_start - lm_rodata_start) >> PAGE_SHIFT);
>>> +#endif
>>
>> Lots of unreadable overly lone lines.  Why not add a helper and do
>> something like:
>>
>> static void set_kernel_memory_ro(char *startp, char *endp)
>> {
>>          unsigned long start = (unsigned long)startp;
>> 	unsigned long end = (unsigned long)endp;
>>
>> 	set_memory_ro(start, (start - end) >> PAGE_SHIFT);
>> }
>>
>>          set_kernel_memory_ro(_start_rodata, _data);
>> 	if (IS_ENABLED(CONFIG_64BIT))
>> 		set_kernel_memory_ro(lm_alias(__start_rodata), lm_alias(_data));
>>
>>
>
> Ok, that's better indeed. I will do something like that instead, to
> avoid multiple versions of this helper:
>
> int set_kernel_memory(char *startp, char *endp,
>
>                        int (*set_memory)(unsigned long start, int
> num_pages))
>
>>> +static __init pgprot_t pgprot_from_va(uintptr_t va)
>>> +{
>>> +#ifdef CONFIG_64BIT
>>> +	if (is_kernel_mapping(va))
>>> +		return PAGE_KERNEL_EXEC;
>>> +
>>> +	if (is_linear_mapping(va))
>>> +		return PAGE_KERNEL;
>>> +
>>> +	return PAGE_KERNEL;
>>> +#else
>>> +	return PAGE_KERNEL_EXEC;
>>> +#endif /* CONFIG_64BIT */
>>> +}
>>> +#endif /* CONFIG_STRICT_KERNEL_RWX */
>>> +
>>
>> Same comment as for the other version.  This could become:
>>
>> static __init pgprot_t pgprot_from_va(uintptr_t va)
>> {
>> 	if (IS_ENABLED(CONFIG_64BIT) && !is_kernel_mapping(va))
>> 		return PAGE_KERNEL;
>> 	return PAGE_KERNEL_EXEC;
>> }
>
> Ok I'll do that.
>
>>
>>> -static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size)
>>> +static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size, bool early)
>>
>> Overly long line.
>>
>>>   	for (va = kernel_virt_addr; va < end_va; va += map_size)
>>>   		create_pgd_mapping(pgdir, va,
>>>   				   load_pa + (va - kernel_virt_addr),
>>> -				   map_size, PAGE_KERNEL_EXEC);
>>> +				   map_size, early ? PAGE_KERNEL_EXEC : pgprot_from_va(va));
>>
>> Same here.  But why not pass in a "pgprot_t ram_pgprot" instead of the
>> bool, which would be self-documenting.
>
> This function is used to map the kernel mapping, the pgprot_t is then
> different in create_kernel_page_table depending on the virtual address
> so I can't pass a single pgprot_t for that or I would need a dummy
> pgprot_t to test anyway.

Thanks.  I've got a riscv-wx-mappings branch with the fix on it, I'll 
take this on there when we have something ready to go and then merge 
both into for-next so we can avoid merge conflicts.

>
> Thank you for your review,
>
> Alex
>
>>
>> _______________________________________________
>> linux-riscv mailing list
>> linux-riscv@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-riscv
>>

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

  reply	other threads:[~2021-05-29 20:38 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-26 13:41 [PATCH v2] riscv: Map the kernel with correct permissions the first time Alexandre Ghiti
2021-05-26 13:41 ` Alexandre Ghiti
2021-05-27  6:35 ` Christoph Hellwig
2021-05-27  6:35   ` Christoph Hellwig
2021-05-28  8:24   ` Alex Ghiti
2021-05-28  8:24     ` Alex Ghiti
2021-05-29 20:38     ` Palmer Dabbelt [this message]
2021-05-29 20:38       ` Palmer Dabbelt
2021-06-03  5:59   ` Alex Ghiti
2021-06-03  5:59     ` Alex Ghiti
2021-05-29  4:08 ` Drew Fustini
2021-05-29  4:08   ` Drew Fustini
2021-05-29 17:46   ` Drew Fustini
2021-05-29 17:46     ` Drew Fustini
2021-05-30  7:52     ` Alex Ghiti
2021-05-30  7:52       ` Alex Ghiti

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=mhng-7da55144-a2f6-458b-9e47-235391855832@palmerdabbelt-glaptop \
    --to=palmer@dabbelt.com \
    --cc=alex@ghiti.fr \
    --cc=anup@brainfault.org \
    --cc=aou@eecs.berkeley.edu \
    --cc=hch@infradead.org \
    --cc=jszhang@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=paul.walmsley@sifive.com \
    --cc=zong.li@sifive.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.