As with previous assignments, we wil be using GitHub to distribute skeleton code and collect submissions. Please refer to our Git Workflow guide for more details. Note that we will be using multiple tags for this assignment, for each deliverable part.
For students on ARM Mac computers (e.g. with M1 chip): if you want your
submission to be built/tested for ARM, you must create and submit a file called
.armpls
in the top-level directory of your repo; feel free to use the
following one-liner:
cd "$(git rev-parse --show-toplevel)" && touch .armpls && git add .armpls && git commit -m "ARM pls"
You should do this first so that this file is present in all parts.
There is a script in the skeleton code named run_checkpatch.sh
. It is a
wrapper over linux/scripts/checkpatch.pl
, which is a Perl script that comes
with the linux kernel that checks if your code conforms to the kernel coding
style.
Execute run_checkpatch.sh
to see if your code conforms to the kernel style –
it’ll let you know what changes you should make. You must make these changes
before pushing a tag. Passing run_checkpatch.sh
with no warnings and no errors
is required for this assignment.
In addition to the pristine Linux kernel source tree (now under linux/
) we’ve
provided a patch file which will create the syscall stubs for you. You will need
to apply this patch to your repo.
The patch is under the following path:
patch/ikea.patch
You can use git apply
to apply this patch. First, check which files will be
modified by the patch:
$ git apply --stat patch/ikea.patch
You should also inspect what the patch is doing by reading the diffs inside. Finally, you can apply the patch with the following:
$ git apply patch/ikea.patch
Now, when you run git status
, you should see some files modified, as well as
some .c
and .h
files added. After verifying that these changes worked as
intended, commit them.
Build your kernel. Make sure you’re building with a local version that is
different from your fallback (-cs4118
), so you don’t overwrite it; set your
local version to your UNI (i.e. -<uni>-HW7
).
Now, when you build your kernel, you should have the inspect_cabinet()
syscall
stub in your kernel.
The syscall you will implement has a struct pointer as a parameter. This means
that the struct definition needs to be available in both kernel and user land.
You’ll need to install the cabinet header (include/uapi/linux/cabinet.h
) from
the kernel source tree to userspace.
Once you’ve built your cabinet-stubbed kernel, run the following command:
# make headers_install INSTALL_HDR_PATH=/usr
This command will install the headers found under include/uapi/
in your Linux
source tree into /usr/include/
. Now you should be able to #include
<linux/cabinet.h>
from userspace! Try compiling the tester program (see below)
to make sure this works.
For this assignment, you will be implementing inspect_cabinet()
, a system call
that allows you to inspect the physical memory associated with a given virtual
address of some process. The syscall number for inspect_cabinet()
is 505, and
it should be implemented as a dynamically loadable module.
The function prototype for inspect_cabinet()
is the following:
long inspect_cabinet(pid_t pid, unsigned long vaddr, struct cab_info *inventory);
inspect_cabinet()
will take in three arguments:
pid
: the PID of the process for which the lookup will be performed
pid
is -1, then the syscall will be performed on the current process’s
PIDvaddr
: the virtual address for which the lookup will be performed
inventory
: a pointer to the struct which will be populated with the
information retrieved by this syscall
inspect_cabinet()
will report the following information about the process:
The physical address associated with the specified virtual address
The physical addresses of its page frame and all intermediate page tables (PTE, PMD, PUD, P4D, PGD)
Whether or not the page containing the specified virtual address is dirty
The number of processes that share the specified physical address
This information will be used to populate a struct cab_info
in userspace
(pointed to by inventory
), which is defined as follows:
struct cab_info {
unsigned long paddr; /* the physical address the virtual address is mapped to */
unsigned long pf_paddr; /* the physical address of its page frame */
unsigned long pte_paddr; /* the physical address of its PTE */
unsigned long pmd_paddr; /* the physical address of its PMD */
unsigned long pud_paddr; /* the physical address of its PUD */
unsigned long p4d_paddr; /* the physical address of its P4D */
unsigned long pgd_paddr; /* the physical address of its PGD */
int dirty; /* 1 if dirty, 0 otherwise */
int refcount; /* number of processes sharing the physical address */
};
On success, inspect_cabinet()
should return 0.
If the page or any of the intermediate page tables are not present in memory,
then its physical address and those of subsequent page frames should be set
to 0. The value of the dirty
and refcount
fields should also be set to 0.
The syscall should still return 0.
pmd_paddr
, pte_paddr
, pf_paddr
, paddr
, dirty
, and
refcount
should all be set to 0, while pud_paddr
, p4d_paddr
, and
pgd_paddr
should be set to the values found; the syscall should return 0.If the user issuing the syscall is not root, fail with the errno value
EACCES
.
If the specified PID is invalid (i.e. < -1), fail with the errno value
EINVAL
.
If the specified PID does not exist, fail with the errno value ESRCH
.
If the specified virtual address does not exist, fail with the errno value
EINVAL
.
If the pointer to the struct cab_info
is invalid, fail with the errno value
EFAULT
.
We’ve also provided some test programs to help you test your implementation, under the following path:
user/test/cabinet_inspector/
In particular, the cabinet_inspector
will execute your syscall, as well as
perform a similar lookup using pagemap (from the /proc/
filesystem)
as a point of reference. You should make sure that the information from
/proc/<pid>/pagemap
is consistent with the information reported by your
implementation of inspect_cabinet()
.
You may also find mmapper
useful for mapping files into memory and finding
their virtual address.
See the README.txt
in that directory for detailed usage instructions.
Here are some example shell sessions of testing with cabinet_inspector
:
You may use /proc/<pid>/maps
to find useful virtual memory addresses of
running processes to test your syscalls on.
Feel free to write your own test programs for additional testing.
Please implement the cabinet syscall in a kernel module using the function pointer technique from HW4.
You will find a module stub in your skeleton repo at the path
user/module/cabinet/
. Please implement your modularized system call here
in cabinet.c
.
Please don’t modify the existing boilerplate code.
You should start your code in the inspect_cabinet()
function.
Feel free to define and call any more functions inside your module.
You can find the cabinet data structures defined for you in the Linux kernel
source tree, under include/uapi/linux/cabinet.h
. Remember to install these
during the setup stage so that you can include this file from userspace.
You do not have to make your cabinet solution architecture-independent. That is, we will only test your solution on your specified architecture. Feel free to use architecture-specific function/macros as long as they are for your architecture.
Once you have completed writing your code, you should test it with the given
tester, cabinet_inspector
.
In your README.txt
, you should describe how you tested your code, what
processes you tested it with, and what you found.
If you wrote any programs to reproduce any particular circumstances that you
tested with, please submit them under user/test/<TEAM-NAME>/
.
To submit this assignment, push the hw7handin
tag with the following:
$ git tag -a -m "Completed hw7." hw7handin
$ git push origin master
$ git push origin hw7handin
Below is some online reading material that you may find helpful for this assignment:
Understanding the Linux Virtual Memory Manager: Page Table Management
Stack Overflow: Difference between Kernel Virtual Address and Kernel Logical Address?
The Cabinet assignment and reference implementation were designed and implemented by the following TAs of COMS W4118 Operating Systems I, Spring 2017, Columbia University:
The Cabinet assignment and test harness were updated by the following TAs of COMS W4118 Operating Systems I, Spring 2018, Columbia University:
The Cabinet assignment and test harness were updated by the following TAs of COMS W4118 Operating Systems I, Spring 2020, Columbia University:
Last updated: 2021-11-24