diff --git a/README.md b/README.md
index f29e2cac3d729038d338ae4d63f22a6961ba9727..0face34c38cdc1b0a0ff23cf42dcffd6604fdf1e 100644
--- a/README.md
+++ b/README.md
@@ -1,92 +1,427 @@
-# asee-2023
+- [Introduction](#org6f719bb)
+  - [Compiling the kernel](#org072ad5e)
+    - [WARNING](#org0c11bd1)
+    - [Debugging](#org55c1542)
+    - [Compiling](#org61e4414)
+  - [Debian Image](#org8fa0fff)
+    - [Prepare an image](#orgcab109a)
+  - [Run the new kernel](#org3ba93db)
+  - [Network problems](#org2eda997)
+- [Linux kernel device programming](#orgc0005c2)
+  - [Part 1 : from "Hello world" to char devices](#org302c6ef)
+    - [Compiling and executing hello-1.ko](#org131f088)
+    - [Sycalls](#org410743b)
+    - [Character devices drivers](#orgcde40e9)
+    - [From user space to kernel space](#orgefaacce)
+  - [First TP](#org9f6fb6e)
+  - [Part 2: Sysfs and ioctl](#orgfe44fd7)
+  - [Second TP](#org872d14a)
+  - [Part 3: Blocking and sleeping](#org0b88ed2)
+    - [Task structure](#org782d6bc)
+    - [Blocking Processes and threads](#org45560df)
+    - [Mutexes](#org6ce70e1)
+    - [Spinlocks and atomic operations](#orge07dab6)
+  - [Third TP: Blocking processes](#org9278176)
+  - [Part 4: Interrupts](#org30f320c)
+  - [Fourth TP (optional): Interrupt handling](#orgdd3559f)
 
 
 
-## Getting started
+<a id="org6f719bb"></a>
 
-To make it easy for you to get started with GitLab, here's a list of recommended next steps.
+# Introduction
 
-Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
+The objective of this short course is to understand the internals of the Linux Kernel. More specifically we will see:
 
-## Add your files
+-   How to set up a development environment for programming Linux kernel code on a PC (for embedded programming the tools to be used are slightly different);
+-   What is a kernel module, and how to write a simple one;
+-   How does scheduling works in Linux;
+-   How to debug and trace kernel code.
 
-- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
-- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
+The course is not exhaustive; we will just touch the surface of some topic. However, it is a good starting point for people that would like to pursue the topic of kernel programming. It is also useful for the students interested in other topics because it gives an overview of the internal workings of the kernel, and of the many difficulties that you can find in developing system code.
 
-```
-cd existing_repo
-git remote add origin https://gitlab-etu.fil.univ-lille.fr/asee/asee-2023.git
-git branch -M main
-git push -uf origin main
-```
+In this course, we will use the on-line book "The Linux Kernel Module Programming Guide" (<https://sysprog21.github.io/lkmpg/>)
 
-## Integrate with your tools
+First, some information on how to download, compile and launch the kernel in a virtual machine.
 
-- [ ] [Set up project integrations](https://gitlab-etu.fil.univ-lille.fr/asee/asee-2023/-/settings/integrations)
 
-## Collaborate with your team
+<a id="org072ad5e"></a>
 
-- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
-- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
-- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
-- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
-- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
+## Compiling the kernel
 
-## Test and Deploy
+Download the latest version of the Linux kernel from <http://www.kernel.org>. Untar:
 
-Use the built-in continuous integration in GitLab.
+    tar -xf linux-6.5.tar.xz
 
-- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
-- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
-- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
-- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
-- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
+Prepare a directory `build/kvm/` and type
 
-***
+    cd linux-6.5
+    make O=../build/kvm menuconfig 
 
-# Editing this README
+(it's an upper case letter 'O', not a 0). In the configuration menu, make sure the following options are set:
 
-When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
+-   Make sure you are compiling e1000 driver which we are going to use. It is in:
+    
+        Device Drivers -> Network device support 
+        -> Ethernet driver support 
+        -> Intel(R) PRO/1000 Gigabit Ethernet support
 
-## Suggestions for a good README
-Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
+-   For serial console access you need
+    
+        Device Drivers -> Character devices -> Serial drivers 
+        -> 8250/16550 and compatible serial support 
+        -> Console on 8250/16550 and compatible serial port
+    
+    Other options for PCI or DMA are not necessary
 
-## Name
-Choose a self-explaining name for your project.
+-   Make sure Virtualization is marked in main menu and KVM support is enabled for your processor (Intel or AMD). You can disable any options regarding the host.
 
-## Description
-Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
+-   Mark
+    
+        Device Drivers -> Virtio drivers 
+        -> PCI driver for virtio devices 
+    
+    Then go to
+    
+        Device Drivers -> Block devices 
+    
+    and mark Virtio block driver.
 
-## Badges
-On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
+**Pay attention**: you need to mark these options with an asterisk "\*" and not with a "M" (module), otherwise they will be compiled as kernel modules and their use is going to be more complex. We can set other virtio drivers too, but they are not mandatory for our course.
 
-## Visuals
-Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
+**Typically, most of these options are already set**, but please check out, then save the configuration file.
 
-## Installation
-Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
 
-## Usage
-Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
+<a id="org0c11bd1"></a>
 
-## Support
-Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
+### WARNING
 
-## Roadmap
-If you have ideas for releases in the future, it is a good idea to list them in the README.
+In your kernel configuration file you will find these lines:
 
-## Contributing
-State if you are open to contributions and what your requirements are for accepting them.
+    CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"
+    CONFIG_SYSTEM_REVOCATION_KEYS="debian/canonical-revoked-certs.pem"
 
-For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
+Change it to this:
 
-You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
+    CONFIG_SYSTEM_TRUSTED_KEYS=""
+    CONFIG_SYSTEM_REVOCATION_KEYS="
 
-## Authors and acknowledgment
-Show your appreciation to those who have contributed to the project.
+Please, check that libssl-dev is installed in your system.
 
-## License
-For open source projects, say how it is licensed.
 
-## Project status
-If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
+<a id="org55c1542"></a>
+
+### Debugging
+
+It is useful to set the following config variable :
+
+    CONFIG_MODULE_FORCE_UNLOAD=y
+
+this will allow you to unload a module even if something went wrong and the kernel thinks it is unsafe to unload the module. It may save you some reboot.
+
+If you want to use gdb for debugging the kernel, the procedure is a little more complex. I suggest you look at the following link:
+
+<https://www.josehu.com/memo/2021/01/02/linux-kernel-build-debug.html>
+
+In this course, it is not necessary to use gdb, so you can skip the above.
+
+
+<a id="org61e4414"></a>
+
+### Compiling
+
+Then, go inside the target directory and type
+
+    cd ../build/kvm
+    make -j8 bzImage 
+    make -j8 modules
+
+The last step is necessary to generate the `Module.symvers` file that contains the exported symbols by the kernel and by all the modules with their CRC. Without this file it is very difficult to compile your own module, so this is unfortunately a mandatory step.
+
+Please be advised that compiling the kernel can take **up to 1 hour**, so relax and continue reading the rest of the documentation while the kernel compiles.
+
+
+<a id="org8fa0fff"></a>
+
+## Debian Image
+
+I prepared a Debian image that you can download [here](https://filesender.renater.fr/?s=download&token=d65d9fa9-cd36-43c7-ad29-e84fd9202f99). Then, to test if it works, you can run the script `kvm.sh` to run the image into a QEMU-KVM virtual machine.
+
+**Optional:** If you want to prepare your own image, please follow the instructions below.
+
+
+<a id="orgcab109a"></a>
+
+### Prepare an image
+
+Download a ISO from Debian.
+
+Create an image (<http://wiki.colar.net/creating_a_qemu_image_and_installing_debian_in_it>)
+
+    qemu-img create -f qcow debian.qcow 2G
+    qemu -cdrom debian.iso -hda debian.img -boot d
+
+You can use the script `kvm-prepare.sh` to install your own debian image, or you can use the one I prepared for you.
+
+Please notice that you may need to install `sudo` and other packages in your debian image.
+
+
+<a id="org3ba93db"></a>
+
+## Run the new kernel
+
+Once the kernel has been compiled, run the script `kvm-mykernel.sh` that you will find in this repository to launch the debian image with your kernel (instead of the standard one). You need to adjust the first line to point the location of your compiled kernel.
+
+Then you can connect to the virtual machine using
+
+    ssh -p 10022 root@localhost 
+    ssh -p 10022 asee@localhost 
+
+For my image, in both cases the password is `asee`.
+
+
+<a id="org2eda997"></a>
+
+## Network problems
+
+Sometimes the dhcp client does not work properly (problems at start time, maybe). The problem seems to have disappeared in the latest versions. However, if you encounter it, here is a solution:
+
+<https://stackoverflow.com/questions/53199827/my-newly-compiled-kernel-loses-networking-in-qemu>
+
+To solve the problem, in the guest OS you can run
+
+    ip a
+    dhclient -v <interface>
+
+where interface is the one that corresponds to the ethernet link in the output of "ip a". To do this permanently, just add the following lines to the file `/etc/network/interfaces`
+
+    auto <interface>
+    iface <interface> inet dhcp
+
+
+<a id="orgc0005c2"></a>
+
+# Linux kernel device programming
+
+In this course, we will use the on-line book "The Linux Kernel Module Programming Guide".
+
+<https://sysprog21.github.io/lkmpg/>
+
+In this course, it is not necessary to read the whole book. In the following I will highlight the mandatory parts and the optional parts. Also, we will use some of the provided examples. I recommend you clone the github repository with the book and all the examples.
+
+It is often useful to explore the kernel code and see what the functions do, what is their prototype and their definition, read the comments, etc. Since the kernel is huge, it is difficult to explore it conveniently without a support. You may use the following website to search the kernel tree and explore the code:
+
+<https://elixir.bootlin.com/linux/latest/source>
+
+
+<a id="org302c6ef"></a>
+
+## Part 1 : from "Hello world" to char devices
+
+This part covers Chapter 1 (Introduction), Chapter 4 (Hello World), Chapter 5 (Preliminaries) and Chapter 6 (Character Device Drivers).
+
+
+<a id="org131f088"></a>
+
+### Compiling and executing hello-1.ko
+
+Go inside `work/hello-1` and read [section 4](https://sysprog21.github.io/lkmpg/#hello-world) until 4.6 of the book (no need to cut and paste, the code is already in this repo) while looking at the code.
+
+Please notice that, in the book the authors assume that you are compiling the module for the host (that is the kernel where you work and compile). Therefore, after compiling, they ask you to directly load the kernel with `insmod hello-1.ko`.
+
+In our case, we are compiling in the host, but the kernel and the module will be executing in the target (the virtual machine). Therefore, after compiling, you need to copy the module into the target with the following command:
+
+    $ scp -P 10022 hello-1.ko asee@localhost: 
+
+and then you need to log in into the target to load the module:
+
+    $ ssh -p 10022 asee@localhost 
+    asee@debian$ sudo su 
+    root@debian:/home/asee# insmod hello-1.ko
+
+Once you load the module you can watch the last 5 messages emitted by all modules with `printk` by running the command
+
+    root@debian:/home/asee#journalctl | tail -n 5 
+
+
+<a id="org410743b"></a>
+
+### Sycalls
+
+Read [section 5](https://sysprog21.github.io/lkmpg/#preliminaries) of the book to understand what is going on. In particular, run the example in section 5.2 to see the trace of syscalls.
+
+
+<a id="orgcde40e9"></a>
+
+### Character devices drivers
+
+Read [Section 6](https://sysprog21.github.io/lkmpg/#character-device-drivers) of the book until section 6.5.
+
+Some additional comment: we may notice that the `file_operations` structure is a sort of "interface" for our character device. By using an **object-oriented analogy**, we can interpret the code as follows:
+
+-   The character device we are coding can be seen as an object of a class that "derives" from a generic class "DeviceDriver";
+
+-   The parent class "DeviceDriver" implements a set of <span class="underline">virtual functions</span> for opening the device driver (`open`), for reading from or writing to it (`read` and `write`), for moving the head (`llseek`), etc. Most of these functions are not implemented, that is they are <span class="underline">abstract functions</span>.
+
+-   Our device driver (the derived class) has to overload some of these functions to implement the desired behaviour. In other words it has to say what does it mean to read or to write to the device. To do this, it implements the corresponding functions and store their address into a `file_operations` structure. Then is registers the structure within the kernel to the corresponding device file. In our analogy, this is equivalent to overload the virtual functions.
+
+Of course, since we are coding in C, we cannot use the typical constructs of an object-oriented language like C++, so the kernel developers use a structure of pointers to functions instead. You may notice the correspondence with the <span class="underline">virtual function table</span> (VTABLE) that is used in C++.
+
+Why using such an interface? In Linux, a device driver is exposed to the used as a file in directory `/dev/`. Therefore, the `file_operations` structure lists all operations that may be performed on a file, and gives the programmer of a module the possibility to overload such functions to perform operations on the device (rather than on a classical file on a disk).
+
+
+<a id="orgefaacce"></a>
+
+### From user space to kernel space
+
+The example in section 6.5 deals with a read-only character device. If we want to write to the device, we have to implement a `device_write()` function.
+
+**This is important:** when in user space, we see memory differently than in kernel space. Remember the course ASA: virtual memory involves using translation tables that map virtual addresses to physical addresses: kernel and the user map the same physical address to different virtual addresses. Therefore, every time the user process passes an address to the kernel, it is necessary to do a "translation" of that address to be able to transfer the data.
+
+To import data from user space, we need to use the function `copy_from_user` that takes an address in user space and copies the content into an address in kernel space. The reverse function is `copy_to_user`. If we have to just copy one single byte, we can use `get_user` and `put_user`.
+
+
+<a id="org9f6fb6e"></a>
+
+## First TP
+
+By using the structure of the example in section 6.5, write a character device `/dev/asee_mod` that :
+
+1.  Stores the characters that the user writes into the device into a circular buffer of 16 characters
+2.  Reads the characters in the buffer in the same order they have been written.
+3.  Keeps the buffer alive between open and close operations.
+
+In particular, we want to observe the following behaviour:
+
+    echo "Hello world" > /dev/asee_mod  
+
+will store "Hello world" into the buffer.
+
+    echo "Ciao" > /dev/asee_mod 
+    cat /dev/asee_mod 
+
+will print the "Hello worldCiao" on the screen. A following
+
+    cat /dev/asee_mod
+
+will print nothing (the data has been consumed).
+
+If more than 16 characters are written in the buffer, then the first characters are overwritten (the buffer is circular). For example:
+
+    echo "abcdefghijklmnopq" > /dev/asee_mod 
+    cat /dev/asee_mod
+
+will print on screen "bcdefghijklmnopq" (the first 'a' has been overwritten). So, only the last 16 characters will be shown.
+
+
+<a id="orgfe44fd7"></a>
+
+## Part 2: Sysfs and ioctl
+
+To interact with your module, you may need to change its configuration. We are going to use a different interface for it, the sysfs.
+
+Read [section 8](https://sysprog21.github.io/lkmpg/#sysfs-interacting-with-your-module) about the sysfs to know how to program this interface. Read, understand, compile and execute the example.
+
+
+<a id="org872d14a"></a>
+
+## Second TP
+
+The idea is to slowly transform our `asee_mod` device into a many-to-many communication channel between different processes. One process can write (produce) data to the channel, and other processes can later read (consume) the data. This is similar to the `pipe()` system call, however our channel is global and accessible to every process.
+
+1.  Starting from your code for TP1, add a variable `asee_buf_size` that contains the current buffer size (by default 16) and a variable `asee_buf_count` that contains the number of characters currently contained in the buffer. For debugging purpouses, you may decide to add additional variables. These variables will all be contained in `sys/kernel/asee_mod/`.
+
+2.  The size of the buffer is now be a variable that can be changed by writing into `asee_buf_size`. Therefore, you should also modify the existing code to take this change into account. Pay attention that, when you decrease the buffer size, the new size could be less than the number of characters currently present inside the buffer: in this case, the operation is aborted, and the size is not modified. Also, you may log the error into the log file with `pr_err()` (see <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>).
+
+Implement and test your module.
+
+
+<a id="org0b88ed2"></a>
+
+## Part 3: Blocking and sleeping
+
+Read [section 11](https://sysprog21.github.io/lkmpg/#blocking-processes-and-threads) of the book. Read, understand, compile and execute the example in 11.1.
+
+Read [section 12](https://sysprog21.github.io/lkmpg/#avoiding-collisions-and-deadlocks) of the book. Read, understand, compile and execute the examples.
+
+
+<a id="org782d6bc"></a>
+
+### Task structure
+
+Inside the kernel, a thread (or a process) is called a task. All information about a task are contained in the [task structure](https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L661).
+
+In this task structure there are many relevant things:
+
+-   the process id (pid)
+-   its exit state (in case the task is in zombie state)
+-   the amount of time it has executed (the utime/stime/gtime fields)
+-   the scheduling policy for this task
+-   its priority
+
+and so many other things. One of the most important is the task `state`. A task can be in one of the [following states](https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L82):
+
+-   `TASK_RUNNING`, the task is executing
+-   `TASK_INTERRUPTIBLE`, the process sleeps waiting for an event or a signal
+-   `TASK_UNINTERRUPTIBLE`, the process waits for something, but it cannot be wake-up by a signal
+-   `TASK_STOPPED`, the task waits for a `SIG_CONTINUE`
+-   `TASK_TRACED`, the task has been suspended by a debugger
+-   `EXIT_ZOMBIE` and `EXIT_DEAD`, the task has finished executing, but the structure has not been deleted yet.
+
+
+<a id="org45560df"></a>
+
+### Blocking Processes and threads
+
+When a thread needs to wait for an event, it can be blocked (put to sleep) by changing its status and inserting it in a waiting queue. See `modules/sleepmod.c` and the description [here](https://sysprog21.github.io/lkmpg/#sleep).
+
+
+<a id="org6ce70e1"></a>
+
+### Mutexes
+
+Kernel mutexes are very similar to userland mutexes. You can use them almost in the same way. See [here](https://elixir.bootlin.com/linux/latest/source/include/linux/mutex.h#L54) for the definition.
+
+In particular, `mutex_lock()` tries to lock the mutex, and if it fails, it blocks on a queue (i.e. its state becomes `TASK_UNINTERRUPTIBLE`, see [here](https://elixir.bootlin.com/linux/latest/source/kernel/locking/mutex.c#L1358)).
+
+Mutex operations are easy to use but are internally complex, see for example the code of the most common case [here](https://elixir.bootlin.com/linux/latest/source/kernel/locking/mutex.c#L926). Therefore, use them when you have no stringent performance requirement.
+
+
+<a id="orge07dab6"></a>
+
+### Spinlocks and atomic operations
+
+In case your critical section is very short (a few tenths of instructions), you may consider using a lower level mechanism called *spinlock*. A spinlock is a busy-wait on a condition, that is the task does not sleep. Very useful to avoid conflicts in multicore systems, must be avoided in single processor systems (use mutexes instead). Finally, for single operations on simple data (i.e. integers), consider using atomic operations.
+
+
+<a id="org9278176"></a>
+
+## Third TP: Blocking processes
+
+We continue the work done in TP2, and we add the possibility to block the tasks under certain circumstances.
+
+1.  If the channel is full and a task wants to write additional data, it is **blocked** (sleeps) until there is at least one byte available for writing. This is different from before: in TP1 and TP2, when the buffer was full, a process would overwrite part of the buffer without blocking. Now, we require the writing process to block if there is not enough space.
+
+2.  In the first two TPs, if the channel was empty, the reader would return an empty string. Now, if the channel is empty and a task wants to read data from it, it is **blocked** (sleeps) until there is at least one byte available for reading.
+
+3.  Handling conflicts: Since several tasks can read/write at the same time executing in parallel on different cores, it is necessary to protect the data structures with mutexes or with spinlocks.
+    -   Use a single spinlock first for the whole device. Pay attention, you must release the spinlock before sleeping
+    -   Try to think about using a mutex. What does it change?
+
+
+<a id="org30f320c"></a>
+
+## Part 4: Interrupts
+
+Read [Section 15](https://sysprog21.github.io/lkmpg/#interrupt-handlers) of the book.
+
+We are developing in a virtual machine that simulates a PC, so we have no way for the moment to install a physical button on the GPIO. To simulate the occurrence of an interrupt, we can use the HW instruction int, as described here:
+
+<https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-13-interrupt-example-program-in-linux-kernel/>
+
+
+<a id="orgdd3559f"></a>
+
+## Fourth TP (optional): Interrupt handling
+
+Modify you previous code from TP3 so that, when a certain interrupt arrives, every blocked task is unblocked and returns with an error. To simulate the occurrence of an interrupt, you can implement a special sysfs variable that, when written, will raise the interrupt with INT.
\ No newline at end of file
diff --git a/cours.pdf b/cours.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..d72c9854d03e06221cd4f63f619dedb6f728574b
Binary files /dev/null and b/cours.pdf differ
diff --git a/docs/cours.org b/docs/cours.org
new file mode 100644
index 0000000000000000000000000000000000000000..0331c6fcb20d612f868392ba78f2638c6502e6f3
--- /dev/null
+++ b/docs/cours.org
@@ -0,0 +1,489 @@
+#+OPTIONS: ^:nil
+#+latex_header: \usepackage[textwidth=15cm,textheight=21cm]{geometry}
+
+#+TITLE: Architecture des Systèmes d'Exploitation Évolués\\
+#+TITLE: Université de Lille, Master 2 Info : A.A. 2023/2024
+#+AUTHOR: Giuseppe Lipari
+
+* Introduction 
+
+The objective of this short course is to understand the internals of
+the Linux Kernel. More specifically we will see:
+
+- How to set up a development environment for programming Linux kernel
+  code on a PC (for embedded programming the tools to be used are
+  slightly different);
+- What is a kernel module, and how to write a simple one;
+- How does scheduling works in Linux;
+- How to debug and trace kernel code.
+
+The course is not exhaustive; we will just touch the surface of some
+topic. However, it is a good starting point for people that would like
+to pursue the topic of kernel programming. It is also useful for the
+students interested in other topics because it gives an overview of
+the internal workings of the kernel, and of the many difficulties that
+you can find in developing system code.
+
+In this course, we will use the on-line book "The Linux Kernel
+Module Programming Guide" (https://sysprog21.github.io/lkmpg/)
+
+First, some information on how to download, compile and launch the
+kernel in a virtual machine.
+
+** Compiling the kernel 
+
+Download the latest version of the Linux kernel from [[http://www.kernel.org]]. 
+Untar: 
+
+  : tar -xf linux-6.5.tar.xz
+
+Prepare a directory =build/kvm/= and type 
+
+   : cd linux-6.5
+   : make O=../build/kvm menuconfig 
+
+(it's an upper case letter 'O', not a 0).
+In the configuration menu, make sure the following options are set:
+
+- Make sure you are compiling e1000 driver which we are going to
+  use. It is in:
+  : Device Drivers -> Network device support 
+  : -> Ethernet driver support 
+  : -> Intel(R) PRO/1000 Gigabit Ethernet support
+
+- For serial console access you need 
+  : Device Drivers -> Character devices -> Serial drivers 
+  : -> 8250/16550 and compatible serial support 
+  : -> Console on 8250/16550 and compatible serial port
+  Other options for PCI or DMA are not necessary
+
+- Make sure Virtualization is marked in main menu and KVM support is
+  enabled for your processor (Intel or AMD). You can disable any
+  options regarding the host.
+
+- Mark 
+  : Device Drivers -> Virtio drivers 
+  : -> PCI driver for virtio devices 
+  Then go to 
+  : Device Drivers -> Block devices 
+  and mark Virtio block driver.
+
+*Pay attention*: you need to mark these options with an asterisk "*"
+and not with a "M" (module), otherwise they will be compiled as kernel
+modules and their use is going to be more complex. We can set other
+virtio drivers too, but they are not mandatory for our course.
+
+*Typically, most of these options are already set*, but please check
+out, then save the configuration file. 
+
+*** WARNING
+
+   In your kernel configuration file you will find these lines:
+
+   : CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"
+   : CONFIG_SYSTEM_REVOCATION_KEYS="debian/canonical-revoked-certs.pem"
+
+   Change it to this:
+
+   : CONFIG_SYSTEM_TRUSTED_KEYS=""
+   : CONFIG_SYSTEM_REVOCATION_KEYS="
+
+   Please, check that libssl-dev is installed in your system.
+
+*** Debugging
+ 
+   It is useful to set the following config variable :
+
+   : CONFIG_MODULE_FORCE_UNLOAD=y
+
+   this will allow you to unload a module even if something went wrong
+   and the kernel thinks it is unsafe to unload the module. It may
+   save you some reboot.
+
+   If you want to use gdb for debugging the kernel, the procedure is a
+   little more complex. I suggest you look at the following link:
+
+   https://www.josehu.com/memo/2021/01/02/linux-kernel-build-debug.html
+
+   In this course, it is not necessary to use gdb, so you can skip the
+   above.
+   
+*** Compiling
+
+Then, go inside the target directory and type
+
+   : cd ../build/kvm
+   : make -j8 bzImage 
+   : make -j8 modules
+
+   The last step is necessary to generate the =Module.symvers= file
+   that contains the exported symbols by the kernel and by all the
+   modules with their CRC. Without this file it is very difficult to
+   compile your own module, so this is unfortunately a mandatory step.
+
+   Please be advised that compiling the kernel can take *up to 1 hour*,
+   so relax and continue reading the rest of the documentation while
+   the kernel compiles.
+
+** Debian Image 
+
+   I prepared a Debian image that you can download [[https://filesender.renater.fr/?s=download&token=d65d9fa9-cd36-43c7-ad29-e84fd9202f99][here]].  Then, to
+   test if it works, you can run the script =kvm.sh= to run the image
+   into a QEMU-KVM virtual machine.
+
+   *Optional:* If you want to prepare your own image, please follow
+   the instructions below.
+   
+*** Prepare an image 
+
+    Download a ISO from Debian.
+
+    Create an image (http://wiki.colar.net/creating_a_qemu_image_and_installing_debian_in_it)
+
+    : qemu-img create -f qcow debian.qcow 2G
+    : qemu -cdrom debian.iso -hda debian.img -boot d
+  
+    You can use the script =kvm-prepare.sh= to install your own debian
+    image, or you can use the one I prepared for you. 
+
+    Please notice that you may need to install =sudo= and other
+    packages in your debian image.
+  
+** Run the new kernel 
+
+   Once the kernel has been compiled, run the script =kvm-mykernel.sh=
+   that you will find in this repository to launch the debian image
+   with your kernel (instead of the standard one). You need to adjust
+   the first line to point the location of your compiled kernel.
+
+   Then you can connect to the virtual machine using
+
+   : ssh -p 10022 root@localhost 
+   : ssh -p 10022 asee@localhost 
+  
+   For my image, in both cases the password is =asee=.
+
+** Network problems
+
+   Sometimes the dhcp client does not work properly (problems at start
+   time, maybe). The problem seems to have disappeared in the latest
+   versions. However, if you encounter it, here is a solution:
+
+   https://stackoverflow.com/questions/53199827/my-newly-compiled-kernel-loses-networking-in-qemu
+
+   To solve the problem, in the guest OS you can run 
+  
+   : ip a
+   : dhclient -v <interface>
+
+   where interface is the one that corresponds to the ethernet link in
+   the output of "ip a". To do this permanently, just add the following
+   lines to the file =/etc/network/interfaces=
+
+   : auto <interface>
+   : iface <interface> inet dhcp
+    
+
+* Linux kernel device programming 
+
+  In this course, we will use the on-line book "The Linux Kernel Module Programming Guide". 
+
+  https://sysprog21.github.io/lkmpg/
+
+  In this course, it is not necessary to read the whole book. In the
+  following I will highlight the mandatory parts and the optional
+  parts. Also, we will use some of the provided examples. I recommend
+  you clone the github repository with the book and all the examples.
+
+  It is often useful to explore the kernel code and see what the
+  functions do, what is their prototype and their definition, read the
+  comments, etc. Since the kernel is huge, it is difficult to explore
+  it conveniently without a support. You may use the following website
+  to search the kernel tree and explore the code:
+
+  https://elixir.bootlin.com/linux/latest/source
+
+  
+** Part 1 : from "Hello world" to char devices 
+
+This part covers Chapter 1 (Introduction), Chapter 4 (Hello World),
+Chapter 5 (Preliminaries) and Chapter 6 (Character Device Drivers).
+
+*** Compiling and executing hello-1.ko
+
+Go inside =work/hello-1= and read [[https://sysprog21.github.io/lkmpg/#hello-world][section 4]] until 4.6 of the book (no need to
+cut and paste, the code is already in this repo) while looking at the
+code.
+
+Please notice that, in the book the authors assume that you are
+compiling the module for the host (that is the kernel where you work
+and compile). Therefore, after compiling, they ask you to directly
+load the kernel with =insmod hello-1.ko=.
+
+In our case, we are compiling in the host, but the kernel and the
+module will be executing in the target (the virtual
+machine). Therefore, after compiling, you need to copy the module into
+the target with the following command:
+
+: $ scp -P 10022 hello-1.ko asee@localhost: 
+
+and then you need to log in into the target to load the module:
+
+: $ ssh -p 10022 asee@localhost 
+: asee@debian$ sudo su 
+: root@debian:/home/asee# insmod hello-1.ko
+
+Once you load the module you can watch the last 5 messages emitted by
+all modules with =printk= by running the command
+
+: root@debian:/home/asee#journalctl | tail -n 5 
+
+*** Sycalls
+
+Read [[https://sysprog21.github.io/lkmpg/#preliminaries][section 5]] of the book to understand what is going on. In
+particular, run the example in section 5.2 to see the trace of
+syscalls.
+ 
+
+*** Character devices drivers
+
+Read [[https://sysprog21.github.io/lkmpg/#character-device-drivers][Section 6]] of the book until section 6.5. 
+
+Some additional comment: we may notice that the =file_operations=
+structure is a sort of "interface" for our character device. By using
+an *object-oriented analogy*, we can interpret the code as follows:
+
+- The character device we are coding can be seen as an object of a
+  class that "derives" from a generic class "DeviceDriver";
+
+- The parent class "DeviceDriver" implements a set of _virtual
+  functions_ for opening the device driver (=open=), for reading from
+  or writing to it (=read= and =write=), for moving the head
+  (=llseek=), etc. Most of these functions are not implemented, that
+  is they are _abstract functions_.
+
+- Our device driver (the derived class) has to overload some of these
+  functions to implement the desired behaviour. In other words it has
+  to say what does it mean to read or to write to the device. To do
+  this, it implements the corresponding functions and store their
+  address into a =file_operations= structure. Then is registers the
+  structure within the kernel to the corresponding device file. In our
+  analogy, this is equivalent to overload the virtual functions. 
+
+Of course, since we are coding in C, we cannot use the typical
+constructs of an object-oriented language like C++, so the kernel
+developers use a structure of pointers to functions instead. You may
+notice the correspondence with the _virtual function table_ (VTABLE)
+that is used in C++.
+
+Why using such an interface? In Linux, a device driver is exposed to
+the used as a file in directory =/dev/=. Therefore, the
+=file_operations= structure lists all operations that may be performed
+on a file, and gives the programmer of a module the possibility to
+overload such functions to perform operations on the device (rather
+than on a classical file on a disk). 
+
+
+*** From user space to kernel space 
+
+The example in section 6.5 deals with a read-only character device. If
+we want to write to the device, we have to implement a
+=device_write()= function. 
+
+*This is important:* when in user space, we see memory differently
+than in kernel space. Remember the course ASA: virtual memory
+involves using translation tables that map virtual addresses to
+physical addresses: kernel and the user map the same physical address
+to different virtual addresses. Therefore, every time the user process
+passes an address to the kernel, it is necessary to do a "translation"
+of that address to be able to transfer the data.
+
+To import data from user space, we need to use the function
+=copy_from_user= that takes an address in user space and copies the
+content into an address in kernel space. The reverse function is
+=copy_to_user=. If we have to just copy one single byte, we can use
+=get_user= and =put_user=.
+
+** First TP
+
+By using the structure of the example in section 6.5, write a
+character device =/dev/asee_mod= that :
+1. Stores the characters that the user writes into the device into a circular buffer of 16 characters
+2. Reads the characters in the buffer in the same order they have been written. 
+3. Keeps the buffer alive between open and close operations.
+
+In particular, we want to observe the following behaviour:
+
+: echo "Hello world" > /dev/asee_mod  
+will store "Hello world" into the buffer. 
+: echo "Ciao" > /dev/asee_mod 
+: cat /dev/asee_mod 
+will print the "Hello worldCiao" on the screen. A following
+: cat /dev/asee_mod
+will print nothing (the data has been consumed). 
+
+If more than 16 characters are written in the buffer, then the first
+characters are overwritten (the buffer is circular). For example:
+
+: echo "abcdefghijklmnopq" > /dev/asee_mod 
+: cat /dev/asee_mod
+will print on screen "bcdefghijklmnopq" (the first 'a' has been
+overwritten). So, only the last 16 characters will be shown.
+
+** Part 2: Sysfs and ioctl
+
+To interact with your module, you may need to change its
+configuration. We are going to use a different interface for it, the
+sysfs.
+
+Read [[https://sysprog21.github.io/lkmpg/#sysfs-interacting-with-your-module][section 8]] about the sysfs to know how to program this
+interface. Read, understand, compile and execute the example.
+
+** Second TP 
+
+  The idea is to slowly transform our =asee_mod= device into a
+  many-to-many communication channel between different processes.
+  One process can write (produce) data to the channel, and other
+  processes can later read (consume) the data.
+  This is similar to the =pipe()= system call, however our channel is
+  global and accessible to every process. 
+
+  1. Starting from your code for TP1, add a variable =asee_buf_size=
+     that contains the current buffer size (by default 16) and a
+     variable =asee_buf_count= that contains the number of characters
+     currently contained in the buffer. For debugging purpouses, you
+     may decide to add additional variables. These variables will all
+     be contained in =sys/kernel/asee_mod/=.
+
+  2. The size of the buffer is now be a variable that can be changed
+     by writing into =asee_buf_size=. Therefore, you should also
+     modify the existing code to take this change into account.  Pay
+     attention that, when you decrease the buffer size, the new size
+     could be less than the number of characters currently present
+     inside the buffer: in this case, the operation is aborted, and
+     the size is not modified. Also, you may log the error into the
+     log file with =pr_err()= (see
+     https://www.kernel.org/doc/html/latest/core-api/printk-basics.html).
+
+  Implement and test your module. 
+
+** Part 3: Blocking and sleeping 
+
+Read [[https://sysprog21.github.io/lkmpg/#blocking-processes-and-threads][section 11]] of the book. Read, understand, compile and execute the example in 11.1. 
+
+Read [[https://sysprog21.github.io/lkmpg/#avoiding-collisions-and-deadlocks][section 12]] of the book. Read, understand, compile and execute the examples. 
+
+*** Task structure
+
+   Inside the kernel, a thread (or a process) is called a task. All
+   information about a task are contained in the [[https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L661][task structure]].
+
+   In this task structure there are many relevant things: 
+
+   - the process id (pid)
+   - its exit state (in case the task is in zombie state)
+   - the amount of time it has executed (the utime/stime/gtime fields)
+   - the scheduling policy for this task
+   - its priority
+   and so many other things. One of the most important is the task
+   =state=. A task can be in one of the [[https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L82][following states]]: 
+   - =TASK_RUNNING=, the task is executing
+   - =TASK_INTERRUPTIBLE=, the process sleeps waiting for an event or a signal
+   - =TASK_UNINTERRUPTIBLE=, the process waits for something, but it
+     cannot be wake-up by a signal
+   - =TASK_STOPPED=, the task waits for a =SIG_CONTINUE=
+   - =TASK_TRACED=, the task has been suspended by a debugger
+   - =EXIT_ZOMBIE= and =EXIT_DEAD=, the task has finished executing,
+     but the structure has not been deleted yet.
+   
+
+*** Blocking Processes and threads
+
+   When a thread needs to wait for an event, it can be blocked (put to
+   sleep) by changing its status and inserting it in a waiting queue.
+   See =modules/sleepmod.c= and the description [[https://sysprog21.github.io/lkmpg/#sleep][here]].
+   
+   
+*** Mutexes
+
+   Kernel mutexes are very similar to userland mutexes. You can use
+   them almost in the same way. See [[https://elixir.bootlin.com/linux/latest/source/include/linux/mutex.h#L54][here]] for the definition. 
+
+   In particular, =mutex_lock()= tries to lock the mutex, and if it
+   fails, it blocks on a queue (i.e. its state becomes
+   =TASK_UNINTERRUPTIBLE=, see [[https://elixir.bootlin.com/linux/latest/source/kernel/locking/mutex.c#L1358][here]]).
+   
+   Mutex operations are easy to use but are internally complex, see
+   for example the code of the most common case [[https://elixir.bootlin.com/linux/latest/source/kernel/locking/mutex.c#L926][here]]. Therefore, use
+   them when you have no stringent performance requirement.
+   
+
+*** Spinlocks and atomic operations 
+
+   In case your critical section is very short (a few tenths of
+   instructions), you may consider using a lower level mechanism
+   called /spinlock/. A spinlock is a busy-wait on a condition, that
+   is the task does not sleep. Very useful to avoid conflicts in
+   multicore systems, must be avoided in single processor systems (use
+   mutexes instead). Finally, for single operations on simple data
+   (i.e. integers), consider using atomic operations.
+
+
+
+** Third TP: Blocking processes 
+
+  We continue the work done in TP2, and we add the possibility to
+  block the tasks under certain circumstances. 
+
+  1) If the channel is full and a task wants to write additional data,
+     it is *blocked* (sleeps) until there is at least one byte
+     available for writing. This is different from before: in TP1 and
+     TP2, when the buffer was full, a process would overwrite part of
+     the buffer without blocking. Now, we require the writing process
+     to block if there is not enough space.
+
+  2) In the first two TPs, if the channel was empty, the reader would
+     return an empty string. Now, if the channel is empty and a task
+     wants to read data from it, it is *blocked* (sleeps) until there
+     is at least one byte available for reading.
+  
+  3) Handling conflicts: Since several tasks can read/write at the
+     same time executing in parallel on different cores, it is
+     necessary to protect the data structures with mutexes or with
+     spinlocks.
+     - Use a single spinlock first for the whole device. Pay attention,
+       you must release the spinlock before sleeping
+     - Try to think about using a mutex. What does it change?
+	 
+** Part 4: Interrupts 
+
+Read [[https://sysprog21.github.io/lkmpg/#interrupt-handlers][Section 15]] of the book.  
+
+We are developing in a virtual machine that simulates a PC, so we have
+no way for the moment to install a physical button on the GPIO. To
+simulate the occurrence of an interrupt, we can use the HW instruction
+int, as described here: 
+
+  https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-13-interrupt-example-program-in-linux-kernel/
+
+** Fourth TP (optional): Interrupt handling
+
+  Modify you previous code from TP3 so that, when a certain interrupt
+  arrives, every blocked task is unblocked and returns with an error.
+  To simulate the occurrence of an interrupt, you can implement a
+  special sysfs variable that, when written, will raise the interrupt
+  with INT.
+  
+
+
+
+
+
+   
+
+   
+
+
+
+
+  
diff --git a/kvm-mylinux.sh b/kvm-mylinux.sh
new file mode 100755
index 0000000000000000000000000000000000000000..eed53d5d4d38474eca11147d65f2dca9a7ab1808
--- /dev/null
+++ b/kvm-mylinux.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+KERNEL=${1-/home/lipari/Documents/corsi/2023-2024/ASEE/prova/build/kvm/arch/x86/boot/bzImage}
+SMP=${2-2}
+
+kvm -smp $SMP -m 1G -boot c --enable-kvm \
+    -kernel $KERNEL -append "root=/dev/sda1 console=ttyS0 rw" \
+    -hda debian.qcow \
+    -net user,hostfwd=tcp::10022-:22 -net nic
+    -serial mon:stdio
+
diff --git a/kvm.sh b/kvm.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f69b87f034bcc6c7d1e6b5ce6c62e2641f3c629d
--- /dev/null
+++ b/kvm.sh
@@ -0,0 +1,7 @@
+SMP=${2-2}
+
+kvm -smp $SMP -m 2048 -boot c \
+	-hda debian.qcow \
+	-net nic -net user,hostfwd=tcp::10022-:22 \
+	-serial stdio
+
diff --git a/work/hello-1/Makefile b/work/hello-1/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..5288f363e215823d84dae35c7cdc2172ff6f9c7d
--- /dev/null
+++ b/work/hello-1/Makefile
@@ -0,0 +1,9 @@
+KDIR=../../build/kvm/
+
+obj-m += hello-1.o 
+PWD := $(CURDIR) 
+
+all: 
+	make -C $(KDIR) M=$(PWD) modules 
+clean: 
+	make -C $(KDIR) M=$(PWD) clean
diff --git a/work/hello-1/hello-1.c b/work/hello-1/hello-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..12f1a5d45dd0d45768e2bb138fcfe9ee4f985018
--- /dev/null
+++ b/work/hello-1/hello-1.c
@@ -0,0 +1,20 @@
+/*
+ * hello-1.c - The simplest kernel module.
+ */
+#include <linux/module.h> /* Needed by all modules */
+#include <linux/printk.h> /* Needed for pr_info() */
+
+int init_module(void)
+{
+    pr_info("Hello world 1.\n");
+
+    /* A non 0 return means init_module failed; module can't be loaded. */
+    return 0;
+}
+
+void cleanup_module(void)
+{
+    pr_info("Goodbye world 1.\n");
+}
+
+MODULE_LICENSE("GPL");