why processor_t::egalize_privilege(ret_t prv) returns PRV_U if (prv == PRV_HS || (prv == PRV_S && !supports_extension('S'))) - riscv

I cannot understand source code in legalize_privilege() shown below:
reg_t processor_t::legalize_privilege(reg_t prv)
{
if (!supports_extension('U'))
return PRV_M;
if (prv == PRV_HS || (prv == PRV_S && !supports_extension('S')))
return PRV_U;
//according to my understanding, HS mode actually works in Supervisor mode. So PRV_S should be returned here.
return prv;
}

PRV_HS is only used as a dummy privilege level within the simulator for CSR permission checks.
In the H-extension specification, HS-mode takes the place of S-mode (level 1).
The integer value 2 is used for PRV_HS to distinguish it from PRV_S, but that is a reserved value in the RISC-V Privileged Architecture (ISA Manual Vol. 2 § 1.2 Privilege Levels) and not used by the H-extension.
It is therefore illegal to actually set this mode. To set either HS- or S-mode, always use PRV_S.
In the same condition, you can also see that it is illegal to set S-mode if the S-extension is not supported.
Both of these cases are illegal, so the privilege level is instead forced to the lowest level, which is PRV_U.
The only use of PRV_HS is in the permission check segment of processor_t::get_csr (here), where it is used instead of PRV_S if the processor is not in a virtual state (as set by processor_t::set_virt), to permit access to Hypervisor CSRs.
This is because the CSR address encodes the minimum privilege level required for access in bits [9:8], which is defined as 10b = 2 for Hypervisor CSRs, even though there is no such distinct privilege level (ISA Manual Vol. 2 § 2.1 CSR Address Mapping Conventions).

Related

No more satisfying instances

No examples generated for my alloy model with the error message: 'No more satisfying instances' (see image attached)
I have created the following small model in Alloy:
sig System
{
subSystem : System
}
// Prevent a subsystem from directly including itself
fact noDirectInclusion
{
no s : System | s in s.subSystem
}
// Prevent a subsystem from transitivelyincluding itself
fact noTransitiveInclusion
{
no s : System | s in s.^subSystem
}
pred show {}
run show for 5
The fact 'noDirectInclusion' nicely prevents the generation of examples where a subsystem is a subsystem of itself.
I am probably missing something trivial, but When I also use the fact 'noTransitiveInclusion' there are no longer any examples generated with the error message: 'No more satisfying instances' (see image attached)
What am I missing?
What am I missing?
Try to make your graph by hand for only 2 System sigs ...
You will see that with the constraints you specified in the System sig you can only make a cycle ... You force a System to have 1 and exactly 1 subSystem, i.e. the default for a field is one. Therefore, the transitive graph can only be a cycle with a finite set of objects and that invalidates your fact.
Either make subSystem a lone or set.

device driver documentation for linux

in the book 2017 " UNIX and Linux System Administration " i've read the article below :
Modern systems manage their device files automatically. However, a few rare corner
cases may still require you to create devices manually with the mknod command.
So here’s how to do it:
mknod filename type major minor
Here, filename is the device file to be created, type is c for a character device or b
for a block device, and major and minor are the major and minor device numbers.
If you are creating a device file that refers to a driver that’s already present in your
kernel, check the documentation for the driver to find the appropriate major and
minor device numbers.
where can i find this doc and how to find Major & Minor for a device driver ???
The command cat /proc/devices shows the character and block major device numbers in use by drivers in the currently running Linux kernel, but provides no information about minor device numbers.
There is a list of pre-assigned (reserved) device numbers in the Linux kernel user's and administrator's guide: Linux allocated devices (4.x+ version). (The same list also appears in "Documentation/admin-guide/devices.txt" in the Linux kernel sources.) The list shows how minor device numbers are interpreted for each pre-assigned character and block major device number.
Some major device numbers are reserved for local or experimental use, or for dynamic assignment:
60-63 char LOCAL/EXPERIMENTAL USE
60-63 block LOCAL/EXPERIMENTAL USE
Allocated for local/experimental use. For devices not
assigned official numbers, these ranges should be
used in order to avoid conflicting with future assignments.
120-127 char LOCAL/EXPERIMENTAL USE
120-127 block LOCAL/EXPERIMENTAL USE
Allocated for local/experimental use. For devices not
assigned official numbers, these ranges should be
used in order to avoid conflicting with future assignments.
234-254 char RESERVED FOR DYNAMIC ASSIGNMENT
Character devices that request a dynamic allocation of major number will
take numbers starting from 254 and downward.
240-254 block LOCAL/EXPERIMENTAL USE
Allocated for local/experimental use. For devices not
assigned official numbers, these ranges should be
used in order to avoid conflicting with future assignments.
384-511 char RESERVED FOR DYNAMIC ASSIGNMENT
Character devices that request a dynamic allocation of major
number will take numbers starting from 511 and downward,
once the 234-254 range is full.
Character device drivers that call alloc_chrdev_region() to register a range of character device numbers will be assigned an unused major device number from the dynamic range. The same is true for character device drivers that call __register_chrdev() with the first argument (major) set to 0.
Some external ("out-of-tree") Linux kernel modules have a module parameter to allow their default major device number to be specified at module load time. That is useful for drivers that do not create their "/dev" entries dynamically, but want some flexibility for the system administrator to choose a major device number when creating device files manually with mknod.
docs:
https://www.oreilly.com/library/view/linux-device-drivers/0596000081/ch03s02.html
https://tldp.org/LDP/tlk/dd/drivers.html
how to find the appropriate minor & major number for a device number:
ls -l /dev/
cat /proc/devices shows the same as lsblk

How the RISC-V HW can determine the privilege level?

The RISC-V current SW privilege level is not set in any CSR. Nevertheless the spec states that "Attempts to access a CSR without appropriate privilege level ... raise illegal instruction". How can it be implemented then (in the HW)?
Well, on interrupts - "xPP holds the previous privilege mode (x=M,S or U). The xPP fields can only hold privilege modes up to x, so MPP is two bits wide, SPP is one bit wide, and UPP is implicitly zero."
Actually, what I have found now is that the xRET instruction enables the processor to store (internally) the current mode - "The MRET, SRET, or URET instructions are used to return from traps in M-mode, S-mode, or U-mode respectively. When executing an xRET instruction, supposing xPP holds the value y, x IE is set to x PIE; the privilege mode is changed to y; x PIE is set to 1; and xPP is set to U (or M if user-mode is not supported)."
The privilege level is reflected in the MPP bits of the mstatus register.
We have mstatus.mPP. that holdS the previous privilege mode. Current privilege mode is not visible to software.
on interrupt the mstatus.mPP is saved to mcause.mPP.. on mrwt, its just written back to mstatus.mPP.
I found this answer from sifive forums quite helpful when I was looking for the same question.
RISC-V deliberately doesn’t make it easy for code to discover what
mode it is running it because this is a virtualisation hole. As a
general principle, code should be designed for and implicitly know
what mode it will run in. Applications code should assume it is in U
mode. The operating system should assume it is in S mode (it might in
fact be virtualised and running in U mode, with things U mode can’t do
trapped and emulated by the hypervisor).
https://forums.sifive.com/t/how-to-determine-the-current-execution-privilege-mode/2823

How to get the physical address with Bus, Device, Function, and Offset

I want to make a kernel module that read the DRAM counters to get the number of data read from DRAM (https://software.intel.com/en-us/articles/monitoring-integrated-memory-controller-requests-in-the-2nd-3rd-and-4th-generation-intel).
In that page, they say
"The BAR is available (in PCI configuration space) at Bus 0; Device 0; Function 0; Offset 048H", and UNC_IMC_DRAM_DATA_READS, which I want to read, is on "BAR + 0x5050".
Does it mean that I can get the physical address of DRAM Counter by typing
sudo setpci 00:00:0 48.L
and then + 0x5050 to get the address where the UNC_IMC_DRAM_DATA_READS?
Actually,
sudo setpci 00:00:0 48.L
outputs
fed10001
, and I accessed 0xfed15051 with busybox.
sudo busybox devmem 0xfed15051
However, the two leftmost bit, I mean "00" in 0x00123456, are always zero.
What was wrong, and how can I get the physical address correctly with Bus, Device, Function, and Offset.
Thank you :)
The low bit is an enable bit and should be excluded from the address you use. See for example https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v6-vol-2-datasheet.pdf (section 3.12 page # 57) -- where it's documented as the MCHBAREN flag.
This document also provides detailed register descriptions of the same registers mentioned in that tech note -- starting at section 7.43 page # 202.
In general, accesses to PCI registers are pretty much always done on 32-bit (DWORD) boundaries. You'll almost never find a counter that overlaps 32-bit words.

Linux DMA API: specifying address increment behavior?

I am writing a driver for Altera Soc Developement Kit and need to support two modes of data transfer to/from a FPGA:
FIFO transfers: When writing to (or reading from) an FPGA FIFO, the destination (or source) address must not be incremented by the DMA controller.
non-FIFO transfers: These are normal (RAM-like) transfers where both the source and destination addresses require an increment for each word transferred.
The particular DMA controller I am using is the CoreLink DMA-330 DMA Controller and its Linux driver is pl330.c (drivers/dma/pl330.c). This DMA controller does provide a mechanism to switch between "Fixed-address burst" and "Incrementing-address burst" (these are synonymous with my "FIFO transfers" and "non-FIFO transfers"). The pl330 driver specifies which behavior it wants by setting the appropriate bits in the CCRn register
#define CC_SRCINC (1 << 0)
#define CC_DSTINC (1 << 14)
My question: it is not at all clear to me how clients of the pl330 (my driver, for example) should specify the address-incrementing behavior.
The DMA engine client API says nothing about how to specify this while the DMA engine provider API simply states:
Addresses pointing to RAM are typically incremented (or decremented)
after each transfer. In case of a ring buffer, they may loop
(DMA_CYCLIC). Addresses pointing to a device's register (e.g. a FIFO)
are typically fixed.
without giving any detail as to how the address types are communicated to providers (in my case the pl300 driver).
The in the pl330_prep_slave_sg method it does:
if (direction == DMA_MEM_TO_DEV) {
desc->rqcfg.src_inc = 1;
desc->rqcfg.dst_inc = 0;
desc->req.rqtype = MEMTODEV;
fill_px(&desc->px,
addr, sg_dma_address(sg), sg_dma_len(sg));
} else {
desc->rqcfg.src_inc = 0;
desc->rqcfg.dst_inc = 1;
desc->req.rqtype = DEVTOMEM;
fill_px(&desc->px,
sg_dma_address(sg), addr, sg_dma_len(sg));
}
where later, the desc->rqcfg.src_inc, and desc->rqcfg.dst_inc are used by the driver to specify the address-increment behavior.
This implies the following:
Specifying a direction = DMA_MEM_TO_DEV means the client wishes to pull data from a FIFO into RAM. And presumably DMA_DEV_TO_MEM means the client wishes to push data from RAM into a FIFO.
Scatter-gather DMA operations (for the pl300 at least) is restricted to cases where either the source or destination end point is a FIFO. What if I wanted to do a scatter-gather operation from system RAM into FPGA (non-FIFO) memory?
Am I misunderstanding and/or overlooking something? Does the DMA engine already provide a (undocumented) mechanism to specify address-increment behavior?
Look at this
pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
pd->device_prep_slave_sg = pl330_prep_slave_sg;
It means you have different approaches like you have read in documentation. RAM-like transfers could be done, I suspect, via device_prep_dma_memcpy().
It appears to me (after looking to various drivers in a kernel) the only DMA transfer styles which allows you (indirectly) control auto-increment behavior is the ones which have enum dma_transfer_direction in its corresponding device_prep_... function.
And this parameter declared only for device_prep_slave_sg and device_prep_dma_cyclic, according to include/linux/dmaengine.h
Another option should be to use and struct dma_interleaved_template which allows you to specify increment behaviour directly. But support for this method is limited (only i.MX DMA driver does support it in 3.8 kernel, for example. And even this support seems to be limited)
So I think, we are stuck with device_prep_slave_sg case with all sg-related complexities for a some while.
That is that I am doing at the moment (although it is for accessing of some EBI-connected device on Atmel SAM9 SOC)
Another thing to consider is a device's bus width. memcopy-variant can perform different bus-width transfers, depending on a source and target addresses and sizes. And this may not match size of FIFO element.

Resources