Skip to content

Conversation

@Copper280z
Copy link
Contributor

ch32v chips with v3 or v4 cpus support both machine mode and user mode, this sets the cpu to stay in machine mode after it leaves the startup function. In user mode attempts to enable, disable, read, etc CSRs cause the chip to hang.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

🔍 Lint Results

@Grazfather
Copy link
Collaborator

since we literally have a guard on the cpu on the line above it, we probably should for this bit as well. Does that bit even exist for ev2/3? I guess CI will tell us.

@Copper280z
Copy link
Contributor Author

Copper280z commented Jan 18, 2026

All of the wch qingke cpus support setting mpp = 0x3

from v2 manual
The Machine mode has the highest privileges, and the program can access all Control and Status Registers (CSR) in this mode, and there is no Physical Memory Protection (PMP) unit designed inside QingKe V2. The MPP bit in the CSR register mstatus (Machine Mode Status Register) is 0b11 by default, i.e. it is always running in Machine mode.

v3:
The power-up default is in machine mode, when the execution of mret (Machine mode return instruction) returns, according to the CSR register mstatus (Machine mode status register) in the MPP bit, if MPP = 0b00, then exit the Machine mode into the User mode, MPP = 0b11, then continue to retain the Machine mode.

v4:
QingKe V4 microprocessor supports Machine mode and User mode. If you need to make the microprocessor work only in Machine mode, you can set the MPP to 0x3 in the initialization of the startup file, i.e. after returning, it will always remain in Machine mode.

The mpp bit sets the mode that the cpu will go to when the mret instruction is executed, so I think when user mode isn't supported the value defaults to (and is fixed at) 0x3 (like in the v2 cpus). I believe on v3 and v4 cpus this means the user can elect to switch to user mode whenever they want by setting the bit to 0x0 and executing an mret.

@Grazfather
Copy link
Collaborator

I forget which issue this was solving. The cpu was barking at you for running some thing in a different mode, right? Can you add a tiny comment explaining why this is needed?

Added comments explaining the machine mode setting for interrupts.
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

🔍 Lint Results

@Copper280z
Copy link
Contributor Author

CPU hard faults if you try to enable or disable interrupts when in user mode, additionally you can't switch or read modes when in user mode. We should be letting the user decide when to change privilege levels, we don't need to manage that.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

🔍 Lint Results

@Grazfather
Copy link
Collaborator

OK cool. And how/when does it switch modes as we have it?

@Copper280z
Copy link
Contributor Author

As soon as an mret instruction is executed from machine mode the current level is switched to the value in mpp. Looking at a dump I only see mret instructions at the end of interrupt handlers, so I presume it stays in machine mode from the start until an interrupt handler completes, then switches to the mode set in mpp. I haven't actually done any testing to verify this on hardware though.

I have verified that with mpp set to machine mode I can enable/disable interrupts from inside of main, but with mpp set to zero (previous setting) the chip hard faults when I try.

@Grazfather
Copy link
Collaborator

Grazfather commented Jan 20, 2026

I imagine that machine mode is automatically entered when an isr is entered, though I would expect the mode to be saved and restored, i.e. if we never left machine mode, I would think that entering the ISR would (re) enter machine mode, and then mret would return us to that mode.

So that's still a mystery, but I'll look into it.

zig fmt and we should be good to go.

@Grazfather Grazfather changed the title Set machine mode bit in startup logic. ch32v: Set machine mode bit in startup logic Jan 20, 2026
Comment on lines +266 to +269
// We set machine mode (0x3) so the user can enable/disable interrupts
// or manage machine/user mode themselves.
// With mpp at 0 the users main function is forced to run at user level.
// Also enable interrupts.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it would be more clear to explain that mpp = 3 means that the mret will keep us in machine mode.

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