Add iommu support for capdl initializer and sel4 crate#337
Conversation
|
Are there any updates necessary for the code, model, and spec/docs in the capDL repo? https://github.com/seL4/capdl/ (We don't want the feature set of these tools to diverge, the whole point of capDL is to provide the same interface to multiple backends). |
87f4ad3 to
70bb0a9
Compare
| // Reuse sel4::vspace_levels::step_bits | ||
| let ioaddr = ioaddr + (usize::from(i) << sel4::vspace_levels::step_bits(level)); |
There was a problem hiding this comment.
Is this actually correct? Do the IO PT level bits always match the SW PT level bits?
| self.orig_cap::<cap_type::IOPageTable>(cap.object) | ||
| .io_page_table_map(iospace, ioaddr)?; | ||
| let obj = self.object_as::<object::ArchivedIOPageTable>(cap.object); | ||
| self.init_iospace(iospace, level + 1, ioaddr, obj)?; |
There was a problem hiding this comment.
This seems inefficient, to set up a page table you're going to do a full walk from level 0 -> end for each frame. Surely a level-order walk of the tree makes more sense here?
Also, am I blind, or does the existing capDL loader C version not support IOMMU at all? It has IOPT in the specification but I can't see any kind of equivalent for IOMMU in there? I was trying to see how it did it.
There was a problem hiding this comment.
I am not sure whether there is a huge difference between breadth-first search(I guess BFS is what you mean by level-order walk?) and depth-first search(what is implemented here) when recursion is used. Depth-first search is easier to implement, and we know the maximum number of recursions (since the maximum page table level is four). DFS is also used in init_vspace(). There might be a way to optimize the process further(using iterative traversal with a parent pointer so we do not need to use recursion), but it would be better to leave optimization to a different PR.
And yes, I think the C version of the capdl loader does not support IOMMU.
There was a problem hiding this comment.
I believe I slightly misunderstood the code here: the object is changing (rather than just the new value being an argument), so there's some subtle control flow. Presumably the spec containing all the objects is already in the order so that you can walk the tree once in order.
(It's not a DFS vs BFS thing here at all: we aren't doing a search. A level-order walk is it's own thing, separate to DFS vs BFS. But actually, a preorder walk like you do is fine).
There was a problem hiding this comment.
And yes, I think the C version of the capdl loader does not support IOMMU.
Yes, it only has some code for SMMU, but nothing for VT-d.
| pub pci_bus: u8, | ||
| pub pci_device: u8, | ||
| pub dev_func: u8, | ||
| pub domain_id: u16, |
There was a problem hiding this comment.
These are x86-specific. I don't know how rust-seL4 does this but they should be as part of some kind of arch-specific data.
| match &entry.cap { | ||
| ArchivedCap::IOPageTable(cap) => IOPageTableEntry::IOPageTable(cap), | ||
| ArchivedCap::Frame(cap) => IOPageTableEntry::Frame(cap), | ||
| _ => panic!(), |
There was a problem hiding this comment.
panic! without a message seems silly.
maybe:
| _ => panic!(), | |
| _ => unreachable!("non-IO-PT cap in IO-PT"), |
| (IO_PORT_CONTROL, IOPortControl, seL4_CapIOPortControl), | ||
| #[cfg(false)] // TODO | ||
| (IO_SPACE, Null, seL4_CapIOSpace), | ||
| #[sel4_cfg(all(ARCH_X86_64, IOMMU))] // TODO |
| pub is_root: bool, | ||
| pub level: Option<u8>, |
There was a problem hiding this comment.
Why is this Option<u8>? Why would a page table not have a level.
Also, isn't is_root <=> (level == 0)?
| const DEVICE_ID_SHIFT: u16 = 3; | ||
| const PCI_ID_SHIFT: u16 = DEVICE_ID_SHIFT + 5; | ||
| const DOMAIN_ID_SHIFT: u16 = PCI_ID_SHIFT + 8; |
There was a problem hiding this comment.
Is this arbitrary or derived from something?
| panic!( | ||
| "The hardware does not support three level VTD Page Table, but {} level is provided", | ||
| level |
There was a problem hiding this comment.
| panic!( | |
| "The hardware does not support three level VTD Page Table, but {} level is provided", | |
| level | |
| panic!( | |
| "The hardware page table has {level} levels which we do not support", | |
| level |
| // There is no way to determine the level of io page table before actually running it on hardware | ||
| // So there is no way to allocate the correct number of slots | ||
| // Thus we default to assume the four level page table structure | ||
| match level { | ||
| // If three level page table is chosen by seL4, we skip mapping the root page table in | ||
| // Current approach wastes the memory root page table object | ||
| VTD_THREE_LEVEL_PT => { | ||
| self.init_iospace(iospace_cap, root_level, 0, root_pt)?; | ||
| } | ||
| VTD_FOUR_LEVEL_PT => { | ||
| self.orig_cap::<cap_type::IOPageTable>(iospace.slots[0].cap.obj()) | ||
| .io_page_table_map(iospace_cap, 0)?; | ||
| self.init_iospace(iospace_cap, root_level, 0, root_pt)?; |
There was a problem hiding this comment.
I'm confused. Assuming the four-level page table structure seems like it wouldn't work.
Wouldn't it make more sense to assume the three-level page table structure, and just have an extra top-level table for the four-level page table structure?
That way, when you have 3 levels, you use the 3 levels, but when you have 4, you basically just use 3 levels, and have a top-level page table that just maps the lower 3 in the lowest entry, say.
(Also, these sentences need to be reworked, the grammar is awful and doesn't make any sense)
| let badge = ((iospace.pci_bus as u64) << PCI_ID_SHIFT) | ||
| + ((iospace.pci_device as u64) << DEVICE_ID_SHIFT) | ||
| + iospace.dev_func as u64 | ||
| + ((u16::from(iospace.domain_id) as u64) << DOMAIN_ID_SHIFT) as u64; |
The spec in the capDL tool seems to support an 'IOPT' and an 'IODevice' (not in this PR at all? it seems to contain the pci bus + domain that the IOPT does here...), but we can't see any implementation of say |
Signed-off-by: Cheng Li <lichengchaoreng@gmail.com>
Signed-off-by: Cheng Li <lichengchaoreng@gmail.com>
Signed-off-by: Cheng Li <lichengchaoreng@gmail.com>
Signed-off-by: Cheng Li <lichengchaoreng@gmail.com>
Signed-off-by: Cheng Li <lichengchaoreng@gmail.com>
Signed-off-by: Cheng Li <lichengchaoreng@gmail.com>
Signed-off-by: Cheng Li <lichengchaoreng@gmail.com>
Signed-off-by: Cheng Li <lichengchaoreng@gmail.com>
Signed-off-by: Cheng Li <lichengchaoreng@gmail.com> Fix typo. Co-authored-by: Gerwin Klein <gerwin.klein@proofcraft.systems> Signed-off-by: Cheng Li <53856318+Cheng-Li1@users.noreply.github.com> Remove unnecessary debug prints. Signed-off-by: Cheng Li <lichengchaoreng@gmail.com>
70bb0a9 to
3b4a5ff
Compare
This pull request adds functionalities to the capdl initializer and the sel4 crate.
Added functionalities include:
Tests done:
Blk example with iommu feature enabled on x86 qemu and hardware(vb-105).