Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libsel4vm, vgic: generate dist and cpu values #83

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

chrisguikema
Copy link
Contributor

This commit adds an "fdt_ori" and "gic_node" parameter to the vm struct, which allows the library to find the GIC_DIST and GIC_CPU register addresses required for emulating the vgic.

@chrisguikema
Copy link
Contributor Author

This isn't perfect, and requires a change in camkes-vm to set the path and pointers. It could also use a check to handle address-cells and size-cells properly. I just wanted to put it out for review and discussion, and to show its possible to grab the values from the device tree. I'm open to other and better ways to do this.

@chrisguikema
Copy link
Contributor Author

Test with: seL4/camkes-vm#52

@@ -58,7 +58,8 @@
#include "gicv2.h"
#include "vdist.h"


static uintptr_t vcpu_addr;
static uintptr_t cpu_addr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid these global variables and change the code flow to pass this pas parameter? We could also wrap al this in a struct for a context and then pass a pointer around. I think I have tried something in #69

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, yes, it feels like this could be reworked to avoid the globals. Since you've already done some work with that in the PR you referenced, do you want to handle that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd try to rebase my PR on this then.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference would be to avoid adding the globals in this PR. The vgic_dist_device struct is intended for storing these exact mapping addresses and so they should be added there. As they aren't the same for the gic_v3, it's fine to create a different vgic_dist_device that's specialized to the gicv2 as it's private to this compilation unit.


/* Contants for getting registers from Device Tree */
#define NUM_GIC_REGS 4
#define GIC_DIST_ENTRY 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should get a more verbose comment. How much of a device tree standard is this actually or is it just what everybody seems to use. I think it might be better to inline these values and not expose any constants. Then a comment there can explain the the magic values come from. We can factor this out when these constants are to be somewhere. If we provide defines here, we names must be much more specific to avoid conflicts or get confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a link with the standard. Its not just what everyone seems to use.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rename this to e.g. NUM_FDT_GIC_REGS and FDT_GIC_REG_IDX_<DIST|CPU|VCPU_CNTR|VCPU>? So we have names that are a bit less ambiguous and clearly state this is device tree related

This commit adds an "fdt_ori" and "gic_node" parameter to the vm struct,
which allows the library to find the gic register addresses required for
emulating the vgic.

Signed-off-by: Chris Guikema <[email protected]>
@@ -236,6 +297,9 @@ static vm_frame_t vgic_vcpu_iterator(uintptr_t addr, void *cookie)
*/
int vm_install_vgic(vm_t *vm)
{
/* Read device tree to find memory regions */
gic_get_registers_from_fdt(vm, &dist_addr, &cpu_addr, &vcpu_addr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably check and return the error here if the GIC can't be found in the FDT.

Comment on lines +207 to +208
char *gic_path;
void *fdt_ori;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As these are both Arm specific, they should be added to the vm_arch struct.

@kent-mcleod
Copy link
Member

This commit adds an "fdt_ori" and "gic_node" parameter to the vm struct,

This isn't an insignificant design change to the vm_t struct. If this is something that we should add, then it probably needs to be properly integrated into the rest of the library with proper initialization functions. If it's just an initial way to prototype associating a device tree with a guest for virtual devices to more easily find configuration information it should probably still have a proper way of installing it. (This would also allow the camkes-vm layer to more explicitly generate the fdt and then install it into the guest for the rest of the guest devices to use). Also, how is this expected to work with guests that don't use an FDT but want to use virtual devices that do use an fdt?

@kent-mcleod
Copy link
Member

One more comment, if this isn't something that we want to tackle now, then maybe a smaller-impact change would be choosing to have device specific interfaces for vm_install_vgic() that could take the configuration arguments needed, allowing the caller (camkes-vm) to do the device tree parsing and pass in the address ranges via the newer vm_install_vgic() interface.

@chrisguikema
Copy link
Contributor Author

Thanks for the comments, Kent. This was something that I just put together based on the comments on using the GIC path to find the phandle. Basically, its more of a proof of concept. If you want to separate this commit out into a draft, so we can figure out the best way to do this properly while merging in the gic phandle, I'm okay with that approach.

@chrisguikema
Copy link
Contributor Author

Also, how is this expected to work with guests that don't use an FDT but want to use virtual devices that do use an fdt?

Doesn't the kernel pass an FDT to each VMM regardless of whether the guest needs to use the FDT? So I guess there's a disconnect between the guest's device tree, and the FDT used to describe the hardware resources of the system.

Would it be possible to just use the ps_io_ops interface to get the FDT? Then search for the node with the arm,gic-400 string?

@kent-mcleod
Copy link
Member

Doesn't the kernel pass an FDT to each VMM regardless of whether the guest needs to use the FDT? So I guess there's a disconnect between the guest's device tree, and the FDT used to describe the hardware resources of the system.

In CAmkES, the DTB is given to the component if it has the dtb property set in its configuration, so it's not always expected to be present. It would be reasonable for a VM component to load a file from the fileserver component and not need the system DTB given to the component at all.

I think one question that needs to be decided is whether device trees are a concept that libsel4vm should know about and have a mechanism for managing a device tree and installing it into the guest. It seems to me that this is better suited for libsel4vmmplatsupport?

@kent-mcleod
Copy link
Member

Thanks for the comments, Kent. This was something that I just put together based on the comments on using the GIC path to find the phandle

Yea, I'm not trying to say you shouldn't have proposed the changes, just pointing out that adding a way for vm devices to query a device tree associated with the guest is something that would be quite useful to many more devices than just the vgic, so we should consider the wider implications. EG, should this device tree be the system device tree, or the one that the guest sees? Are devices allowed to mutate it? If it's using a libfdt compatible object, then we could allow devices to install nodes in during their own initialization and have an explicit finalization step which is what Qemu does.

}

int address_cells = fdt_address_cells(vm->fdt_ori, parent_offset);
int size_cells = fdt_address_cells(vm->fdt_ori, parent_offset);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int size_cells = fdt_address_cells(vm->fdt_ori, parent_offset);
int size_cells = fdt_size_cells(vm->fdt_ori, parent_offset);

*/
uint64_t gic_regs[NUM_GIC_REGS];
int calculated_size = size_cells * address_cells * NUM_GIC_REGS * sizeof(uint32_t);
int reg_offset = calculated_size / NUM_GIC_REGS;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int reg_offset = calculated_size / NUM_GIC_REGS;
int reg_size = calculated_size / NUM_GIC_REGS;

This is the size of one value, not the offset

}

for (int i = 0; i < NUM_GIC_REGS; i++) {
memcpy(&gic_regs[i], (void *)(c->data + (i * reg_offset)), sizeof(uint32_t) * address_cells);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this has an implicit assumption that address_cells is 2 and address_cells is 1. That may hold practically, so we could simply reject anything else for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work with any case of address/size being 1 or 2.

Copy link
Member

@axel-h axel-h Oct 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, extracting the value works for 1 or 2. But we need uint64_t gic_regs[NUM_GIC_REGS] = {0}; then to ensure the array is filled with zeros. Otherwise we might just copy 32 bits and the other 32-bit are random data,

* 4th reg entry: GIC Virtual CPU Interface Register
*/
uint64_t gic_regs[NUM_GIC_REGS];
int calculated_size = size_cells * address_cells * NUM_GIC_REGS * sizeof(uint32_t);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int calculated_size = size_cells * address_cells * NUM_GIC_REGS * sizeof(uint32_t);
int calculated_size = (address_cells + size_cells) * NUM_GIC_REGS * sizeof(uint32_t);

We have one address cell followed by a size cell for each element. This just work because 2 * 2 happens to equal 2 + 2

@chrisguikema
Copy link
Contributor Author

I'm going to mark this as a draft, since like Kent mentioned, in order to do this, you need access to the FDT in the libraries, which is a bigger design choice than just this PR. I think this would still be useful as a reference for getting the GIC information out of the device tree once the FDT is available.

@chrisguikema chrisguikema marked this pull request as draft October 27, 2022 23:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants