[RFC,v1,4/4] target-arm: Compute page size based on ARM target cpu type
diff mbox

Message ID 1465808915-4887-5-git-send-email-vijayak@caviumnetworks.com
State New
Headers show

Commit Message

vijayak@caviumnetworks.com June 13, 2016, 9:08 a.m. UTC
From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Replace TARGET_PAGE_BITS with arm_target_page_size function
in order to fetch page size at run-time.

Introduced MachineClass callback to compute target page
size at the early boot before memory initialization.
This callback is currently implemented for ARM platforms.
Based on cpu_model, the page size is updated in
target_page_bits which is defined as TARGET_PAGE_BITS.

Signed-off-by: Vijaya Kumar K <vijayak@cavium.com>
---
 hw/arm/virt.c       |   48 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/boards.h |    1 +
 target-arm/cpu.h    |   12 +++++++-----
 vl.c                |    7 +++++++
 4 files changed, 63 insertions(+), 5 deletions(-)

Comments

Vijay Kilari June 14, 2016, 11:14 a.m. UTC | #1
On Mon, Jun 13, 2016 at 3:40 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 13 June 2016 at 10:43, Peter Maydell <peter.maydell@linaro.org> wrote:
>> On 13 June 2016 at 10:08,  <vijayak@caviumnetworks.com> wrote:
>>> +/*
>>> + * Holds TARGET_AARCH_64_PAGE_BITS or TARGET_ARM_PAGE_BITS
>>> + * based on the the cpu type emulated at runtime.
>>> + */
>>> +static uint32_t target_page_bits;
>>
>> The CPU page size is not specific to the 'virt' board, so this
>> is the wrong place to do this. You should identify the
>> page size in arm_cpu_realizefn() based on the set of feature
>> bits the CPU has: anything with ARM_FEATURE_V7 has a 4K page
>> table (this includes a lot of 32-bit CPUs).

  cpu_init and cpu_realizefn() of required cpu model is called in
machvirt_init(),
which is quite late in the initialization sequence.
The cpu_exec_init_all() which calls memory_map_init() is called very
early stage,
is where TARGET_PAGE_BITS information is required.

In order to get feature information of CPU early, one option is to
create cpu object
early, initialize it. This means moving some cpu object creation and
initalization
code from machvirt_init().

>
> Actually that should be "with ARM_FEATURE_V7 and not
> ARM_FEATURE_MPU", or we'll break the PMSA code.
>
> Note that you'll also need to handle systems where the
> different CPUs in it disagree about the preferred target
> page size -- the xlnx-ep108 board can have both
> Cortex-A53 (prefers 4K) and Cortex-R5 (prefers 1K) CPUs in it.
> "Use the smallest value required by any CPU on the board"
> is probably the best approach.

How -cpu options are passed for xlnx-ep108 board in qemu command?.

>
> thanks
> -- PMM
Peter Maydell June 14, 2016, 11:36 a.m. UTC | #2
On 14 June 2016 at 12:14, Vijay Kilari <vijay.kilari@gmail.com> wrote:
> On Mon, Jun 13, 2016 at 3:40 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> On 13 June 2016 at 10:43, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> On 13 June 2016 at 10:08,  <vijayak@caviumnetworks.com> wrote:
>>>> +/*
>>>> + * Holds TARGET_AARCH_64_PAGE_BITS or TARGET_ARM_PAGE_BITS
>>>> + * based on the the cpu type emulated at runtime.
>>>> + */
>>>> +static uint32_t target_page_bits;
>>>
>>> The CPU page size is not specific to the 'virt' board, so this
>>> is the wrong place to do this. You should identify the
>>> page size in arm_cpu_realizefn() based on the set of feature
>>> bits the CPU has: anything with ARM_FEATURE_V7 has a 4K page
>>> table (this includes a lot of 32-bit CPUs).
>
>   cpu_init and cpu_realizefn() of required cpu model is called in
> machvirt_init(),
> which is quite late in the initialization sequence.
> The cpu_exec_init_all() which calls memory_map_init() is called very
> early stage,
> is where TARGET_PAGE_BITS information is required.
>
> In order to get feature information of CPU early, one option is to
> create cpu object
> early, initialize it. This means moving some cpu object creation and
> initalization
> code from machvirt_init().

It would be better to delay the point at which we allocate
the data structures which care about page size, rather than
moving init of the CPU earlier.

Also we should consider what happens if we have decided
the page size is X, and then a CPU is hotplugged which
requires a page size Y where Y < X.

>> Actually that should be "with ARM_FEATURE_V7 and not
>> ARM_FEATURE_MPU", or we'll break the PMSA code.
>>
>> Note that you'll also need to handle systems where the
>> different CPUs in it disagree about the preferred target
>> page size -- the xlnx-ep108 board can have both
>> Cortex-A53 (prefers 4K) and Cortex-R5 (prefers 1K) CPUs in it.
>> "Use the smallest value required by any CPU on the board"
>> is probably the best approach.
>
> How -cpu options are passed for xlnx-ep108 board in qemu command?

They aren't -- you always get the cpus the board has in real h/w.

thanks
-- PMM
Richard Henderson June 16, 2016, 7:42 p.m. UTC | #3
On 06/14/2016 04:36 AM, Peter Maydell wrote:
> It would be better to delay the point at which we allocate
> the data structures which care about page size, rather than
> moving init of the CPU earlier.

It would be *best* if we could re-initialize and re-allocate these data
structures so that we can follow the current page size as it changes.

Yes, this might require flushing just about everything, but it's the kind of
thing that's likely to happen only at system startup.  After that, everything
benefits from having the correct (larger) page size.

> Also we should consider what happens if we have decided
> the page size is X, and then a CPU is hotplugged which
> requires a page size Y where Y < X.

Is that a real possibility?  Or trivially true because the new cpu has yet to
be initialized by the OS to use the regular OS page size.


r~
Vijay Kilari June 17, 2016, 10:20 a.m. UTC | #4
On Fri, Jun 17, 2016 at 1:12 AM, Richard Henderson <rth@twiddle.net> wrote:
> On 06/14/2016 04:36 AM, Peter Maydell wrote:
>> It would be better to delay the point at which we allocate
>> the data structures which care about page size, rather than
>> moving init of the CPU earlier.
>
> It would be *best* if we could re-initialize and re-allocate these data
> structures so that we can follow the current page size as it changes.
>
> Yes, this might require flushing just about everything, but it's the kind of
> thing that's likely to happen only at system startup.  After that, everything
> benefits from having the correct (larger) page size.

I tried shuffling the memory initialization code after cpu initialization.
but it was full mess. So could not proceed further.

However, I tried early creation cpu objects instead of doing it from
machvirt_init.
With this, initfn of the cpu model is called earlier and feature set is updated.
With that I could fetch arm architecture info. Based on this we can
choose page size.
I can send out RFC patch.

>
>> Also we should consider what happens if we have decided
>> the page size is X, and then a CPU is hotplugged which
>> requires a page size Y where Y < X.
>
> Is that a real possibility?  Or trivially true because the new cpu has yet to
> be initialized by the OS to use the regular OS page size.
>
>
> r~
Peter Maydell June 17, 2016, 10:30 a.m. UTC | #5
On 17 June 2016 at 11:20, Vijay Kilari <vijay.kilari@gmail.com> wrote:
> On Fri, Jun 17, 2016 at 1:12 AM, Richard Henderson <rth@twiddle.net> wrote:
>> On 06/14/2016 04:36 AM, Peter Maydell wrote:
>>> It would be better to delay the point at which we allocate
>>> the data structures which care about page size, rather than
>>> moving init of the CPU earlier.
>>
>> It would be *best* if we could re-initialize and re-allocate these data
>> structures so that we can follow the current page size as it changes.
>>
>> Yes, this might require flushing just about everything, but it's the kind of
>> thing that's likely to happen only at system startup.  After that, everything
>> benefits from having the correct (larger) page size.
>
> I tried shuffling the memory initialization code after cpu initialization.
> but it was full mess. So could not proceed further.
>
> However, I tried early creation cpu objects instead of doing it from
> machvirt_init.
> With this, initfn of the cpu model is called earlier and feature set is updated.
> With that I could fetch arm architecture info. Based on this we can
> choose page size.

This won't work, because machvirt_init needs to be able to specify
properties of the CPU. I think we need to solve the issues with
dynamically reinitializing and reallocating the data structures,
as rth suggests.

thanks
-- PMM
Vijay Kilari June 17, 2016, 10:39 a.m. UTC | #6
On Fri, Jun 17, 2016 at 4:00 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 17 June 2016 at 11:20, Vijay Kilari <vijay.kilari@gmail.com> wrote:
>> On Fri, Jun 17, 2016 at 1:12 AM, Richard Henderson <rth@twiddle.net> wrote:
>>> On 06/14/2016 04:36 AM, Peter Maydell wrote:
>>>> It would be better to delay the point at which we allocate
>>>> the data structures which care about page size, rather than
>>>> moving init of the CPU earlier.
>>>
>>> It would be *best* if we could re-initialize and re-allocate these data
>>> structures so that we can follow the current page size as it changes.
>>>
>>> Yes, this might require flushing just about everything, but it's the kind of
>>> thing that's likely to happen only at system startup.  After that, everything
>>> benefits from having the correct (larger) page size.
>>
>> I tried shuffling the memory initialization code after cpu initialization.
>> but it was full mess. So could not proceed further.
>>
>> However, I tried early creation cpu objects instead of doing it from
>> machvirt_init.
>> With this, initfn of the cpu model is called earlier and feature set is updated.
>> With that I could fetch arm architecture info. Based on this we can
>> choose page size.
>
> This won't work, because machvirt_init needs to be able to specify
> properties of the CPU. I think we need to solve the issues with
> dynamically reinitializing and reallocating the data structures,
> as rth suggests.

In early init, only cpu object is created and does not specify
properties of the CPU.
machvirt_init will reuse already created cpu object and specify
properties of the CPU.

Regards
Vijay
Peter Maydell June 17, 2016, 10:42 a.m. UTC | #7
On 17 June 2016 at 11:39, Vijay Kilari <vijay.kilari@gmail.com> wrote:
> On Fri, Jun 17, 2016 at 4:00 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> This won't work, because machvirt_init needs to be able to specify
>> properties of the CPU. I think we need to solve the issues with
>> dynamically reinitializing and reallocating the data structures,
>> as rth suggests.
>
> In early init, only cpu object is created and does not specify
> properties of the CPU.
> machvirt_init will reuse already created cpu object and specify
> properties of the CPU.

You don't know how many CPUs to create, though, and some of the
properties defined by the machine init function include those
which tell you whether the page size should be 1K or 4K.

thanks
-- PMM
Peter Maydell June 21, 2016, 11:55 a.m. UTC | #8
On 17 June 2016 at 11:20, Vijay Kilari <vijay.kilari@gmail.com> wrote:
> On Fri, Jun 17, 2016 at 1:12 AM, Richard Henderson <rth@twiddle.net> wrote:
>> On 06/14/2016 04:36 AM, Peter Maydell wrote:
>>> It would be better to delay the point at which we allocate
>>> the data structures which care about page size, rather than
>>> moving init of the CPU earlier.
>>
>> It would be *best* if we could re-initialize and re-allocate these data
>> structures so that we can follow the current page size as it changes.
>>
>> Yes, this might require flushing just about everything, but it's the kind of
>> thing that's likely to happen only at system startup.  After that, everything
>> benefits from having the correct (larger) page size.
>
> I tried shuffling the memory initialization code after cpu initialization.
> but it was full mess. So could not proceed further.
>
> However, I tried early creation cpu objects instead of doing it from
> machvirt_init.

I'm going to have a go at this and see if I can come up with a
nice looking arrangement. Will try to send some patches by the
end of the week...

thanks
-- PMM

Patch
diff mbox

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 73113cf..37aab33 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -90,6 +90,12 @@  typedef struct {
     int32_t gic_version;
 } VirtMachineState;
 
+/*
+ * Holds TARGET_AARCH_64_PAGE_BITS or TARGET_ARM_PAGE_BITS
+ * based on the the cpu type emulated at runtime.
+ */
+static uint32_t target_page_bits;
+
 #define TYPE_VIRT_MACHINE   MACHINE_TYPE_NAME("virt")
 #define VIRT_MACHINE(obj) \
     OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
@@ -1099,6 +1105,47 @@  void virt_guest_info_machine_done(Notifier *notifier, void *data)
     virt_build_smbios(&guest_info_state->info);
 }
 
+static void machvirt_update_target_page_size(const char *cpu_model)
+{
+    char **cpustr;
+    ObjectClass *oc, *parent;
+    const char *parent_type;
+    /* Set to default page size */
+    uint32_t page_bits = TARGET_ARM_PAGE_BITS;
+
+    cpustr = g_strsplit(cpu_model, ",", 2);
+    if (!strcmp(cpustr[0], "host")) {
+#ifdef __aarch64__
+        page_bits = TARGET_AARCH64_PAGE_BITS;
+#else
+        page_bits = TARGET_ARM_PAGE_BITS;
+#endif
+        goto out;
+    }
+
+    oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
+    if (!oc) {
+        oc = cpu_class_by_name(TYPE_AARCH64_CPU, cpustr[0]);
+        if (!oc)
+           goto out;
+    }
+
+    parent = object_class_get_parent(oc);
+    if (!parent)
+       goto out;
+
+    parent_type = object_class_get_name(parent);
+    if (!strcmp(parent_type, TYPE_AARCH64_CPU))
+       page_bits = TARGET_AARCH64_PAGE_BITS;
+out:
+    target_page_bits = page_bits;
+}
+
+uint32_t arm_get_target_page_bits(void)
+{
+    return target_page_bits;
+}
+
 static void machvirt_init(MachineState *machine)
 {
     VirtMachineState *vms = VIRT_MACHINE(machine);
@@ -1376,6 +1423,7 @@  static void virt_machine_class_init(ObjectClass *oc, void *data)
     mc->block_default_type = IF_VIRTIO;
     mc->no_cdrom = 1;
     mc->pci_allow_0_address = true;
+    mc->update_target_page_size = machvirt_update_target_page_size;
 }
 
 static const TypeInfo virt_machine_info = {
diff --git a/include/hw/boards.h b/include/hw/boards.h
index d268bd0..1e8abb6 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -124,6 +124,7 @@  struct MachineClass {
                                            DeviceState *dev);
     unsigned (*cpu_index_to_socket_id)(unsigned cpu_index);
     CPUArchIdList *(*possible_cpu_arch_ids)(MachineState *machine);
+    void (*update_target_page_size)(const char *cpu_model);
 };
 
 /**
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 17d8051..f593620 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1743,14 +1743,16 @@  bool write_cpustate_to_list(ARMCPU *cpu);
 #define ARM_CPUID_TI915T      0x54029152
 #define ARM_CPUID_TI925T      0x54029252
 
-#if defined(CONFIG_USER_ONLY)
-#define TARGET_PAGE_BITS 12
-#else
+uint32_t arm_get_target_page_bits(void);
+/*
+ * Minimum page size for aarch64 is 4K
+ */
+#define TARGET_AARCH64_PAGE_BITS 12
 /* The ARM MMU allows 1k pages.  */
 /* ??? Linux doesn't actually use these, and they're deprecated in recent
    architecture revisions.  Maybe a configure option to disable them.  */
-#define TARGET_PAGE_BITS 10
-#endif
+#define TARGET_ARM_PAGE_BITS 10
+#define TARGET_PAGE_BITS arm_get_target_page_bits()
 
 #if defined(TARGET_AARCH64)
 #  define TARGET_PHYS_ADDR_SPACE_BITS 48
diff --git a/vl.c b/vl.c
index b6da265..a317cf1 100644
--- a/vl.c
+++ b/vl.c
@@ -4045,6 +4045,13 @@  int main(int argc, char **argv, char **envp)
     object_property_add_child(object_get_root(), "machine",
                               OBJECT(current_machine), &error_abort);
 
+    /*
+     * Compute target page size dynamically if arch supports
+     * multiple page sizes. Ex: ARM
+     */
+    if (machine_class->update_target_page_size)
+        machine_class->update_target_page_size(cpu_model);
+
     init_l1_page_table_param();
 
     cpu_exec_init_all();