Thanks to visit codestin.com
Credit goes to github.com

Skip to content

add uc_mem_read_virtual #2121

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

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from

Conversation

PhilippTakacs
Copy link
Contributor

New api to read from a vaddr. When using the MMU it's useful to direct read from virtual addresses.

Needs some tests.

I'm not sure about a write_virtual() function. Could also be useful, but is a lot more complex to implement, because of snapshots.

A virtual to physical translate function would be also nice, but currently the tlb_fill() function has no probe argument.

@wtdcode
Copy link
Member

wtdcode commented Feb 26, 2025

I have dreamed of this API for quite a while because uc_mem_read/write only deals with physical addresses and super inconvenient with MMU. Thanks for prototyping!

It would be cool to even have translation API as suggested, but many QEMU MMU fill implementation has serious side effects.

Why does "write_vritual" not work with snapshots? What's the current uc_mem_write behavior? Maybe just keep the same behavior.

Lastly please target dev branch instead (for 2.2.0), the master branch is preparing for 2.1.3 and this change can't go into 2.1.3 obviously =).

@PhilippTakacs PhilippTakacs changed the base branch from master to dev February 26, 2025 09:02
@PhilippTakacs
Copy link
Contributor Author

Lastly please target dev

Sorry my bad.

Why does "write_vritual" not work with snapshots?

It would work, it's just more code and maybe duplicated code, because of the snapshot handling. With a simple virtual to physical API it would be more simple.

It would be cool to even have translation API as suggested, but many QEMU MMU fill implementation has serious side effects.

In the current QEMU version is tlb_fill() replaced by tlb_fill_align(). This function has a probe parameter, which would be the key for a virtual to physical translation API.

@wtdcode
Copy link
Member

wtdcode commented Feb 26, 2025

CI is failing at this moment and I lack time to fix it. Will do later this week.

@PhilippTakacs
Copy link
Contributor Author

CI is failing at this moment

There were also some bugs in my changes which causes the CI to fail.

but many QEMU MMU fill implementation has serious side effects

I have added a testcase (on x86) and read the MMU implementations to verify this would work. As far as I see it works on every MMU expect for SPARC. Would it be OK to just document this issue?

About the write: Would it be OK to just have a read implementation at the moment?

@PhilippTakacs
Copy link
Contributor Author

What's the current uc_mem_write behavior? Maybe just keep the same behavior.

Currently uc_mem_write does COW when memory snapshots are enabled. I would also expect this from a uc_mem_write_virtual function.

The problem is: This is quite complicated code and with the given tlb_vaddr_to_host it would be more complicated to implement for a uc_mem_write_virtual function. Given the fact that I have two times missed some cases in the uc_mem_write function, I would try to avoid implement this without a simple way to translate virtual to physical addresses.

@wtdcode
Copy link
Member

wtdcode commented Feb 27, 2025

I just revisited the tlb_vaddr_to_host and noticed the probe parameter, which should avoid the side effects. Sorry I forget the functionality here yesterday without further checking the code. I also saw documents in SPARC and that's okay we can document it and return something like UC_ERR_ARG.

Btw the tlb_fill function indeed has the probe argument, I assume we can expose the translation API directly? Maybe just expose tlb_vaddr_to_host? In this case, we can avoid code duplication by using tlb_vaddr_to_host to convert vaddr to phyaddr and use uc_mem_read/write to do memory operations.

typedef struct CPUClass {
    // ...
    bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
                     MMUAccessType access_type, int mmu_idx,
                     bool probe, uintptr_t retaddr);
    // ...
}

@PhilippTakacs PhilippTakacs marked this pull request as ready for review March 7, 2025 12:07
@PhilippTakacs PhilippTakacs force-pushed the read-virtuall branch 2 times, most recently from be29636 to 013877e Compare March 7, 2025 14:48
@PhilippTakacs
Copy link
Contributor Author

So I have added a uc_virtual_to_physical function. The problem I had was: I wanted to (ab)use a function and only add some code to extract the physical address (like I have done with tlb_vaddr_to_host). I have now just added a tlb_vaddr_to_paddr.

I'll try to implement a uc_mem_write_virtual next week.

@PhilippTakacs
Copy link
Contributor Author

The uc_mem_write_virtual function should work, but I haven't had time to test it. I'll write some tests and a bit more documentation. But I have not that much time at the moment.

@PhilippTakacs
Copy link
Contributor Author

@wtdcode write_virtual is also there and tested.

@wtdcode
Copy link
Member

wtdcode commented Apr 2, 2025

@wtdcode write_virtual is also there and tested.

Thanks for the brilliant work. I can review only a bit later as I'm having an urgent deadline on April 10.

uc.c Outdated
@@ -773,6 +773,136 @@ static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)
return (count == size);
}

uc_err uc_virtual_to_physical(uc_engine *uc, uint64_t address, uc_prot prot,
Copy link
Member

Choose a reason for hiding this comment

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

Do we really need prot here? Is there possible that different protections lead to different physical addresses? If the protection is only used for access check, is it trivial to skip such checks and only "translate" addresses for whatever protection? If that is not trivial, we can keep it as it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The prot is to have the mmu access rights checked. You might want to check if the corresponding address is write accessible. To check this you can call uc_virtual_to_physical(uc, addr, UC_PROT_WRITE, &paddr) and check the return code.

Also it's necessary to have prot for a potential tlb_fill call.

Copy link
Member

Choose a reason for hiding this comment

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

But for “translation” itself, it has nothing to do with permissions, right? My point is that, from the semantics of the API, protection seems not necessary here though I understand tlb_fill requires this.

Copy link
Member

@wtdcode wtdcode Apr 7, 2025

Choose a reason for hiding this comment

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

For example, assume a memory region located at vaddr 0x2000 with paddr 0x1000 but with PROT_NONE, i.e. no one can access it. But from the perspective of emulator, the mapping is there exactly 0x2000 -> 0x1000 and we should be able to translate addresses no matter the protections.

However, I do understand that qemu code might not design for such cases. Therefore, if you think it is not feasible to translate addresses without protection, we can leave it as it is but with better docs.

@wtdcode
Copy link
Member

wtdcode commented Apr 7, 2025

Interrupted by some other things. Will continue my review a bit later.

uc.c Outdated
}

UNICORN_EXPORT
uc_err uc_mem_read_virtual(uc_engine *uc, uint64_t address, uc_prot prot,
Copy link
Member

@wtdcode wtdcode Apr 7, 2025

Choose a reason for hiding this comment

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

I just come up with alternative names: uc_vmem_read/write. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good, I'll adopt this.

* Only page aligned access is allowed,
* because tlb_fill() might change the mappings
*/
assert((addr & TARGET_PAGE_MASK) == ((addr + len - 1) & TARGET_PAGE_MASK));
Copy link
Member

Choose a reason for hiding this comment

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

this shall return UC_ERR_ARG or more appropriate errors instead of assertions.

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 use asserts for potential unicorn bugs and return errors for user bugs. This internal function is designed to only be called within one page. This is implemented in uc_mem_read_virtual. Returning an error might cause a user to believe it's a bug in there code.

I'll write a comment about this.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, but addr is from user inputs, no? uc_mem_read_virtual seems using it directly? My concern is that this might cause the assertion too easy to trigger.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes addr is (more or less) from user input, but len is enforced to be maximum the rest of the page. What this assert checks is that the full len is on the same page. So the assert is in exactly what uc_mem_read_virtual enforces. When we add other callers, they must handle this internal api the same way.

So I don't see how this assert triggers to early.

for detailed error).
*/
UNICORN_EXPORT
uc_err uc_virtual_to_physical(uc_engine *uc, uint64_t address, uint32_t prot,
Copy link
Member

Choose a reason for hiding this comment

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

I would suggest uc_vmem_translate. What do you think?


@uc: handle returned by uc_open()
@address: starting virtual memory address of bytes to get.
@prot: The access type for the tlb lookup
Copy link
Member

Choose a reason for hiding this comment

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

As reviewed previously, if @prot is essential, please document a bit more here. Like how different protections could affect the behavior. For example, what does uc_mem_read_virtual with prot = UC_PROT_WRITE imply?

New api to read from, translate, or write to a virtual address. When
using the MMU it's useful to direct use the virtual addresses.
@PhilippTakacs
Copy link
Contributor Author

@wtdcode is there anything missing for this getting merged?

@wtdcode
Copy link
Member

wtdcode commented Apr 30, 2025

@wtdcode is there anything missing for this getting merged?

Hello Philipp, sorry for late because I'm on academic travel. I will give another review shortly.

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.

2 participants