mirror of
https://github.com/0xAX/linux-insides.git
synced 2024-12-22 14:48:08 +00:00
modify broken links related with Thoery, Data structure, Misc and so on
This commit is contained in:
parent
6eaffded82
commit
49c8951eb8
@ -213,7 +213,7 @@ If you are interested, you can find these sections in the `arch/x86/kernel/vmlin
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are not familiar with this then you can know more about [linkers](https://en.wikipedia.org/wiki/Linker_%28computing%29) in the special [part](https://0xax.gitbooks.io/linux-insides/content/Misc/linkers.html) of this book.
|
If you are not familiar with this then you can know more about [linkers](https://en.wikipedia.org/wiki/Linker_%28computing%29) in the special [part](https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-3.html) of this book.
|
||||||
|
|
||||||
As we just saw, the `do_initcall_level` function takes one parameter - level of `initcall` and does following two things: First of all this function parses the `initcall_command_line` which is copy of usual kernel [command line](https://www.kernel.org/doc/Documentation/kernel-parameters.txt) which may contain parameters for modules with the `parse_args` function from the [kernel/params.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/params.c) source code file and call the `do_on_initcall` function for each level:
|
As we just saw, the `do_initcall_level` function takes one parameter - level of `initcall` and does following two things: First of all this function parses the `initcall_command_line` which is copy of usual kernel [command line](https://www.kernel.org/doc/Documentation/kernel-parameters.txt) which may contain parameters for modules with the `parse_args` function from the [kernel/params.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/params.c) source code file and call the `do_on_initcall` function for each level:
|
||||||
|
|
||||||
@ -387,9 +387,9 @@ Links
|
|||||||
* [symbols concatenation](https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html)
|
* [symbols concatenation](https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html)
|
||||||
* [GCC](https://en.wikipedia.org/wiki/GNU_Compiler_Collection)
|
* [GCC](https://en.wikipedia.org/wiki/GNU_Compiler_Collection)
|
||||||
* [Link time optimization](https://gcc.gnu.org/wiki/LinkTimeOptimization)
|
* [Link time optimization](https://gcc.gnu.org/wiki/LinkTimeOptimization)
|
||||||
* [Introduction to linkers](https://0xax.gitbooks.io/linux-insides/content/Misc/linkers.html)
|
* [Introduction to linkers](https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-3.html)
|
||||||
* [Linux kernel command line](https://www.kernel.org/doc/Documentation/kernel-parameters.txt)
|
* [Linux kernel command line](https://www.kernel.org/doc/Documentation/kernel-parameters.txt)
|
||||||
* [Process identifier](https://en.wikipedia.org/wiki/Process_identifier)
|
* [Process identifier](https://en.wikipedia.org/wiki/Process_identifier)
|
||||||
* [IRQs](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
* [IRQs](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
||||||
* [rootfs](https://en.wikipedia.org/wiki/Initramfs)
|
* [rootfs](https://en.wikipedia.org/wiki/Initramfs)
|
||||||
* [previous part](https://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [previous part](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
|
@ -366,4 +366,4 @@ Links
|
|||||||
* [system call](https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-1.html)
|
* [system call](https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-1.html)
|
||||||
* [init_module system call](http://man7.org/linux/man-pages/man2/init_module.2.html)
|
* [init_module system call](http://man7.org/linux/man-pages/man2/init_module.2.html)
|
||||||
* [delete_module](http://man7.org/linux/man-pages/man2/delete_module.2.html)
|
* [delete_module](http://man7.org/linux/man-pages/man2/delete_module.2.html)
|
||||||
* [previous part](https://0xax.gitbooks.io/linux-insides/content/Concepts/initcall.html)
|
* [previous part](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-3.html)
|
||||||
|
@ -13,7 +13,7 @@ Besides these two files, there is also architecture-specific header file which p
|
|||||||
|
|
||||||
* [arch/x86/include/asm/bitops.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/include/asm/bitops.h)
|
* [arch/x86/include/asm/bitops.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/include/asm/bitops.h)
|
||||||
|
|
||||||
header file. As I just wrote above, the `bitmap` is heavily used in the Linux kernel. For example a `bit array` is used to store set of online/offline processors for systems which support [hot-plug](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt) cpu (more about this you can read in the [cpumasks](https://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) part), a `bit array` stores set of allocated [irqs](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29) during initialization of the Linux kernel and etc.
|
header file. As I just wrote above, the `bitmap` is heavily used in the Linux kernel. For example a `bit array` is used to store set of online/offline processors for systems which support [hot-plug](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt) cpu (more about this you can read in the [cpumasks](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) part), a `bit array` stores set of allocated [irqs](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29) during initialization of the Linux kernel and etc.
|
||||||
|
|
||||||
So, the main goal of this part is to see how `bit arrays` are implemented in the Linux kernel. Let's start.
|
So, the main goal of this part is to see how `bit arrays` are implemented in the Linux kernel. Let's start.
|
||||||
|
|
||||||
@ -365,7 +365,7 @@ Links
|
|||||||
* [linked data structures](https://en.wikipedia.org/wiki/Linked_data_structure)
|
* [linked data structures](https://en.wikipedia.org/wiki/Linked_data_structure)
|
||||||
* [tree data structures](https://en.wikipedia.org/wiki/Tree_%28data_structure%29)
|
* [tree data structures](https://en.wikipedia.org/wiki/Tree_%28data_structure%29)
|
||||||
* [hot-plug](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt)
|
* [hot-plug](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt)
|
||||||
* [cpumasks](https://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [cpumasks](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
* [IRQs](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
* [IRQs](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
||||||
* [API](https://en.wikipedia.org/wiki/Application_programming_interface)
|
* [API](https://en.wikipedia.org/wiki/Application_programming_interface)
|
||||||
* [atomic operations](https://en.wikipedia.org/wiki/Linearizability)
|
* [atomic operations](https://en.wikipedia.org/wiki/Linearizability)
|
||||||
|
@ -88,7 +88,7 @@ After we got the address of the `startup_64`, we need to do a check that this ad
|
|||||||
jnz bad_address
|
jnz bad_address
|
||||||
```
|
```
|
||||||
|
|
||||||
Here we just compare low part of the `rbp` register with the complemented value of the `PMD_PAGE_MASK`. The `PMD_PAGE_MASK` indicates the mask for `Page middle directory` (read [paging](http://0xax.gitbooks.io/linux-insides/content/Theory/Paging.html) about it) and defined as:
|
Here we just compare low part of the `rbp` register with the complemented value of the `PMD_PAGE_MASK`. The `PMD_PAGE_MASK` indicates the mask for `Page middle directory` (read [Paging](https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-1.html) about it) and defined as:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
#define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1))
|
#define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1))
|
||||||
@ -163,7 +163,7 @@ Looks hard, but it isn't. First of all let's look at the `early_level4_pgt`. It
|
|||||||
_PAGE_ACCESSED | _PAGE_DIRTY)
|
_PAGE_ACCESSED | _PAGE_DIRTY)
|
||||||
```
|
```
|
||||||
|
|
||||||
You can read more about it in the [paging](http://0xax.gitbooks.io/linux-insides/content/Theory/Paging.html) part.
|
You can read more about it in the [Paging](https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-1.html) part.
|
||||||
|
|
||||||
The `level3_kernel_pgt` - stores two entries which map kernel space. At the start of it's definition, we can see that it is filled with zeros `L3_START_KERNEL` or `510` times. Here the `L3_START_KERNEL` is the index in the page upper directory which contains `__START_KERNEL_map` address and it equals `510`. After this, we can see the definition of the two `level3_kernel_pgt` entries: `level2_kernel_pgt` and `level2_fixmap_pgt`. First is simple, it is page table entry which contains pointer to the page middle directory which maps kernel space and it has:
|
The `level3_kernel_pgt` - stores two entries which map kernel space. At the start of it's definition, we can see that it is filled with zeros `L3_START_KERNEL` or `510` times. Here the `L3_START_KERNEL` is the index in the page upper directory which contains `__START_KERNEL_map` address and it equals `510`. After this, we can see the definition of the two `level3_kernel_pgt` entries: `level2_kernel_pgt` and `level2_fixmap_pgt`. First is simple, it is page table entry which contains pointer to the page middle directory which maps kernel space and it has:
|
||||||
|
|
||||||
@ -485,7 +485,7 @@ INIT_PER_CPU(gdt_page);
|
|||||||
|
|
||||||
As we got `init_per_cpu__gdt_page` in `INIT_PER_CPU_VAR` and `INIT_PER_CPU` macro from linker script will be expanded we will get offset from the `__per_cpu_load`. After this calculations, we will have correct base address of the new GDT.
|
As we got `init_per_cpu__gdt_page` in `INIT_PER_CPU_VAR` and `INIT_PER_CPU` macro from linker script will be expanded we will get offset from the `__per_cpu_load`. After this calculations, we will have correct base address of the new GDT.
|
||||||
|
|
||||||
Generally per-CPU variables is a 2.6 kernel feature. You can understand what it is from its name. When we create `per-CPU` variable, each CPU will have its own copy of this variable. Here we creating `gdt_page` per-CPU variable. There are many advantages for variables of this type, like there are no locks, because each CPU works with its own copy of variable and etc... So every core on multiprocessor will have its own `GDT` table and every entry in the table will represent a memory segment which can be accessed from the thread which ran on the core. You can read in details about `per-CPU` variables in the [Theory/per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) post.
|
Generally per-CPU variables is a 2.6 kernel feature. You can understand what it is from its name. When we create `per-CPU` variable, each CPU will have its own copy of this variable. Here we creating `gdt_page` per-CPU variable. There are many advantages for variables of this type, like there are no locks, because each CPU works with its own copy of variable and etc... So every core on multiprocessor will have its own `GDT` table and every entry in the table will represent a memory segment which can be accessed from the thread which ran on the core. You can read in details about `per-CPU` variables in the [Theory/per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) post.
|
||||||
|
|
||||||
As we loaded new Global Descriptor Table, we reload segments as we did it every time:
|
As we loaded new Global Descriptor Table, we reload segments as we did it every time:
|
||||||
|
|
||||||
@ -614,7 +614,7 @@ Links
|
|||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
* [Model Specific Register](http://en.wikipedia.org/wiki/Model-specific_register)
|
* [Model Specific Register](http://en.wikipedia.org/wiki/Model-specific_register)
|
||||||
* [Paging](http://0xax.gitbooks.io/linux-insides/content/Theory/Paging.html)
|
* [Paging](http://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-1.html)
|
||||||
* [Previous part - Kernel decompression](http://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-5.html)
|
* [Previous part - Kernel decompression](http://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-5.html)
|
||||||
* [NX](http://en.wikipedia.org/wiki/NX_bit)
|
* [NX](http://en.wikipedia.org/wiki/NX_bit)
|
||||||
* [ASLR](http://en.wikipedia.org/wiki/Address_space_layout_randomization)
|
* [ASLR](http://en.wikipedia.org/wiki/Address_space_layout_randomization)
|
||||||
|
@ -241,7 +241,7 @@ For now it is just zero. If the `CONFIG_DEBUG_PREEMPT` configuration option is d
|
|||||||
#define raw_smp_processor_id() (this_cpu_read(cpu_number))
|
#define raw_smp_processor_id() (this_cpu_read(cpu_number))
|
||||||
```
|
```
|
||||||
|
|
||||||
`this_cpu_read` as many other function like this (`this_cpu_write`, `this_cpu_add` and etc...) defined in the [include/linux/percpu-defs.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/percpu-defs.h) and presents `this_cpu` operation. These operations provide a way of optimizing access to the [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Theory/per-cpu.html) variables which are associated with the current processor. In our case it is `this_cpu_read`:
|
`this_cpu_read` as many other function like this (`this_cpu_write`, `this_cpu_add` and etc...) defined in the [include/linux/percpu-defs.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/percpu-defs.h) and presents `this_cpu` operation. These operations provide a way of optimizing access to the [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variables which are associated with the current processor. In our case it is `this_cpu_read`:
|
||||||
|
|
||||||
```
|
```
|
||||||
__pcpu_size_call_return(this_cpu_read_, pcp)
|
__pcpu_size_call_return(this_cpu_read_, pcp)
|
||||||
@ -346,7 +346,7 @@ static inline int __check_is_bitmap(const unsigned long *bitmap)
|
|||||||
|
|
||||||
Yeah, it just returns `1` every time. Actually we need in it here only for one purpose: at compile time it checks that the given `bitmap` is a bitmap, or in other words it checks that the given `bitmap` has a type of `unsigned long *`. So we just pass `cpu_possible_bits` to the `to_cpumask` macro for converting the array of `unsigned long` to the `struct cpumask *`. Now we can call `cpumask_set_cpu` function with the `cpu` - 0 and `struct cpumask *cpu_possible_bits`. This function makes only one call of the `set_bit` function which sets the given `cpu` in the cpumask. All of these `set_cpu_*` functions work on the same principle.
|
Yeah, it just returns `1` every time. Actually we need in it here only for one purpose: at compile time it checks that the given `bitmap` is a bitmap, or in other words it checks that the given `bitmap` has a type of `unsigned long *`. So we just pass `cpu_possible_bits` to the `to_cpumask` macro for converting the array of `unsigned long` to the `struct cpumask *`. Now we can call `cpumask_set_cpu` function with the `cpu` - 0 and `struct cpumask *cpu_possible_bits`. This function makes only one call of the `set_bit` function which sets the given `cpu` in the cpumask. All of these `set_cpu_*` functions work on the same principle.
|
||||||
|
|
||||||
If you're not sure that this `set_cpu_*` operations and `cpumask` are not clear for you, don't worry about it. You can get more info by reading the special part about it - [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) or [documentation](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt).
|
If you're not sure that this `set_cpu_*` operations and `cpumask` are not clear for you, don't worry about it. You can get more info by reading the special part about it - [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) or [documentation](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt).
|
||||||
|
|
||||||
As we activated the bootstrap processor, it's time to go to the next function in the `start_kernel.` Now it is `page_address_init`, but this function does nothing in our case, because it executes only when all `RAM` can't be mapped directly.
|
As we activated the bootstrap processor, it's time to go to the next function in the `start_kernel.` Now it is `page_address_init`, but this function does nothing in our case, because it executes only when all `RAM` can't be mapped directly.
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ int __init acpi_mps_check(void)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
It checks the built-in `MPS` or [MultiProcessor Specification](http://en.wikipedia.org/wiki/MultiProcessor_Specification) table. If `CONFIG_X86_LOCAL_APIC` is set and `CONFIG_x86_MPPAARSE` is not set, `acpi_mps_check` prints warning message if the one of the command line options: `acpi=off`, `acpi=noirq` or `pci=noacpi` passed to the kernel. If `acpi_mps_check` returns `1` it means that we disable local [APIC](http://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller) and clear `X86_FEATURE_APIC` bit in the of the current CPU with the `setup_clear_cpu_cap` macro. (more about CPU mask you can read in the [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)).
|
It checks the built-in `MPS` or [MultiProcessor Specification](http://en.wikipedia.org/wiki/MultiProcessor_Specification) table. If `CONFIG_X86_LOCAL_APIC` is set and `CONFIG_x86_MPPAARSE` is not set, `acpi_mps_check` prints warning message if the one of the command line options: `acpi=off`, `acpi=noirq` or `pci=noacpi` passed to the kernel. If `acpi_mps_check` returns `1` it means that we disable local [APIC](http://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller) and clear `X86_FEATURE_APIC` bit in the of the current CPU with the `setup_clear_cpu_cap` macro. (more about CPU mask you can read in the [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)).
|
||||||
|
|
||||||
Early PCI dump
|
Early PCI dump
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -535,7 +535,7 @@ Links
|
|||||||
* [NX bit](http://en.wikipedia.org/wiki/NX_bit)
|
* [NX bit](http://en.wikipedia.org/wiki/NX_bit)
|
||||||
* [Documentation/kernel-parameters.txt](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/Documentation/kernel-parameters.txt)
|
* [Documentation/kernel-parameters.txt](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/Documentation/kernel-parameters.txt)
|
||||||
* [APIC](http://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller)
|
* [APIC](http://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller)
|
||||||
* [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
* [Linux kernel memory management](http://0xax.gitbooks.io/linux-insides/content/MM/index.html)
|
* [Linux kernel memory management](http://0xax.gitbooks.io/linux-insides/content/MM/index.html)
|
||||||
* [PCI](http://en.wikipedia.org/wiki/Conventional_PCI)
|
* [PCI](http://en.wikipedia.org/wiki/Conventional_PCI)
|
||||||
* [e820](http://en.wikipedia.org/wiki/E820)
|
* [e820](http://en.wikipedia.org/wiki/E820)
|
||||||
|
@ -320,7 +320,7 @@ if (acpi_lapic && early)
|
|||||||
return;
|
return;
|
||||||
```
|
```
|
||||||
|
|
||||||
Here we can see that multiprocessor configuration was found in the `smp_scan_config` function or just return from the function if not. The next check is `acpi_lapic` and `early`. And as we did this checks, we start to read the `SMP` configuration. As we finished reading it, the next step is - `prefill_possible_map` function which makes preliminary filling of the possible CPU's `cpumask` (more about it you can read in the [Introduction to the cpumasks](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)).
|
Here we can see that multiprocessor configuration was found in the `smp_scan_config` function or just return from the function if not. The next check is `acpi_lapic` and `early`. And as we did this checks, we start to read the `SMP` configuration. As we finished reading it, the next step is - `prefill_possible_map` function which makes preliminary filling of the possible CPU's `cpumask` (more about it you can read in the [Introduction to the cpumasks](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)).
|
||||||
|
|
||||||
The rest of the setup_arch
|
The rest of the setup_arch
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -334,7 +334,7 @@ That's all, and now we can back to the `start_kernel` from the `setup_arch`.
|
|||||||
Back to the main.c
|
Back to the main.c
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
As I wrote above, we have finished with the `setup_arch` function and now we can back to the `start_kernel` function from the [init/main.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/init/main.c). As you may remember or saw yourself, `start_kernel` function as big as the `setup_arch`. So the couple of the next part will be dedicated to learning of this function. So, let's continue with it. After the `setup_arch` we can see the call of the `mm_init_cpumask` function. This function sets the [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) pointer to the memory descriptor `cpumask`. We can look on its implementation:
|
As I wrote above, we have finished with the `setup_arch` function and now we can back to the `start_kernel` function from the [init/main.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/init/main.c). As you may remember or saw yourself, `start_kernel` function as big as the `setup_arch`. So the couple of the next part will be dedicated to learning of this function. So, let's continue with it. After the `setup_arch` we can see the call of the `mm_init_cpumask` function. This function sets the [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) pointer to the memory descriptor `cpumask`. We can look on its implementation:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
static inline void mm_init_cpumask(struct mm_struct *mm)
|
static inline void mm_init_cpumask(struct mm_struct *mm)
|
||||||
@ -379,7 +379,7 @@ static void __init setup_command_line(char *command_line)
|
|||||||
|
|
||||||
Here we can see that we allocate space for the three buffers which will contain kernel command line for the different purposes (read above). And as we allocated space, we store `boot_command_line` in the `saved_command_line` and `command_line` (kernel command line from the `setup_arch`) to the `static_command_line`.
|
Here we can see that we allocate space for the three buffers which will contain kernel command line for the different purposes (read above). And as we allocated space, we store `boot_command_line` in the `saved_command_line` and `command_line` (kernel command line from the `setup_arch`) to the `static_command_line`.
|
||||||
|
|
||||||
The next function after the `setup_command_line` is the `setup_nr_cpu_ids`. This function setting `nr_cpu_ids` (number of CPUs) according to the last bit in the `cpu_possible_mask` (more about it you can read in the chapter describes [cpumasks](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) concept). Let's look on its implementation:
|
The next function after the `setup_command_line` is the `setup_nr_cpu_ids`. This function setting `nr_cpu_ids` (number of CPUs) according to the last bit in the `cpu_possible_mask` (more about it you can read in the chapter describes [cpumasks](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) concept). Let's look on its implementation:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
void __init setup_nr_cpu_ids(void)
|
void __init setup_nr_cpu_ids(void)
|
||||||
|
@ -6,7 +6,7 @@ Scheduler initialization
|
|||||||
|
|
||||||
This is the eighth [part](http://0xax.gitbooks.io/linux-insides/content/Initialization/index.html) of the Linux kernel initialization process chapter and we stopped on the `setup_nr_cpu_ids` function in the [previous part](https://github.com/0xAX/linux-insides/blob/master/Initialization/linux-initialization-7.md).
|
This is the eighth [part](http://0xax.gitbooks.io/linux-insides/content/Initialization/index.html) of the Linux kernel initialization process chapter and we stopped on the `setup_nr_cpu_ids` function in the [previous part](https://github.com/0xAX/linux-insides/blob/master/Initialization/linux-initialization-7.md).
|
||||||
|
|
||||||
The main point of this part is [scheduler](http://en.wikipedia.org/wiki/Scheduling_%28computing%29) initialization. But before we will start to learn initialization process of the scheduler, we need to do some stuff. The next step in the [init/main.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/init/main.c) is the `setup_per_cpu_areas` function. This function setups memory areas for the `percpu` variables, more about it you can read in the special part about the [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html). After `percpu` areas is up and running, the next step is the `smp_prepare_boot_cpu` function.
|
The main point of this part is [scheduler](http://en.wikipedia.org/wiki/Scheduling_%28computing%29) initialization. But before we will start to learn initialization process of the scheduler, we need to do some stuff. The next step in the [init/main.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/init/main.c) is the `setup_per_cpu_areas` function. This function setups memory areas for the `percpu` variables, more about it you can read in the special part about the [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html). After `percpu` areas is up and running, the next step is the `smp_prepare_boot_cpu` function.
|
||||||
|
|
||||||
This function does some preparations for [symmetric multiprocessing](http://en.wikipedia.org/wiki/Symmetric_multiprocessing). Since this function is architecture specific, it is located in the [arch/x86/include/asm/smp.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/include/asm/smp.h#L78) Linux kernel header file. Let's look at the definition of this function:
|
This function does some preparations for [symmetric multiprocessing](http://en.wikipedia.org/wiki/Symmetric_multiprocessing). Since this function is architecture specific, it is located in the [arch/x86/include/asm/smp.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/include/asm/smp.h#L78) Linux kernel header file. Let's look at the definition of this function:
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
more about `percpu` variables you can read in the [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) part. As we got address and size of the `GDT` descriptor we reload `GDT` with the `load_gdt` which just execute `lgdt` instruct and load `percpu_segment` with the following function:
|
more about `percpu` variables you can read in the [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) part. As we got address and size of the `GDT` descriptor we reload `GDT` with the `load_gdt` which just execute `lgdt` instruct and load `percpu_segment` with the following function:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
void load_percpu_segment(int cpu) {
|
void load_percpu_segment(int cpu) {
|
||||||
@ -230,7 +230,7 @@ pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18,
|
|||||||
```
|
```
|
||||||
|
|
||||||
The number of elements of the `pid_hash` depends on the `RAM` configuration, but it can be between `2^4` and `2^12`. The `pidhash_init` computes the size
|
The number of elements of the `pid_hash` depends on the `RAM` configuration, but it can be between `2^4` and `2^12`. The `pidhash_init` computes the size
|
||||||
and allocates the required storage (which is `hlist` in our case - the same as [doubly linked list](http://0xax.gitbooks.io/linux-insides/content/DataStructures/dlist.html), but contains one pointer instead on the [struct hlist_head](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/types.h)]. The `alloc_large_system_hash` function allocates a large system hash table with `memblock_virt_alloc_nopanic` if we pass `HASH_EARLY` flag (as it in our case) or with `__vmalloc` if we did no pass this flag.
|
and allocates the required storage (which is `hlist` in our case - the same as [doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html), but contains one pointer instead on the [struct hlist_head](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/types.h)]. The `alloc_large_system_hash` function allocates a large system hash table with `memblock_virt_alloc_nopanic` if we pass `HASH_EARLY` flag (as it in our case) or with `__vmalloc` if we did no pass this flag.
|
||||||
|
|
||||||
The result we can see in the `dmesg` output:
|
The result we can see in the `dmesg` output:
|
||||||
|
|
||||||
@ -555,7 +555,7 @@ If you have any questions or suggestions write me a comment or ping me at [twitt
|
|||||||
Links
|
Links
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
* [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
* [high-resolution kernel timer](https://www.kernel.org/doc/Documentation/timers/hrtimers.txt)
|
* [high-resolution kernel timer](https://www.kernel.org/doc/Documentation/timers/hrtimers.txt)
|
||||||
* [spinlock](http://en.wikipedia.org/wiki/Spinlock)
|
* [spinlock](http://en.wikipedia.org/wiki/Spinlock)
|
||||||
* [Run queue](http://en.wikipedia.org/wiki/Run_queue)
|
* [Run queue](http://en.wikipedia.org/wiki/Run_queue)
|
||||||
@ -565,7 +565,7 @@ Links
|
|||||||
* [Linux kernel hotplug documentation](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt)
|
* [Linux kernel hotplug documentation](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt)
|
||||||
* [IRQ](http://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
* [IRQ](http://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
||||||
* [Global Descriptor Table](http://en.wikipedia.org/wiki/Global_Descriptor_Table)
|
* [Global Descriptor Table](http://en.wikipedia.org/wiki/Global_Descriptor_Table)
|
||||||
* [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [SMP](http://en.wikipedia.org/wiki/Symmetric_multiprocessing)
|
* [SMP](http://en.wikipedia.org/wiki/Symmetric_multiprocessing)
|
||||||
* [RCU](http://en.wikipedia.org/wiki/Read-copy-update)
|
* [RCU](http://en.wikipedia.org/wiki/Read-copy-update)
|
||||||
* [CFS Scheduler documentation](https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt)
|
* [CFS Scheduler documentation](https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt)
|
||||||
|
@ -38,7 +38,7 @@ In the first implementation of the `preempt_disable` we increment this `__preemp
|
|||||||
#define preempt_count_add(val) __preempt_count_add(val)
|
#define preempt_count_add(val) __preempt_count_add(val)
|
||||||
```
|
```
|
||||||
|
|
||||||
where `preempt_count_add` calls the `raw_cpu_add_4` macro which adds `1` to the given `percpu` variable (`__preempt_count`) in our case (more about `precpu` variables you can read in the part about [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)). Ok, we increased `__preempt_count` and the next step we can see the call of the `barrier` macro in the both macros. The `barrier` macro inserts an optimization barrier. In the processors with `x86_64` architecture independent memory access operations can be performed in any order. That's why we need the opportunity to point compiler and processor on compliance of order. This mechanism is memory barrier. Let's consider a simple example:
|
where `preempt_count_add` calls the `raw_cpu_add_4` macro which adds `1` to the given `percpu` variable (`__preempt_count`) in our case (more about `precpu` variables you can read in the part about [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)). Ok, we increased `__preempt_count` and the next step we can see the call of the `barrier` macro in the both macros. The `barrier` macro inserts an optimization barrier. In the processors with `x86_64` architecture independent memory access operations can be performed in any order. That's why we need the opportunity to point compiler and processor on compliance of order. This mechanism is memory barrier. Let's consider a simple example:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
@ -127,7 +127,7 @@ The next step is [RCU](http://en.wikipedia.org/wiki/Read-copy-update) initializa
|
|||||||
|
|
||||||
In the first case `rcu_init` will be in the [kernel/rcu/tiny.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/rcu/tiny.c) and in the second case it will be defined in the [kernel/rcu/tree.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/rcu/tree.c). We will see the implementation of the `tree rcu`, but first of all about the `RCU` in general.
|
In the first case `rcu_init` will be in the [kernel/rcu/tiny.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/rcu/tiny.c) and in the second case it will be defined in the [kernel/rcu/tree.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/rcu/tree.c). We will see the implementation of the `tree rcu`, but first of all about the `RCU` in general.
|
||||||
|
|
||||||
`RCU` or read-copy update is a scalable high-performance synchronization mechanism implemented in the Linux kernel. On the early stage the linux kernel provided support and environment for the concurrently running applications, but all execution was serialized in the kernel using a single global lock. In our days linux kernel has no single global lock, but provides different mechanisms including [lock-free data structures](http://en.wikipedia.org/wiki/Concurrent_data_structure), [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) data structures and other. One of these mechanisms is - the `read-copy update`. The `RCU` technique is designed for rarely-modified data structures. The idea of the `RCU` is simple. For example we have a rarely-modified data structure. If somebody wants to change this data structure, we make a copy of this data structure and make all changes in the copy. In the same time all other users of the data structure use old version of it. Next, we need to choose safe moment when original version of the data structure will have no users and update it with the modified copy.
|
`RCU` or read-copy update is a scalable high-performance synchronization mechanism implemented in the Linux kernel. On the early stage the linux kernel provided support and environment for the concurrently running applications, but all execution was serialized in the kernel using a single global lock. In our days linux kernel has no single global lock, but provides different mechanisms including [lock-free data structures](http://en.wikipedia.org/wiki/Concurrent_data_structure), [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) data structures and other. One of these mechanisms is - the `read-copy update`. The `RCU` technique is designed for rarely-modified data structures. The idea of the `RCU` is simple. For example we have a rarely-modified data structure. If somebody wants to change this data structure, we make a copy of this data structure and make all changes in the copy. In the same time all other users of the data structure use old version of it. Next, we need to choose safe moment when original version of the data structure will have no users and update it with the modified copy.
|
||||||
|
|
||||||
Of course this description of the `RCU` is very simplified. To understand some details about `RCU`, first of all we need to learn some terminology. Data readers in the `RCU` executed in the [critical section](http://en.wikipedia.org/wiki/Critical_section). Every time when data reader get to the critical section, it calls the `rcu_read_lock`, and `rcu_read_unlock` on exit from the critical section. If the thread is not in the critical section, it will be in state which called - `quiescent state`. The moment when every thread is in the `quiescent state` called - `grace period`. If a thread wants to remove an element from the data structure, this occurs in two steps. First step is `removal` - atomically removes element from the data structure, but does not release the physical memory. After this thread-writer announces and waits until it is finished. From this moment, the removed element is available to the thread-readers. After the `grace period` finished, the second step of the element removal will be started, it just removes the element from the physical memory.
|
Of course this description of the `RCU` is very simplified. To understand some details about `RCU`, first of all we need to learn some terminology. Data readers in the `RCU` executed in the [critical section](http://en.wikipedia.org/wiki/Critical_section). Every time when data reader get to the critical section, it calls the `rcu_read_lock`, and `rcu_read_unlock` on exit from the critical section. If the thread is not in the critical section, it will be in state which called - `quiescent state`. The moment when every thread is in the `quiescent state` called - `grace period`. If a thread wants to remove an element from the data structure, this occurs in two steps. First step is `removal` - atomically removes element from the data structure, but does not release the physical memory. After this thread-writer announces and waits until it is finished. From this moment, the removed element is available to the thread-readers. After the `grace period` finished, the second step of the element removal will be started, it just removes the element from the physical memory.
|
||||||
|
|
||||||
@ -378,7 +378,7 @@ Ok, we already passed the main theme of this part which is `RCU` initialization,
|
|||||||
|
|
||||||
After we initialized `RCU`, the next step which you can see in the [init/main.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/init/main.c) is the - `trace_init` function. As you can understand from its name, this function initialize [tracing](http://en.wikipedia.org/wiki/Tracing_%28software%29) subsystem. You can read more about linux kernel trace system - [here](http://elinux.org/Kernel_Trace_Systems).
|
After we initialized `RCU`, the next step which you can see in the [init/main.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/init/main.c) is the - `trace_init` function. As you can understand from its name, this function initialize [tracing](http://en.wikipedia.org/wiki/Tracing_%28software%29) subsystem. You can read more about linux kernel trace system - [here](http://elinux.org/Kernel_Trace_Systems).
|
||||||
|
|
||||||
After the `trace_init`, we can see the call of the `radix_tree_init`. If you are familiar with the different data structures, you can understand from the name of this function that it initializes kernel implementation of the [Radix tree](http://en.wikipedia.org/wiki/Radix_tree). This function is defined in the [lib/radix-tree.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/lib/radix-tree.c) and you can read more about it in the part about [Radix tree](https://0xax.gitbooks.io/linux-insides/content/DataStructures/radix-tree.html).
|
After the `trace_init`, we can see the call of the `radix_tree_init`. If you are familiar with the different data structures, you can understand from the name of this function that it initializes kernel implementation of the [Radix tree](http://en.wikipedia.org/wiki/Radix_tree). This function is defined in the [lib/radix-tree.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/lib/radix-tree.c) and you can read more about it in the part about [Radix tree](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-2.html).
|
||||||
|
|
||||||
In the next step we can see the functions which are related to the `interrupts handling` subsystem, they are:
|
In the next step we can see the functions which are related to the `interrupts handling` subsystem, they are:
|
||||||
|
|
||||||
@ -423,7 +423,7 @@ Links
|
|||||||
* [integer ID management](https://lwn.net/Articles/103209/)
|
* [integer ID management](https://lwn.net/Articles/103209/)
|
||||||
* [Documentation/memory-barriers.txt](https://www.kernel.org/doc/Documentation/memory-barriers.txt)
|
* [Documentation/memory-barriers.txt](https://www.kernel.org/doc/Documentation/memory-barriers.txt)
|
||||||
* [Runtime locking correctness validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
|
* [Runtime locking correctness validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
|
||||||
* [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [Linux kernel memory management](http://0xax.gitbooks.io/linux-insides/content/MM/index.html)
|
* [Linux kernel memory management](http://0xax.gitbooks.io/linux-insides/content/MM/index.html)
|
||||||
* [slab](http://en.wikipedia.org/wiki/Slab_allocation)
|
* [slab](http://en.wikipedia.org/wiki/Slab_allocation)
|
||||||
* [i2c](http://en.wikipedia.org/wiki/I%C2%B2C)
|
* [i2c](http://en.wikipedia.org/wiki/I%C2%B2C)
|
||||||
|
@ -306,7 +306,7 @@ union irq_stack_union {
|
|||||||
|
|
||||||
The first `irq_stack` field is a 16 kilobytes array. Also you can see that `irq_stack_union` contains a structure with the two fields:
|
The first `irq_stack` field is a 16 kilobytes array. Also you can see that `irq_stack_union` contains a structure with the two fields:
|
||||||
|
|
||||||
* `gs_base` - The `gs` register always points to the bottom of the `irqstack` union. On the `x86_64`, the `gs` register is shared by per-cpu area and stack canary (more about `per-cpu` variables you can read in the special [part](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)). All per-cpu symbols are zero based and the `gs` points to the base of the per-cpu area. You already know that [segmented memory model](http://en.wikipedia.org/wiki/Memory_segmentation) is abolished in the long mode, but we can set the base address for the two segment registers - `fs` and `gs` with the [Model specific registers](http://en.wikipedia.org/wiki/Model-specific_register) and these registers can be still be used as address registers. If you remember the first [part](http://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-1.html) of the Linux kernel initialization process, you can remember that we have set the `gs` register:
|
* `gs_base` - The `gs` register always points to the bottom of the `irqstack` union. On the `x86_64`, the `gs` register is shared by per-cpu area and stack canary (more about `per-cpu` variables you can read in the special [part](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)). All per-cpu symbols are zero based and the `gs` points to the base of the per-cpu area. You already know that [segmented memory model](http://en.wikipedia.org/wiki/Memory_segmentation) is abolished in the long mode, but we can set the base address for the two segment registers - `fs` and `gs` with the [Model specific registers](http://en.wikipedia.org/wiki/Model-specific_register) and these registers can be still be used as address registers. If you remember the first [part](http://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-1.html) of the Linux kernel initialization process, you can remember that we have set the `gs` register:
|
||||||
|
|
||||||
```assembly
|
```assembly
|
||||||
movl $MSR_GS_BASE,%ecx
|
movl $MSR_GS_BASE,%ecx
|
||||||
|
@ -346,7 +346,7 @@ common_interrupt:
|
|||||||
interrupt do_IRQ
|
interrupt do_IRQ
|
||||||
```
|
```
|
||||||
|
|
||||||
The macro `interrupt` defined in the same source code file and saves [general purpose](https://en.wikipedia.org/wiki/Processor_register) registers on the stack, change the userspace `gs` on the kernel with the `SWAPGS` assembler instruction if need, increase [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) - `irq_count` variable that shows that we are in interrupt and call the `do_IRQ` function. This function defined in the [arch/x86/kernel/irq.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/kernel/irq.c) source code file and handles our device interrupt. Let's look at this function. The `do_IRQ` function takes one parameter - `pt_regs` structure that stores values of the userspace registers:
|
The macro `interrupt` defined in the same source code file and saves [general purpose](https://en.wikipedia.org/wiki/Processor_register) registers on the stack, change the userspace `gs` on the kernel with the `SWAPGS` assembler instruction if need, increase [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) - `irq_count` variable that shows that we are in interrupt and call the `do_IRQ` function. This function defined in the [arch/x86/kernel/irq.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/kernel/irq.c) source code file and handles our device interrupt. Let's look at this function. The `do_IRQ` function takes one parameter - `pt_regs` structure that stores values of the userspace registers:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
__visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
|
__visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
|
||||||
@ -413,7 +413,7 @@ We already know that when an `IRQ` finishes its work, deferred interrupts will b
|
|||||||
Exit from interrupt
|
Exit from interrupt
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Ok, the interrupt handler finished its execution and now we must return from the interrupt. When the work of the `do_IRQ` function will be finsihed, we will return back to the assembler code in the [arch/x86/entry/entry_64.S](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/entry_entry_64.S) to the `ret_from_intr` label. First of all we disable interrupts with the `DISABLE_INTERRUPTS` macro that expands to the `cli` instruction and decreases value of the `irq_count` [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variable. Remember, this variable had value - `1`, when we were in interrupt context:
|
Ok, the interrupt handler finished its execution and now we must return from the interrupt. When the work of the `do_IRQ` function will be finsihed, we will return back to the assembler code in the [arch/x86/entry/entry_64.S](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/entry_entry_64.S) to the `ret_from_intr` label. First of all we disable interrupts with the `DISABLE_INTERRUPTS` macro that expands to the `cli` instruction and decreases value of the `irq_count` [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variable. Remember, this variable had value - `1`, when we were in interrupt context:
|
||||||
|
|
||||||
```assembly
|
```assembly
|
||||||
DISABLE_INTERRUPTS(CLBR_NONE)
|
DISABLE_INTERRUPTS(CLBR_NONE)
|
||||||
@ -469,7 +469,7 @@ Links
|
|||||||
* [APIC](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller)
|
* [APIC](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller)
|
||||||
* [GNU assembler](https://en.wikipedia.org/wiki/GNU_Assembler)
|
* [GNU assembler](https://en.wikipedia.org/wiki/GNU_Assembler)
|
||||||
* [Processor register](https://en.wikipedia.org/wiki/Processor_register)
|
* [Processor register](https://en.wikipedia.org/wiki/Processor_register)
|
||||||
* [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [pid](https://en.wikipedia.org/wiki/Process_identifier)
|
* [pid](https://en.wikipedia.org/wiki/Process_identifier)
|
||||||
* [device tree](https://en.wikipedia.org/wiki/Device_tree)
|
* [device tree](https://en.wikipedia.org/wiki/Device_tree)
|
||||||
* [system calls](https://en.wikipedia.org/wiki/System_call)
|
* [system calls](https://en.wikipedia.org/wiki/System_call)
|
||||||
|
@ -245,7 +245,7 @@ static inline void boot_init_stack_canary(void)
|
|||||||
#endif
|
#endif
|
||||||
```
|
```
|
||||||
|
|
||||||
If the `CONFIG_CC_STACKPROTECTOR` kernel configuration option is set, the `boot_init_stack_canary` function starts from the check stat `irq_stack_union` that represents [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) interrupt stack has offset equal to forty bytes from the `stack_canary` value:
|
If the `CONFIG_CC_STACKPROTECTOR` kernel configuration option is set, the `boot_init_stack_canary` function starts from the check stat `irq_stack_union` that represents [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) interrupt stack has offset equal to forty bytes from the `stack_canary` value:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
@ -516,7 +516,7 @@ Links
|
|||||||
* [system call](http://en.wikipedia.org/wiki/System_call)
|
* [system call](http://en.wikipedia.org/wiki/System_call)
|
||||||
* [swapgs](http://www.felixcloutier.com/x86/SWAPGS.html)
|
* [swapgs](http://www.felixcloutier.com/x86/SWAPGS.html)
|
||||||
* [SIGTRAP](https://en.wikipedia.org/wiki/Unix_signal#SIGTRAP)
|
* [SIGTRAP](https://en.wikipedia.org/wiki/Unix_signal#SIGTRAP)
|
||||||
* [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [Per-CPU variables](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [kgdb](https://en.wikipedia.org/wiki/KGDB)
|
* [kgdb](https://en.wikipedia.org/wiki/KGDB)
|
||||||
* [ACPI](https://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface)
|
* [ACPI](https://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface)
|
||||||
* [Previous part](http://0xax.gitbooks.io/linux-insides/content/Interrupts/index.html)
|
* [Previous part](http://0xax.gitbooks.io/linux-insides/content/Interrupts/index.html)
|
||||||
|
@ -300,7 +300,7 @@ In the next step we fill the `used_vectors` array which defined in the [arch/x86
|
|||||||
DECLARE_BITMAP(used_vectors, NR_VECTORS);
|
DECLARE_BITMAP(used_vectors, NR_VECTORS);
|
||||||
```
|
```
|
||||||
|
|
||||||
of the first `32` interrupts (more about bitmaps in the Linux kernel you can read in the part which describes [cpumasks and bitmaps](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html))
|
of the first `32` interrupts (more about bitmaps in the Linux kernel you can read in the part which describes [cpumasks and bitmaps](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html))
|
||||||
|
|
||||||
```C
|
```C
|
||||||
for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
|
for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
|
||||||
@ -459,7 +459,7 @@ Links
|
|||||||
* [x87 FPU](https://en.wikipedia.org/wiki/X86_instruction_listings#x87_floating-point_instructions)
|
* [x87 FPU](https://en.wikipedia.org/wiki/X86_instruction_listings#x87_floating-point_instructions)
|
||||||
* [MCE exception](https://en.wikipedia.org/wiki/Machine-check_exception)
|
* [MCE exception](https://en.wikipedia.org/wiki/Machine-check_exception)
|
||||||
* [SIMD](https://en.wikipedia.org/?title=SIMD)
|
* [SIMD](https://en.wikipedia.org/?title=SIMD)
|
||||||
* [cpumasks and bitmaps](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [cpumasks and bitmaps](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
* [NX](https://en.wikipedia.org/wiki/NX_bit)
|
* [NX](https://en.wikipedia.org/wiki/NX_bit)
|
||||||
* [Task State Segment](https://en.wikipedia.org/wiki/Task_state_segment)
|
* [Task State Segment](https://en.wikipedia.org/wiki/Task_state_segment)
|
||||||
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-3.html)
|
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-3.html)
|
||||||
|
@ -260,7 +260,7 @@ Now let's look on the `do_nmi` exception handler. This function defined in the [
|
|||||||
* address of the `pt_regs`;
|
* address of the `pt_regs`;
|
||||||
* error code.
|
* error code.
|
||||||
|
|
||||||
as all exception handlers. The `do_nmi` starts from the call of the `nmi_nesting_preprocess` function and ends with the call of the `nmi_nesting_postprocess`. The `nmi_nesting_preprocess` function checks that we likely do not work with the debug stack and if we on the debug stack set the `update_debug_stack` [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variable to `1` and call the `debug_stack_set_zero` function from the [arch/x86/kernel/cpu/common.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/kernel/cpu/common.c). This function increases the `debug_stack_use_ctr` per-cpu variable and loads new `Interrupt Descriptor Table`:
|
as all exception handlers. The `do_nmi` starts from the call of the `nmi_nesting_preprocess` function and ends with the call of the `nmi_nesting_postprocess`. The `nmi_nesting_preprocess` function checks that we likely do not work with the debug stack and if we on the debug stack set the `update_debug_stack` [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variable to `1` and call the `debug_stack_set_zero` function from the [arch/x86/kernel/cpu/common.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/kernel/cpu/common.c). This function increases the `debug_stack_use_ctr` per-cpu variable and loads new `Interrupt Descriptor Table`:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
static inline void nmi_nesting_preprocess(struct pt_regs *regs)
|
static inline void nmi_nesting_preprocess(struct pt_regs *regs)
|
||||||
@ -473,7 +473,7 @@ Links
|
|||||||
* [Global Descriptor Table](https://en.wikipedia.org/wiki/Global_Descriptor_Table)
|
* [Global Descriptor Table](https://en.wikipedia.org/wiki/Global_Descriptor_Table)
|
||||||
* [stack frame](https://en.wikipedia.org/wiki/Call_stack)
|
* [stack frame](https://en.wikipedia.org/wiki/Call_stack)
|
||||||
* [Model Specific regiser](https://en.wikipedia.org/wiki/Model-specific_register)
|
* [Model Specific regiser](https://en.wikipedia.org/wiki/Model-specific_register)
|
||||||
* [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [RCU](https://en.wikipedia.org/wiki/Read-copy-update)
|
* [RCU](https://en.wikipedia.org/wiki/Read-copy-update)
|
||||||
* [MPX](https://en.wikipedia.org/wiki/Intel_MPX)
|
* [MPX](https://en.wikipedia.org/wiki/Intel_MPX)
|
||||||
* [x87 FPU](https://en.wikipedia.org/wiki/X87)
|
* [x87 FPU](https://en.wikipedia.org/wiki/X87)
|
||||||
|
@ -95,7 +95,7 @@ More about this will be in the another chapter about the `NUMA`. The next step a
|
|||||||
init_irq_default_affinity();
|
init_irq_default_affinity();
|
||||||
```
|
```
|
||||||
|
|
||||||
function. The `init_irq_default_affinity` function defined in the same source code file and depends on the `CONFIG_SMP` kernel configuration option allocates a given [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) structure (in our case it is the `irq_default_affinity`):
|
function. The `init_irq_default_affinity` function defined in the same source code file and depends on the `CONFIG_SMP` kernel configuration option allocates a given [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) structure (in our case it is the `irq_default_affinity`):
|
||||||
|
|
||||||
```C
|
```C
|
||||||
#if defined(CONFIG_SMP)
|
#if defined(CONFIG_SMP)
|
||||||
@ -207,7 +207,7 @@ for (i = 0; i < count; i++) {
|
|||||||
|
|
||||||
We are going through the all interrupt descriptors and do the following things:
|
We are going through the all interrupt descriptors and do the following things:
|
||||||
|
|
||||||
First of all we allocate [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variable for the `irq` kernel statistic with the `alloc_percpu` macro. This macro allocates one instance of an object of the given type for every processor on the system. You can access kernel statistic from the userspace via `/proc/stat`:
|
First of all we allocate [percpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variable for the `irq` kernel statistic with the `alloc_percpu` macro. This macro allocates one instance of an object of the given type for every processor on the system. You can access kernel statistic from the userspace via `/proc/stat`:
|
||||||
|
|
||||||
```
|
```
|
||||||
~$ cat /proc/stat
|
~$ cat /proc/stat
|
||||||
@ -221,7 +221,7 @@ cpu3 26648 8 6931 678891 414 0 244 0 0 0
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
Where the sixth column is the servicing interrupts. After this we allocate [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) for the given irq descriptor affinity and initialize the [spinlock](https://en.wikipedia.org/wiki/Spinlock) for the given interrupt descriptor. After this before the [critical section](https://en.wikipedia.org/wiki/Critical_section), the lock will be acquired with a call of the `raw_spin_lock` and unlocked with the call of the `raw_spin_unlock`. In the next step we call the `lockdep_set_class` macro which set the [Lock validator](https://lwn.net/Articles/185666/) `irq_desc_lock_class` class for the lock of the given interrupt descriptor. More about `lockdep`, `spinlock` and other synchronization primitives will be described in the separate chapter.
|
Where the sixth column is the servicing interrupts. After this we allocate [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) for the given irq descriptor affinity and initialize the [spinlock](https://en.wikipedia.org/wiki/Spinlock) for the given interrupt descriptor. After this before the [critical section](https://en.wikipedia.org/wiki/Critical_section), the lock will be acquired with a call of the `raw_spin_lock` and unlocked with the call of the `raw_spin_unlock`. In the next step we call the `lockdep_set_class` macro which set the [Lock validator](https://lwn.net/Articles/185666/) `irq_desc_lock_class` class for the lock of the given interrupt descriptor. More about `lockdep`, `spinlock` and other synchronization primitives will be described in the separate chapter.
|
||||||
|
|
||||||
In the end of the loop we call the `desc_set_defaults` function from the [kernel/irq/irqdesc.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/irq/irqdesc.c). This function takes four parameters:
|
In the end of the loop we call the `desc_set_defaults` function from the [kernel/irq/irqdesc.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/irq/irqdesc.c). This function takes four parameters:
|
||||||
|
|
||||||
@ -275,7 +275,7 @@ desc->owner = owner;
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
After this we go through the all [possible](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) processor with the [for_each_possible_cpu](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/cpumask.h#L714) helper and set the `kstat_irqs` to zero for the given interrupt descriptor:
|
After this we go through the all [possible](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) processor with the [for_each_possible_cpu](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/cpumask.h#L714) helper and set the `kstat_irqs` to zero for the given interrupt descriptor:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
for_each_possible_cpu(cpu)
|
for_each_possible_cpu(cpu)
|
||||||
@ -413,7 +413,7 @@ if (WARN_ON(initcnt > IRQ_BITMAP_BITS))
|
|||||||
initcnt = IRQ_BITMAP_BITS;
|
initcnt = IRQ_BITMAP_BITS;
|
||||||
```
|
```
|
||||||
|
|
||||||
where `IRQ_BITMAP_BITS` is equal to the `NR_IRQS` if the `CONFIG_SPARSE_IRQ` is not set and `NR_IRQS + 8196` in other way. In the next step we are going over all interrupt descriptors which need to be allocated in the loop and allocate space for the descriptor and insert to the `irq_desc_tree` [radix tree](http://0xax.gitbooks.io/linux-insides/content/DataStructures/radix-tree.html):
|
where `IRQ_BITMAP_BITS` is equal to the `NR_IRQS` if the `CONFIG_SPARSE_IRQ` is not set and `NR_IRQS + 8196` in other way. In the next step we are going over all interrupt descriptors which need to be allocated in the loop and allocate space for the descriptor and insert to the `irq_desc_tree` [radix tree](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-2.html):
|
||||||
|
|
||||||
```C
|
```C
|
||||||
for (i = 0; i < initcnt; i++) {
|
for (i = 0; i < initcnt; i++) {
|
||||||
@ -446,8 +446,8 @@ Links
|
|||||||
* [IRQ](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
* [IRQ](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
||||||
* [numa](https://en.wikipedia.org/wiki/Non-uniform_memory_access)
|
* [numa](https://en.wikipedia.org/wiki/Non-uniform_memory_access)
|
||||||
* [Enum type](https://en.wikipedia.org/wiki/Enumerated_type)
|
* [Enum type](https://en.wikipedia.org/wiki/Enumerated_type)
|
||||||
* [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [cpumask](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
* [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [spinlock](https://en.wikipedia.org/wiki/Spinlock)
|
* [spinlock](https://en.wikipedia.org/wiki/Spinlock)
|
||||||
* [critical section](https://en.wikipedia.org/wiki/Critical_section)
|
* [critical section](https://en.wikipedia.org/wiki/Critical_section)
|
||||||
* [Lock validator](https://lwn.net/Articles/185666/)
|
* [Lock validator](https://lwn.net/Articles/185666/)
|
||||||
@ -457,5 +457,5 @@ Links
|
|||||||
* [Intel 8259](https://en.wikipedia.org/wiki/Intel_8259)
|
* [Intel 8259](https://en.wikipedia.org/wiki/Intel_8259)
|
||||||
* [PIC](https://en.wikipedia.org/wiki/Programmable_Interrupt_Controller)
|
* [PIC](https://en.wikipedia.org/wiki/Programmable_Interrupt_Controller)
|
||||||
* [MultiProcessor Configuration Table](https://en.wikipedia.org/wiki/MultiProcessor_Specification)
|
* [MultiProcessor Configuration Table](https://en.wikipedia.org/wiki/MultiProcessor_Specification)
|
||||||
* [radix tree](http://0xax.gitbooks.io/linux-insides/content/DataStructures/radix-tree.html)
|
* [radix tree](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-2.html)
|
||||||
* [dmesg](https://en.wikipedia.org/wiki/Dmesg)
|
* [dmesg](https://en.wikipedia.org/wiki/Dmesg)
|
||||||
|
@ -6,7 +6,7 @@ Non-early initialization of the IRQs
|
|||||||
|
|
||||||
This is the eighth part of the Interrupts and Interrupt Handling in the Linux kernel [chapter](http://0xax.gitbooks.io/linux-insides/content/Interrupts/index.html) and in the previous [part](https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-7.html) we started to dive into the external hardware [interrupts](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29). We looked on the implementation of the `early_irq_init` function from the [kernel/irq/irqdesc.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/irq/irqdesc.c) source code file and saw the initialization of the `irq_desc` structure in this function. Remind that `irq_desc` structure (defined in the [include/linux/irqdesc.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/irqdesc.h#L46) is the foundation of interrupt management code in the Linux kernel and represents an interrupt descriptor. In this part we will continue to dive into the initialization stuff which is related to the external hardware interrupts.
|
This is the eighth part of the Interrupts and Interrupt Handling in the Linux kernel [chapter](http://0xax.gitbooks.io/linux-insides/content/Interrupts/index.html) and in the previous [part](https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-7.html) we started to dive into the external hardware [interrupts](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29). We looked on the implementation of the `early_irq_init` function from the [kernel/irq/irqdesc.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/irq/irqdesc.c) source code file and saw the initialization of the `irq_desc` structure in this function. Remind that `irq_desc` structure (defined in the [include/linux/irqdesc.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/irqdesc.h#L46) is the foundation of interrupt management code in the Linux kernel and represents an interrupt descriptor. In this part we will continue to dive into the initialization stuff which is related to the external hardware interrupts.
|
||||||
|
|
||||||
Right after the call of the `early_irq_init` function in the [init/main.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/init/main.c) we can see the call of the `init_IRQ` function. This function is architecture-specific and defined in the [arch/x86/kernel/irqinit.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/irqinit.c). The `init_IRQ` function makes initialization of the `vector_irq` [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variable that defined in the same [arch/x86/kernel/irqinit.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/irqinit.c) source code file:
|
Right after the call of the `early_irq_init` function in the [init/main.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/init/main.c) we can see the call of the `init_IRQ` function. This function is architecture-specific and defined in the [arch/x86/kernel/irqinit.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/irqinit.c). The `init_IRQ` function makes initialization of the `vector_irq` [percpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variable that defined in the same [arch/x86/kernel/irqinit.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/irqinit.c) source code file:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
...
|
...
|
||||||
@ -28,7 +28,7 @@ where `NR_VECTORS` is count of the vector number and as you can remember from th
|
|||||||
#define NR_VECTORS 256
|
#define NR_VECTORS 256
|
||||||
```
|
```
|
||||||
|
|
||||||
So, in the start of the `init_IRQ` function we fill the `vector_irq` [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) array with the vector number of the `legacy` interrupts:
|
So, in the start of the `init_IRQ` function we fill the `vector_irq` [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) array with the vector number of the `legacy` interrupts:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
void __init init_IRQ(void)
|
void __init init_IRQ(void)
|
||||||
@ -521,7 +521,7 @@ Links
|
|||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
* [IRQ](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
* [IRQ](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
||||||
* [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [percpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [x86_64](https://en.wikipedia.org/wiki/X86-64)
|
* [x86_64](https://en.wikipedia.org/wiki/X86-64)
|
||||||
* [Intel 8259](https://en.wikipedia.org/wiki/Intel_8259)
|
* [Intel 8259](https://en.wikipedia.org/wiki/Intel_8259)
|
||||||
* [Programmable Interrupt Controller](https://en.wikipedia.org/wiki/Programmable_Interrupt_Controller)
|
* [Programmable Interrupt Controller](https://en.wikipedia.org/wiki/Programmable_Interrupt_Controller)
|
||||||
|
@ -227,7 +227,7 @@ void __init softirq_init(void)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We can see definition of the integer `cpu` variable at the beginning of the `softirq_init` function. Next we will use it as parameter for the `for_each_possible_cpu` macro that goes through the all possible processors in the system. If the `possible processor` is the new terminology for you, you can read more about it the [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) chapter. In short words, `possible cpus` is the set of processors that can be plugged in anytime during the life of that system boot. All `possible processors` stored in the `cpu_possible_bits` bitmap, you can find its definition in the [kernel/cpu.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/cpu.c):
|
We can see definition of the integer `cpu` variable at the beginning of the `softirq_init` function. Next we will use it as parameter for the `for_each_possible_cpu` macro that goes through the all possible processors in the system. If the `possible processor` is the new terminology for you, you can read more about it the [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) chapter. In short words, `possible cpus` is the set of processors that can be plugged in anytime during the life of that system boot. All `possible processors` stored in the `cpu_possible_bits` bitmap, you can find its definition in the [kernel/cpu.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/cpu.c):
|
||||||
|
|
||||||
```C
|
```C
|
||||||
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
|
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
|
||||||
@ -237,7 +237,7 @@ static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
|
|||||||
const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
|
const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
|
||||||
```
|
```
|
||||||
|
|
||||||
Ok, we defined the integer `cpu` variable and go through the all possible processors with the `for_each_possible_cpu` macro and makes initialization of the two following [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variables:
|
Ok, we defined the integer `cpu` variable and go through the all possible processors with the `for_each_possible_cpu` macro and makes initialization of the two following [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variables:
|
||||||
|
|
||||||
* `tasklet_vec`;
|
* `tasklet_vec`;
|
||||||
* `tasklet_hi_vec`;
|
* `tasklet_hi_vec`;
|
||||||
@ -520,7 +520,7 @@ Links
|
|||||||
* [initcall](http://www.compsoc.man.ac.uk/~moz/kernelnewbies/documents/initcall/index.html)
|
* [initcall](http://www.compsoc.man.ac.uk/~moz/kernelnewbies/documents/initcall/index.html)
|
||||||
* [IF](https://en.wikipedia.org/wiki/Interrupt_flag)
|
* [IF](https://en.wikipedia.org/wiki/Interrupt_flag)
|
||||||
* [eflags](https://en.wikipedia.org/wiki/FLAGS_register)
|
* [eflags](https://en.wikipedia.org/wiki/FLAGS_register)
|
||||||
* [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [CPU masks](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
* [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [Workqueue](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/Documentation/workqueue.txt)
|
* [Workqueue](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/Documentation/workqueue.txt)
|
||||||
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-8.html)
|
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-8.html)
|
||||||
|
@ -535,5 +535,5 @@ Links
|
|||||||
* [e820](http://en.wikipedia.org/wiki/E820)
|
* [e820](http://en.wikipedia.org/wiki/E820)
|
||||||
* [Memory management unit](http://en.wikipedia.org/wiki/Memory_management_unit)
|
* [Memory management unit](http://en.wikipedia.org/wiki/Memory_management_unit)
|
||||||
* [TLB](http://en.wikipedia.org/wiki/Translation_lookaside_buffer)
|
* [TLB](http://en.wikipedia.org/wiki/Translation_lookaside_buffer)
|
||||||
* [Paging](http://0xax.gitbooks.io/linux-insides/content/Theory/Paging.html)
|
* [Paging](https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-1.html)
|
||||||
* [Linux kernel memory management Part 1.](http://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-1.html)
|
* [Linux kernel memory management Part 1.](http://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-1.html)
|
||||||
|
@ -148,7 +148,7 @@ Ok, so we know that `kmemcheck` provides mechanism to check usage of `uninitiali
|
|||||||
struct my_struct *my_struct = kmalloc(sizeof(struct my_struct), GFP_KERNEL);
|
struct my_struct *my_struct = kmalloc(sizeof(struct my_struct), GFP_KERNEL);
|
||||||
```
|
```
|
||||||
|
|
||||||
or in other words somebody wants to access a [page](https://en.wikipedia.org/wiki/Page_%28computer_memory%29), a [page fault](https://en.wikipedia.org/wiki/Page_fault) exception is generated. This is achieved by the fact that the `kmemcheck` marks memory pages as `non-present` (more about this you can read in the special part which is devoted to [paging](https://0xax.gitbooks.io/linux-insides/content/Theory/Paging.html)). If a `page fault` exception is occurred, the exception handler knows about it and in a case when the `kmemcheck` is enabled it transfers control to it. After the `kmemcheck` will finish its checks, the page will be marked as `present` and the interrupted code will be able to continue execution. There is little subtlety in this chain. When the first instruction of interrupted code will be executed, the `kmemcheck` will mark the page as `non-present` again. In this way next access to memory will be caught again.
|
or in other words somebody wants to access a [page](https://en.wikipedia.org/wiki/Page_%28computer_memory%29), a [page fault](https://en.wikipedia.org/wiki/Page_fault) exception is generated. This is achieved by the fact that the `kmemcheck` marks memory pages as `non-present` (more about this you can read in the special part which is devoted to [Paging](https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-1.html)). If a `page fault` exception is occurred, the exception handler knows about it and in a case when the `kmemcheck` is enabled it transfers control to it. After the `kmemcheck` will finish its checks, the page will be marked as `present` and the interrupted code will be able to continue execution. There is little subtlety in this chain. When the first instruction of interrupted code will be executed, the `kmemcheck` will mark the page as `non-present` again. In this way next access to memory will be caught again.
|
||||||
|
|
||||||
We just considered the `kmemcheck` mechanism from theoretical side. Now let's consider how it is implemented in the Linux kernel.
|
We just considered the `kmemcheck` mechanism from theoretical side. Now let's consider how it is implemented in the Linux kernel.
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ early_param("kmemcheck", param_kmemcheck);
|
|||||||
|
|
||||||
As we already saw, the `param_kmemcheck` may have one of the following values: `0` (enabled), `1` (disabled) or `2` (one-shot). The implementation of the `param_kmemcheck` is pretty simple. We just convert string value of the `kmemcheck` command line option to integer representation and set it to the `kmemcheck_enabled` variable.
|
As we already saw, the `param_kmemcheck` may have one of the following values: `0` (enabled), `1` (disabled) or `2` (one-shot). The implementation of the `param_kmemcheck` is pretty simple. We just convert string value of the `kmemcheck` command line option to integer representation and set it to the `kmemcheck_enabled` variable.
|
||||||
|
|
||||||
The second stage will be executed during initialization of the Linux kernel, rather during initialization of early [initcalls](https://0xax.gitbooks.io/linux-insides/content/Concepts/initcall.html). The second stage is represented by the `kmemcheck_init`:
|
The second stage will be executed during initialization of the Linux kernel, rather during initialization of early [initcalls](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-3.html). The second stage is represented by the `kmemcheck_init`:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
int __init kmemcheck_init(void)
|
int __init kmemcheck_init(void)
|
||||||
@ -296,7 +296,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `kmemcheck_active` gets `kmemcheck_context` [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) structure and return the result of comparison of the `balance` field of this structure with zero:
|
The `kmemcheck_active` gets `kmemcheck_context` [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) structure and return the result of comparison of the `balance` field of this structure with zero:
|
||||||
|
|
||||||
```
|
```
|
||||||
bool kmemcheck_active(struct pt_regs *regs)
|
bool kmemcheck_active(struct pt_regs *regs)
|
||||||
@ -422,13 +422,12 @@ Links
|
|||||||
* [memory leaks](https://en.wikipedia.org/wiki/Memory_leak)
|
* [memory leaks](https://en.wikipedia.org/wiki/Memory_leak)
|
||||||
* [kmemcheck documentation](https://www.kernel.org/doc/Documentation/kmemcheck.txt)
|
* [kmemcheck documentation](https://www.kernel.org/doc/Documentation/kmemcheck.txt)
|
||||||
* [valgrind](https://en.wikipedia.org/wiki/Valgrind)
|
* [valgrind](https://en.wikipedia.org/wiki/Valgrind)
|
||||||
* [paging](https://0xax.gitbooks.io/linux-insides/content/Theory/Paging.html)
|
* [Paging](https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-1.html)
|
||||||
* [page fault](https://en.wikipedia.org/wiki/Page_fault)
|
* [page fault](https://en.wikipedia.org/wiki/Page_fault)
|
||||||
* [initcalls](https://0xax.gitbooks.io/linux-insides/content/Concepts/initcall.html)
|
* [initcalls](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-3.html)
|
||||||
* [opcode](https://en.wikipedia.org/wiki/Opcode)
|
* [opcode](https://en.wikipedia.org/wiki/Opcode)
|
||||||
* [translation lookaside buffer](https://en.wikipedia.org/wiki/Translation_lookaside_buffer)
|
* [translation lookaside buffer](https://en.wikipedia.org/wiki/Translation_lookaside_buffer)
|
||||||
* [per-cpu variables](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [per-cpu variables](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [flags register](https://en.wikipedia.org/wiki/FLAGS_register)
|
* [flags register](https://en.wikipedia.org/wiki/FLAGS_register)
|
||||||
* [tasklet](https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-9.html)
|
* [tasklet](https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-9.html)
|
||||||
* [Paging](http://0xax.gitbooks.io/linux-insides/content/Theory/Paging.html)
|
|
||||||
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-2.html)
|
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-2.html)
|
||||||
|
@ -101,7 +101,7 @@ In the previous [part](https://0xax.gitbooks.io/linux-insides/content/SyncPrim/l
|
|||||||
|
|
||||||
The topic of this part is `queued spinlocks`. This approach may help to solve both of these problems. The `queued spinlocks` allows to each processor to use its own memory location to spin. The basic principle of a queue-based spinlock can best be understood by studying a classic queue-based spinlock implementation called the [MCS](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf) lock. Before we will look at implementation of the `queued spinlocks` in the Linux kernel, we will try to understand what is it `MCS` lock.
|
The topic of this part is `queued spinlocks`. This approach may help to solve both of these problems. The `queued spinlocks` allows to each processor to use its own memory location to spin. The basic principle of a queue-based spinlock can best be understood by studying a classic queue-based spinlock implementation called the [MCS](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf) lock. Before we will look at implementation of the `queued spinlocks` in the Linux kernel, we will try to understand what is it `MCS` lock.
|
||||||
|
|
||||||
The basic idea of the `MCS` lock is in that as I already wrote in the previous paragraph, a thread spins on a local variable and each processor in the system has its own copy of these variable. In other words this concept is built on top of the [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variables concept in the Linux kernel.
|
The basic idea of the `MCS` lock is in that as I already wrote in the previous paragraph, a thread spins on a local variable and each processor in the system has its own copy of these variable. In other words this concept is built on top of the [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variables concept in the Linux kernel.
|
||||||
|
|
||||||
When the first thread wants to acquire a lock, it registers itself in the `queue` or in other words it will be added to the special `queue` and will acquire lock, because it is free for now. When the second thread will want to acquire the same lock before the first thread will release it, this thread adds its own copy of the lock variable into this `queue`. In this case the first thread will contain a `next` field which will point to the second thread. From this moment, the second thread will wait until the first thread will release its lock and notify `next` thread about this event. The first thread will be deleted from the `queue` and the second thread will be owner of a lock.
|
When the first thread wants to acquire a lock, it registers itself in the `queue` or in other words it will be added to the special `queue` and will acquire lock, because it is free for now. When the second thread will want to acquire the same lock before the first thread will release it, this thread adds its own copy of the lock variable into this `queue`. In this case the first thread will contain a `next` field which will point to the second thread. From this moment, the second thread will wait until the first thread will release its lock and notify `next` thread about this event. The first thread will be deleted from the `queue` and the second thread will be owner of a lock.
|
||||||
|
|
||||||
@ -477,7 +477,7 @@ Links
|
|||||||
* [API](https://en.wikipedia.org/wiki/Application_programming_interface)
|
* [API](https://en.wikipedia.org/wiki/Application_programming_interface)
|
||||||
* [Test and Set](https://en.wikipedia.org/wiki/Test-and-set)
|
* [Test and Set](https://en.wikipedia.org/wiki/Test-and-set)
|
||||||
* [MCS](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf)
|
* [MCS](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf)
|
||||||
* [per-cpu variables](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [per-cpu variables](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [atomic instruction](https://en.wikipedia.org/wiki/Linearizability)
|
* [atomic instruction](https://en.wikipedia.org/wiki/Linearizability)
|
||||||
* [CMPXCHG instruction](http://x86.renejeschke.de/html/file_module_x86_id_41.html)
|
* [CMPXCHG instruction](http://x86.renejeschke.de/html/file_module_x86_id_41.html)
|
||||||
* [LOCK instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html)
|
* [LOCK instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html)
|
||||||
|
@ -76,7 +76,7 @@ The `__SEMAPHORE_INITIALIZER` macro takes the name of the future `semaphore` str
|
|||||||
#define __ARCH_SPIN_LOCK_UNLOCKED { { 0 } }
|
#define __ARCH_SPIN_LOCK_UNLOCKED { { 0 } }
|
||||||
```
|
```
|
||||||
|
|
||||||
The last two fields of the `semaphore` structure `count` and `wait_list` are initialized with the given value which represents count of available resources and empty [list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/dlist.html).
|
The last two fields of the `semaphore` structure `count` and `wait_list` are initialized with the given value which represents count of available resources and empty [list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html).
|
||||||
|
|
||||||
The second way to initialize a `semaphore` structure is to pass the `semaphore` and number of available resources to the `sema_init` function which is defined in the [include/linux/semaphore.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/semaphore.h) header file:
|
The second way to initialize a `semaphore` structure is to pass the `semaphore` and number of available resources to the `sema_init` function which is defined in the [include/linux/semaphore.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/semaphore.h) header file:
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ The first represents current task for the local processor which wants to acquire
|
|||||||
#define current get_current()
|
#define current get_current()
|
||||||
```
|
```
|
||||||
|
|
||||||
Where the `get_current` function returns value of the `current_task` [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variable:
|
Where the `get_current` function returns value of the `current_task` [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variable:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
DECLARE_PER_CPU(struct task_struct *, current_task);
|
DECLARE_PER_CPU(struct task_struct *, current_task);
|
||||||
@ -342,10 +342,10 @@ Links
|
|||||||
* [preemption](https://en.wikipedia.org/wiki/Preemption_%28computing%29)
|
* [preemption](https://en.wikipedia.org/wiki/Preemption_%28computing%29)
|
||||||
* [deadlocks](https://en.wikipedia.org/wiki/Deadlock)
|
* [deadlocks](https://en.wikipedia.org/wiki/Deadlock)
|
||||||
* [scheduler](https://en.wikipedia.org/wiki/Scheduling_%28computing%29)
|
* [scheduler](https://en.wikipedia.org/wiki/Scheduling_%28computing%29)
|
||||||
* [Doubly linked list in the Linux kernel](https://0xax.gitbooks.io/linux-insides/content/DataStructures/dlist.html)
|
* [Doubly linked list in the Linux kernel](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html)
|
||||||
* [jiffies](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-1.html)
|
* [jiffies](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-1.html)
|
||||||
* [interrupts](https://en.wikipedia.org/wiki/Interrupt)
|
* [interrupts](https://en.wikipedia.org/wiki/Interrupt)
|
||||||
* [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [bitmask](https://en.wikipedia.org/wiki/Mask_%28computing%29)
|
* [bitmask](https://en.wikipedia.org/wiki/Mask_%28computing%29)
|
||||||
* [SIGKILL](https://en.wikipedia.org/wiki/Unix_signal#SIGKILL)
|
* [SIGKILL](https://en.wikipedia.org/wiki/Unix_signal#SIGKILL)
|
||||||
* [errno](https://en.wikipedia.org/wiki/Errno.h)
|
* [errno](https://en.wikipedia.org/wiki/Errno.h)
|
||||||
|
@ -114,7 +114,7 @@ macro. Let's consider implementation of this macro. As we may see, the `DEFINE_M
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This macro is defined in the [same](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/mutex.h) header file and as we may understand it initializes fields of the `mutex` structure the initial values. The `count` field get initialized with the `1` which represents `unlocked` state of a mutex. The `wait_lock` [spinlock](https://en.wikipedia.org/wiki/Spinlock) get initialized to the unlocked state and the last field `wait_list` to empty [doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/dlist.html).
|
This macro is defined in the [same](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/mutex.h) header file and as we may understand it initializes fields of the `mutex` structure the initial values. The `count` field get initialized with the `1` which represents `unlocked` state of a mutex. The `wait_lock` [spinlock](https://en.wikipedia.org/wiki/Spinlock) get initialized to the unlocked state and the last field `wait_list` to empty [doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html).
|
||||||
|
|
||||||
The second approach allows us to initialize a `mutex` dynamically. To do this we need to call the `__mutex_init` function from the [kernel/locking/mutex.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/locking/mutex.c) source code file. Actually, the `__mutex_init` function rarely called directly. Instead of the `__mutex_init`, the:
|
The second approach allows us to initialize a `mutex` dynamically. To do this we need to call the `__mutex_init` function from the [kernel/locking/mutex.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/locking/mutex.c) source code file. Actually, the `__mutex_init` function rarely called directly. Instead of the `__mutex_init`, the:
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ We may see the call of the `might_sleep` macro from the [include/linux/kernel.h]
|
|||||||
|
|
||||||
After the `might_sleep` macro, we may see the call of the `__mutex_fastpath_lock` function. This function is architecture-specific and as we consider [x86_64](https://en.wikipedia.org/wiki/X86-64) architecture in this book, the implementation of the `__mutex_fastpath_lock` is located in the [arch/x86/include/asm/mutex_64.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/include/asm/mutex_64.h) header file. As we may understand from the name of the `__mutex_fastpath_lock` function, this function will try to acquire lock in a fast path or in other words this function will try to decrement the value of the `count` of the given mutex.
|
After the `might_sleep` macro, we may see the call of the `__mutex_fastpath_lock` function. This function is architecture-specific and as we consider [x86_64](https://en.wikipedia.org/wiki/X86-64) architecture in this book, the implementation of the `__mutex_fastpath_lock` is located in the [arch/x86/include/asm/mutex_64.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/include/asm/mutex_64.h) header file. As we may understand from the name of the `__mutex_fastpath_lock` function, this function will try to acquire lock in a fast path or in other words this function will try to decrement the value of the `count` of the given mutex.
|
||||||
|
|
||||||
Implementation of the `__mutex_fastpath_lock` function consists from two parts. The first part is [inline assembly](https://0xax.gitbooks.io/linux-insides/content/Theory/asm.html) statement. Let's look at it:
|
Implementation of the `__mutex_fastpath_lock` function consists from two parts. The first part is [inline assembly](https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-3.html) statement. Let's look at it:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
asm_volatile_goto(LOCK_PREFIX " decl %0\n"
|
asm_volatile_goto(LOCK_PREFIX " decl %0\n"
|
||||||
@ -429,9 +429,9 @@ Links
|
|||||||
* [lock validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
|
* [lock validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
|
||||||
* [Atomic](https://en.wikipedia.org/wiki/Linearizability)
|
* [Atomic](https://en.wikipedia.org/wiki/Linearizability)
|
||||||
* [MCS lock](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf)
|
* [MCS lock](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf)
|
||||||
* [Doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/dlist.html)
|
* [Doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html)
|
||||||
* [x86_64](https://en.wikipedia.org/wiki/X86-64)
|
* [x86_64](https://en.wikipedia.org/wiki/X86-64)
|
||||||
* [Inline assembly](https://0xax.gitbooks.io/linux-insides/content/Theory/asm.html)
|
* [Inline assembly](https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-3.html)
|
||||||
* [Memory barrier](https://en.wikipedia.org/wiki/Memory_barrier)
|
* [Memory barrier](https://en.wikipedia.org/wiki/Memory_barrier)
|
||||||
* [Lock instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html)
|
* [Lock instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html)
|
||||||
* [JNS instruction](http://unixwiz.net/techtips/x86-jumps.html)
|
* [JNS instruction](http://unixwiz.net/techtips/x86-jumps.html)
|
||||||
|
@ -59,7 +59,7 @@ config RWSEM_GENERIC_SPINLOCK
|
|||||||
|
|
||||||
So, as this [book](https://0xax.gitbooks.io/linux-insides/content) describes only [x86_64](https://en.wikipedia.org/wiki/X86-64) architecture related stuff, we will skip the case when the `CONFIG_RWSEM_GENERIC_SPINLOCK` kernel configuration is enabled and consider definition of the `rw_semaphore` structure only from the [include/linux/rwsem.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/rwsem.h) header file.
|
So, as this [book](https://0xax.gitbooks.io/linux-insides/content) describes only [x86_64](https://en.wikipedia.org/wiki/X86-64) architecture related stuff, we will skip the case when the `CONFIG_RWSEM_GENERIC_SPINLOCK` kernel configuration is enabled and consider definition of the `rw_semaphore` structure only from the [include/linux/rwsem.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/linux/rwsem.h) header file.
|
||||||
|
|
||||||
If we will take a look at the definition of the `rw_semaphore` structure, we will notice that first three fields are the same that in the `semaphore` structure. It contains `count` field which represents amount of available resources, the `wait_list` field which represents [doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/dlist.html) of processes which are waiting to acquire a lock and `wait_lock` [spinlock](https://en.wikipedia.org/wiki/Spinlock) for protection of this list. Notice that `rw_semaphore.count` field is `long` type unlike the same field in the `semaphore` structure.
|
If we will take a look at the definition of the `rw_semaphore` structure, we will notice that first three fields are the same that in the `semaphore` structure. It contains `count` field which represents amount of available resources, the `wait_list` field which represents [doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html) of processes which are waiting to acquire a lock and `wait_lock` [spinlock](https://en.wikipedia.org/wiki/Spinlock) for protection of this list. Notice that `rw_semaphore.count` field is `long` type unlike the same field in the `semaphore` structure.
|
||||||
|
|
||||||
The `count` field of a `rw_semaphore` structure may have following values:
|
The `count` field of a `rw_semaphore` structure may have following values:
|
||||||
|
|
||||||
@ -240,7 +240,7 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
As for other synchronization primitives which we saw in this chapter, usually `lock/unlock` functions consists only from an [inline assembly](https://0xax.gitbooks.io/linux-insides/content/Theory/asm.html) statement. As we may see, in our case the same for `__down_write_nested` function. Let's try to understand what does this function do. The first line of our assembly statement is just a comment, let's skip it. The second like contains `LOCK_PREFIX` which will be expanded to the [LOCK](http://x86.renejeschke.de/html/file_module_x86_id_159.html) instruction as we already know. The next [xadd](http://x86.renejeschke.de/html/file_module_x86_id_327.html) instruction executes `add` and `exchange` operations. In other words, `xadd` instruction adds value of the `RWSEM_ACTIVE_WRITE_BIAS`:
|
As for other synchronization primitives which we saw in this chapter, usually `lock/unlock` functions consists only from an [inline assembly](https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-3.html) statement. As we may see, in our case the same for `__down_write_nested` function. Let's try to understand what does this function do. The first line of our assembly statement is just a comment, let's skip it. The second like contains `LOCK_PREFIX` which will be expanded to the [LOCK](http://x86.renejeschke.de/html/file_module_x86_id_159.html) instruction as we already know. The next [xadd](http://x86.renejeschke.de/html/file_module_x86_id_327.html) instruction executes `add` and `exchange` operations. In other words, `xadd` instruction adds value of the `RWSEM_ACTIVE_WRITE_BIAS`:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
|
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
|
||||||
@ -422,12 +422,12 @@ Links
|
|||||||
* [Semaphore](https://en.wikipedia.org/wiki/Semaphore_%28programming%29)
|
* [Semaphore](https://en.wikipedia.org/wiki/Semaphore_%28programming%29)
|
||||||
* [Mutex](https://en.wikipedia.org/wiki/Mutual_exclusion)
|
* [Mutex](https://en.wikipedia.org/wiki/Mutual_exclusion)
|
||||||
* [x86_64 architecture](https://en.wikipedia.org/wiki/X86-64)
|
* [x86_64 architecture](https://en.wikipedia.org/wiki/X86-64)
|
||||||
* [Doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/dlist.html)
|
* [Doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html)
|
||||||
* [MCS lock](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf)
|
* [MCS lock](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf)
|
||||||
* [API](https://en.wikipedia.org/wiki/Application_programming_interface)
|
* [API](https://en.wikipedia.org/wiki/Application_programming_interface)
|
||||||
* [Linux kernel lock validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
|
* [Linux kernel lock validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
|
||||||
* [Atomic operations](https://en.wikipedia.org/wiki/Linearizability)
|
* [Atomic operations](https://en.wikipedia.org/wiki/Linearizability)
|
||||||
* [Inline assembly](https://0xax.gitbooks.io/linux-insides/content/Theory/asm.html)
|
* [Inline assembly](https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-3.html)
|
||||||
* [XADD instruction](http://x86.renejeschke.de/html/file_module_x86_id_327.html)
|
* [XADD instruction](http://x86.renejeschke.de/html/file_module_x86_id_327.html)
|
||||||
* [LOCK instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html)
|
* [LOCK instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html)
|
||||||
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-4.html)
|
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-4.html)
|
||||||
|
@ -210,7 +210,7 @@ This macro is defined in the [arch/x86/include/asm/irqflags.h](https://github.co
|
|||||||
#define SWAPGS_UNSAFE_STACK swapgs
|
#define SWAPGS_UNSAFE_STACK swapgs
|
||||||
```
|
```
|
||||||
|
|
||||||
which exchanges the current GS base register value with the value contained in the `MSR_KERNEL_GS_BASE ` model specific register. In other words we moved it on to the kernel stack. After this we point the old stack pointer to the `rsp_scratch` [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variable and setup the stack pointer to point to the top of stack for the current processor:
|
which exchanges the current GS base register value with the value contained in the `MSR_KERNEL_GS_BASE ` model specific register. In other words we moved it on to the kernel stack. After this we point the old stack pointer to the `rsp_scratch` [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variable and setup the stack pointer to point to the top of stack for the current processor:
|
||||||
|
|
||||||
```assembly
|
```assembly
|
||||||
movq %rsp, PER_CPU_VAR(rsp_scratch)
|
movq %rsp, PER_CPU_VAR(rsp_scratch)
|
||||||
@ -402,7 +402,7 @@ Links
|
|||||||
* [instruction pointer](https://en.wikipedia.org/wiki/Program_counter)
|
* [instruction pointer](https://en.wikipedia.org/wiki/Program_counter)
|
||||||
* [flags register](https://en.wikipedia.org/wiki/FLAGS_register)
|
* [flags register](https://en.wikipedia.org/wiki/FLAGS_register)
|
||||||
* [Global Descriptor Table](https://en.wikipedia.org/wiki/Global_Descriptor_Table)
|
* [Global Descriptor Table](https://en.wikipedia.org/wiki/Global_Descriptor_Table)
|
||||||
* [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [per-cpu](http://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [general purpose registers](https://en.wikipedia.org/wiki/Processor_register)
|
* [general purpose registers](https://en.wikipedia.org/wiki/Processor_register)
|
||||||
* [ABI](https://en.wikipedia.org/wiki/Application_binary_interface)
|
* [ABI](https://en.wikipedia.org/wiki/Application_binary_interface)
|
||||||
* [x86_64 C ABI](http://www.x86-64.org/documentation/abi.pdf)
|
* [x86_64 C ABI](http://www.x86-64.org/documentation/abi.pdf)
|
||||||
|
@ -252,7 +252,7 @@ Here we can see that [uname](https://en.wikipedia.org/wiki/Uname) util was linke
|
|||||||
* `libc.so.6`;
|
* `libc.so.6`;
|
||||||
* `ld-linux-x86-64.so.2`.
|
* `ld-linux-x86-64.so.2`.
|
||||||
|
|
||||||
The first provides `vDSO` functionality, the second is `C` [standard library](https://en.wikipedia.org/wiki/C_standard_library) and the third is the program interpreter (more about this you can read in the part that describes [linkers](http://0xax.gitbooks.io/linux-insides/content/Misc/linkers.html)). So, the `vDSO` solves limitations of the `vsyscall`. Implementation of the `vDSO` is similar to `vsyscall`.
|
The first provides `vDSO` functionality, the second is `C` [standard library](https://en.wikipedia.org/wiki/C_standard_library) and the third is the program interpreter (more about this you can read in the part that describes [linkers](https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-3.html)). So, the `vDSO` solves limitations of the `vsyscall`. Implementation of the `vDSO` is similar to `vsyscall`.
|
||||||
|
|
||||||
Initialization of the `vDSO` occurs in the `init_vdso` function that defined in the [arch/x86/entry/vdso/vma.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/entry/vdso/vma.c) source code file. This function starts from the initialization of the `vDSO` images for 32-bits and 64-bits depends on the `CONFIG_X86_X32_ABI` kernel configuration option:
|
Initialization of the `vDSO` occurs in the `init_vdso` function that defined in the [arch/x86/entry/vdso/vma.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/entry/vdso/vma.c) source code file. This function starts from the initialization of the `vDSO` images for 32-bits and 64-bits depends on the `CONFIG_X86_X32_ABI` kernel configuration option:
|
||||||
|
|
||||||
@ -399,5 +399,5 @@ Links
|
|||||||
* [instruction pointer](https://en.wikipedia.org/wiki/Program_counter)
|
* [instruction pointer](https://en.wikipedia.org/wiki/Program_counter)
|
||||||
* [stack pointer](https://en.wikipedia.org/wiki/Stack_register)
|
* [stack pointer](https://en.wikipedia.org/wiki/Stack_register)
|
||||||
* [uname](https://en.wikipedia.org/wiki/Uname)
|
* [uname](https://en.wikipedia.org/wiki/Uname)
|
||||||
* [Linkers](http://0xax.gitbooks.io/linux-insides/content/Misc/linkers.html)
|
* [Linkers](https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-3.html)
|
||||||
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-2.html)
|
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-2.html)
|
||||||
|
@ -334,7 +334,7 @@ if (!elf_phdata)
|
|||||||
goto out;
|
goto out;
|
||||||
```
|
```
|
||||||
|
|
||||||
that describes [segments](https://en.wikipedia.org/wiki/Memory_segmentation). Read the `program interpreter` and libraries that linked with the our executable binary file from disk and load it to memory. The `program interpreter` specified in the `.interp` section of the executable file and as you can read in the part that describes [Linkers](http://0xax.gitbooks.io/linux-insides/content/Misc/linkers.html) it is - `/lib64/ld-linux-x86-64.so.2` for the `x86_64`. It setups the stack and map `elf` binary into the correct location in memory. It maps the [bss](https://en.wikipedia.org/wiki/.bss) and the [brk](http://man7.org/linux/man-pages/man2/sbrk.2.html) sections and does many many other different things to prepare executable file to execute.
|
that describes [segments](https://en.wikipedia.org/wiki/Memory_segmentation). Read the `program interpreter` and libraries that linked with the our executable binary file from disk and load it to memory. The `program interpreter` specified in the `.interp` section of the executable file and as you can read in the part that describes [Linkers](https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-3.html) it is - `/lib64/ld-linux-x86-64.so.2` for the `x86_64`. It setups the stack and map `elf` binary into the correct location in memory. It maps the [bss](https://en.wikipedia.org/wiki/.bss) and the [brk](http://man7.org/linux/man-pages/man2/sbrk.2.html) sections and does many many other different things to prepare executable file to execute.
|
||||||
|
|
||||||
In the end of the execution of the `load_elf_binary` we call the `start_thread` function and pass three arguments to it:
|
In the end of the execution of the `load_elf_binary` we call the `start_thread` function and pass three arguments to it:
|
||||||
|
|
||||||
@ -424,7 +424,7 @@ Links
|
|||||||
* [Alpha](https://en.wikipedia.org/wiki/DEC_Alpha)
|
* [Alpha](https://en.wikipedia.org/wiki/DEC_Alpha)
|
||||||
* [FDPIC](http://elinux.org/UClinux_Shared_Library#FDPIC_ELF)
|
* [FDPIC](http://elinux.org/UClinux_Shared_Library#FDPIC_ELF)
|
||||||
* [segments](https://en.wikipedia.org/wiki/Memory_segmentation)
|
* [segments](https://en.wikipedia.org/wiki/Memory_segmentation)
|
||||||
* [Linkers](http://0xax.gitbooks.io/linux-insides/content/Misc/linkers.html)
|
* [Linkers](https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-3.html)
|
||||||
* [Processor register](https://en.wikipedia.org/wiki/Processor_register)
|
* [Processor register](https://en.wikipedia.org/wiki/Processor_register)
|
||||||
* [instruction pointer](https://en.wikipedia.org/wiki/Program_counter)
|
* [instruction pointer](https://en.wikipedia.org/wiki/Program_counter)
|
||||||
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-3.html)
|
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-3.html)
|
||||||
|
@ -102,7 +102,7 @@ void __init tick_broadcast_init(void)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
As we can see, the `tick_broadcast_init` function allocates different [cpumasks](https://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) with the help of the `zalloc_cpumask_var` function. The `zalloc_cpumask_var` function defined in the [lib/cpumask.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/lib/cpumask.c) source code file and expands to the call of the following function:
|
As we can see, the `tick_broadcast_init` function allocates different [cpumasks](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) with the help of the `zalloc_cpumask_var` function. The `zalloc_cpumask_var` function defined in the [lib/cpumask.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/lib/cpumask.c) source code file and expands to the call of the following function:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
bool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
|
bool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
|
||||||
@ -407,7 +407,7 @@ for_each_cpu(cpu, tick_nohz_full_mask)
|
|||||||
context_tracking_cpu_set(cpu);
|
context_tracking_cpu_set(cpu);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `context_tracking_cpu_set` function defined in the [kernel/context_tracking.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/context_tracking.c) source code file and main point of this function is to set the `context_tracking.active` [percpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variable to `true`. When the `active` field will be set to `true` for the certain processor, all [context switches](https://en.wikipedia.org/wiki/Context_switch) will be ignored by the Linux kernel context tracking subsystem for this processor.
|
The `context_tracking_cpu_set` function defined in the [kernel/context_tracking.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/context_tracking.c) source code file and main point of this function is to set the `context_tracking.active` [percpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variable to `true`. When the `active` field will be set to `true` for the certain processor, all [context switches](https://en.wikipedia.org/wiki/Context_switch) will be ignored by the Linux kernel context tracking subsystem for this processor.
|
||||||
|
|
||||||
That's all. This is the end of the `tick_nohz_init` function. After this `NO_HZ` related data structures will be initialized. We didn't see API of the `NO_HZ` mode, but will see it soon.
|
That's all. This is the end of the `tick_nohz_init` function. After this `NO_HZ` related data structures will be initialized. We didn't see API of the `NO_HZ` mode, but will see it soon.
|
||||||
|
|
||||||
@ -433,12 +433,12 @@ Links
|
|||||||
* [CPU idle](https://en.wikipedia.org/wiki/Idle_%28CPU%29)
|
* [CPU idle](https://en.wikipedia.org/wiki/Idle_%28CPU%29)
|
||||||
* [power management](https://en.wikipedia.org/wiki/Power_management)
|
* [power management](https://en.wikipedia.org/wiki/Power_management)
|
||||||
* [NO_HZ documentation](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/Documentation/timers/NO_HZ.txt)
|
* [NO_HZ documentation](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/Documentation/timers/NO_HZ.txt)
|
||||||
* [cpumasks](https://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [cpumasks](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
* [high precision event timer](https://en.wikipedia.org/wiki/High_Precision_Event_Timer)
|
* [high precision event timer](https://en.wikipedia.org/wiki/High_Precision_Event_Timer)
|
||||||
* [irq](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
* [irq](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
|
||||||
* [IPI](https://en.wikipedia.org/wiki/Inter-processor_interrupt)
|
* [IPI](https://en.wikipedia.org/wiki/Inter-processor_interrupt)
|
||||||
* [CPUID](https://en.wikipedia.org/wiki/CPUID)
|
* [CPUID](https://en.wikipedia.org/wiki/CPUID)
|
||||||
* [APIC](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller)
|
* [APIC](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller)
|
||||||
* [percpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [percpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [context switches](https://en.wikipedia.org/wiki/Context_switch)
|
* [context switches](https://en.wikipedia.org/wiki/Context_switch)
|
||||||
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-2.html)
|
* [Previous part](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-2.html)
|
||||||
|
@ -75,7 +75,7 @@ static void __init init_timer_cpus(void)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If you do not know or do not remember what is it a `possible` cpu, you can read the special [part](https://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) of this book which describes `cpumask` concept in the Linux kernel. In short words, a `possible` processor is a processor which can be plugged in anytime during the life of the system.
|
If you do not know or do not remember what is it a `possible` cpu, you can read the special [part](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) of this book which describes `cpumask` concept in the Linux kernel. In short words, a `possible` processor is a processor which can be plugged in anytime during the life of the system.
|
||||||
|
|
||||||
The `init_timer_cpu` function does main work for us, namely it executes initialization of the `tvec_base` structure for each processor. This structure defined in the [kernel/time/timer.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/time/timer.c) source code file and stores data related to a `dynamic` timer for a certain processor. Let's look on the definition of this structure:
|
The `init_timer_cpu` function does main work for us, namely it executes initialization of the `tvec_base` structure for each processor. This structure defined in the [kernel/time/timer.c](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/kernel/time/timer.c) source code file and stores data related to a `dynamic` timer for a certain processor. Let's look on the definition of this structure:
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ static void __init init_timer_cpu(int cpu)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `tvec_bases` represents [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html) variable which represents main data structure for a dynamic timer for a given processor. This `per-cpu` variable defined in the same source code file:
|
The `tvec_bases` represents [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html) variable which represents main data structure for a dynamic timer for a given processor. This `per-cpu` variable defined in the same source code file:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
static DEFINE_PER_CPU(struct tvec_base, tvec_bases);
|
static DEFINE_PER_CPU(struct tvec_base, tvec_bases);
|
||||||
@ -418,10 +418,10 @@ Links
|
|||||||
* [IP](https://en.wikipedia.org/wiki/Internet_Protocol)
|
* [IP](https://en.wikipedia.org/wiki/Internet_Protocol)
|
||||||
* [netfilter](https://en.wikipedia.org/wiki/Netfilter)
|
* [netfilter](https://en.wikipedia.org/wiki/Netfilter)
|
||||||
* [network](https://en.wikipedia.org/wiki/Computer_network)
|
* [network](https://en.wikipedia.org/wiki/Computer_network)
|
||||||
* [cpumask](https://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [cpumask](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
* [interrupt](https://en.wikipedia.org/wiki/Interrupt)
|
* [interrupt](https://en.wikipedia.org/wiki/Interrupt)
|
||||||
* [jiffies](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-1.html)
|
* [jiffies](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-1.html)
|
||||||
* [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/per-cpu.html)
|
* [per-cpu](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html)
|
||||||
* [spinlock](https://en.wikipedia.org/wiki/Spinlock)
|
* [spinlock](https://en.wikipedia.org/wiki/Spinlock)
|
||||||
* [procfs](https://en.wikipedia.org/wiki/Procfs)
|
* [procfs](https://en.wikipedia.org/wiki/Procfs)
|
||||||
* [previous part](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-3.html)
|
* [previous part](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-3.html)
|
||||||
|
@ -130,7 +130,7 @@ The next two fields `shift` and `mult` are familiar to us. They will be used to
|
|||||||
#define cpumask_of(cpu) (get_cpu_mask(cpu))
|
#define cpumask_of(cpu) (get_cpu_mask(cpu))
|
||||||
```
|
```
|
||||||
|
|
||||||
Where the `get_cpu_mask` returns the cpumask containing just a given `cpu` number. More about `cpumasks` concept you may read in the [CPU masks in the Linux kernel](https://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html) part. In the last four lines of code we set callbacks for the clock event device suspend/resume, device shutdown and update of the clock event device state.
|
Where the `get_cpu_mask` returns the cpumask containing just a given `cpu` number. More about `cpumasks` concept you may read in the [CPU masks in the Linux kernel](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html) part. In the last four lines of code we set callbacks for the clock event device suspend/resume, device shutdown and update of the clock event device state.
|
||||||
|
|
||||||
After we finished with the initialization of the `at91sam926x` periodic timer, we can register it by the call of the following functions:
|
After we finished with the initialization of the `at91sam926x` periodic timer, we can register it by the call of the following functions:
|
||||||
|
|
||||||
@ -409,7 +409,7 @@ Links
|
|||||||
* [local APIC](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller)
|
* [local APIC](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller)
|
||||||
* [C3 state](https://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface#Device_states)
|
* [C3 state](https://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface#Device_states)
|
||||||
* [Periodic Interval Timer (PIT) for at91sam926x](http://www.atmel.com/Images/doc6062.pdf)
|
* [Periodic Interval Timer (PIT) for at91sam926x](http://www.atmel.com/Images/doc6062.pdf)
|
||||||
* [CPU masks in the Linux kernel](https://0xax.gitbooks.io/linux-insides/content/Concepts/cpumask.html)
|
* [CPU masks in the Linux kernel](https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html)
|
||||||
* [deadlock](https://en.wikipedia.org/wiki/Deadlock)
|
* [deadlock](https://en.wikipedia.org/wiki/Deadlock)
|
||||||
* [CPU hotplug](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt)
|
* [CPU hotplug](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt)
|
||||||
* [previous part](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-3.html)
|
* [previous part](https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-3.html)
|
||||||
|
Loading…
Reference in New Issue
Block a user