Driver Component
- The user program performs and open() on the device node,
/dev/perfmon
. This ends up calling perfmon_open(),
which the kernel locates through the static cb_ops structure.
In the case of the Perfmon device driver, there is no
special permission checking or state information that needs to
be taken care of upon an open(), so perfmon_open() always returns
successfully.
- The user then calls ioctl() at various points through the
program, which in turn calls perfmon_ioctl(), which the kernel
finds through the cb_ops structure, to handle the
request. For each of the supported ioctl()s, here is what
happens:
PERFMON_SETPCR
: The user passed in a pointer
to a 64-bit value that is to be stored in the PCR register.
But since the pointer is to a user address, and is not valid
in kernel space, we need to call copyin() to map the user's
buffer into the kernel so that we can get at the value.
After we have the value, we simply call pm_set_pcr()
which sets the value of the PCR register.
PERFMON_GETPCR
: The user passed in a pointer
to a 64-bit buffer in which the current value of the PCR register
is to be stored. We have the same memory mapping problem as before,
so we call pm_get_pcr() to get the current PCR value and then store
it in the user's buffer using copyout().
PERFMON_FLUSH_CACHE
: In this case, we just
call the pre-existing kernel routine that flushes the CPU's
cache. This is done by reading a range of kernel addresses
that is guaranteed to alias with all cache lines, causing
them to be flushed. There was a slight problem with the
implementation of this ioctl(), which is described in
the section below.
- The user program then performs a close() on the device, which calls
perfmon_close(), which the kernel located through the cb_ops
structure. Since we needed no special processing on a device
open, we also need nothing special on close, so perfmon_close()
always returns successfully.