fix: update dead link x86.renejeschke.de

This commit is contained in:
Souls-R
2024-08-13 19:42:31 +08:00
parent 65b4223002
commit 44310e8c42
9 changed files with 32 additions and 32 deletions

View File

@@ -136,7 +136,7 @@ Be careful parts of head_64.S assume startup_32 is at address 0.
好了,现在我们知道我们在哪里了,接下来就是深入 `startup_32` 函数的最佳时机。
`startup_32` 函数的开始,我们可以看到 `cld` 指令将[标志寄存器](http://baike.baidu.com/view/1845107.htm)的 `DF` (方向标志)位清空。当方向标志被清空,所有的串操作指令像[stos](http://x86.renejeschke.de/html/file_module_x86_id_306.html) [scas](http://x86.renejeschke.de/html/file_module_x86_id_287.html)等等将会增加索引寄存器 `esi` 或者 `edi` 的值。我们需要清空方向标志是因为接下来我们会使用汇编的串操作指令来做为页表腾出空间等工作。
`startup_32` 函数的开始,我们可以看到 `cld` 指令将[标志寄存器](http://baike.baidu.com/view/1845107.htm)的 `DF` (方向标志)位清空。当方向标志被清空,所有的串操作指令像[stos](https://x86.hust.openatom.club/html/file_module_x86_id_306.html) [scas](https://x86.hust.openatom.club/html/file_module_x86_id_287.html)等等将会增加索引寄存器 `esi` 或者 `edi` 的值。我们需要清空方向标志是因为接下来我们会使用汇编的串操作指令来做为页表腾出空间等工作。
在我们清空 `DF` 标志后,下一步就是从内核加载头中的 `loadflags` 字段来检查 `KEEP_SEGMENTS` 标志。你是否还记得在本书的[最初一节](linux-bootstrap-1.md),我们已经看到过 `loadflags` 。在那里我们检查了 `CAN_USE_HEAP` 标记以使用堆。现在我们需要检查 `KEEP_SEGMENTS` 标记。这些标记在 linux 的[引导协议](https://www.kernel.org/doc/Documentation/x86/boot.txt)文档中有描述:

View File

@@ -73,7 +73,7 @@ unsigned long my_bitmap[1];
我认为没有必要解释这些函数的作用。从它们的名字来看,这已经很清楚了。让我们直接查看它们的实现。如果你浏览 [arch/x86/include/asm/bitops.h](https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/bitops.h) 头文件,你将会注意到这些函数中的每一个都有[原子性](https://en.wikipedia.org/wiki/Linearizability)和非原子性两种变体。在我们开始深入这些函数的实现之前首先我们必须了解一些有关原子atomic操作的知识。
简而言之,原子操作保证两个或以上的操作不会并发地执行同一数据。`x86` 体系结构提供了一系列原子指令,例如, [xchg](http://x86.renejeschke.de/html/file_module_x86_id_328.html)、[cmpxchg](http://x86.renejeschke.de/html/file_module_x86_id_41.html) 等指令。除了原子指令,一些非原子指令可以在 [lock](http://x86.renejeschke.de/html/file_module_x86_id_159.html) 指令的帮助下具有原子性。现在你已经对原子操作有了足够的了解,我们可以接着探讨 `set_bit``clear_bit` 函数的实现。
简而言之,原子操作保证两个或以上的操作不会并发地执行同一数据。`x86` 体系结构提供了一系列原子指令,例如, [xchg](https://x86.hust.openatom.club/html/file_module_x86_id_328.html)、[cmpxchg](https://x86.hust.openatom.club/html/file_module_x86_id_41.html) 等指令。除了原子指令,一些非原子指令可以在 [lock](https://x86.hust.openatom.club/html/file_module_x86_id_159.html) 指令的帮助下具有原子性。现在你已经对原子操作有了足够的了解,我们可以接着探讨 `set_bit``clear_bit` 函数的实现。
我们先考虑函数的非原子性non-atomic变体。非原子性的 `set_bit``clear_bit` 的名字以双下划线开始。正如我们所知道的,所有这些函数都定义于 [arch/x86/include/asm/bitops.h](https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/bitops.h) 头文件,并且第一个函数就是 `__set_bit`:
@@ -89,7 +89,7 @@ static inline void __set_bit(long nr, volatile unsigned long *addr)
* `nr` - 位数组中的位号LCTT 译注:从 0开始
* `addr` - 我们需要置位的位数组地址
注意,`addr` 参数使用 `volatile` 关键字定义,以告诉编译器给定地址指向的变量可能会被修改。 `__set_bit` 的实现相当简单。正如我们所看到的,它仅包含一行[内联汇编代码](https://en.wikipedia.org/wiki/Inline_assembler)。在我们的例子中,我们使用 [bts](http://x86.renejeschke.de/html/file_module_x86_id_25.html) 指令,从位数组中选出一个第一操作数(我们的例子中的 `nr`)所指定的位,存储选出的位的值到 [CF](https://en.wikipedia.org/wiki/FLAGS_register) 标志寄存器并设置该位LCTT 译注:即 `nr` 指定的位置为 1
注意,`addr` 参数使用 `volatile` 关键字定义,以告诉编译器给定地址指向的变量可能会被修改。 `__set_bit` 的实现相当简单。正如我们所看到的,它仅包含一行[内联汇编代码](https://en.wikipedia.org/wiki/Inline_assembler)。在我们的例子中,我们使用 [bts](https://x86.hust.openatom.club/html/file_module_x86_id_25.html) 指令,从位数组中选出一个第一操作数(我们的例子中的 `nr`)所指定的位,存储选出的位的值到 [CF](https://en.wikipedia.org/wiki/FLAGS_register) 标志寄存器并设置该位LCTT 译注:即 `nr` 指定的位置为 1
注意,我们了解了 `nr` 的用法,但这里还有一个参数 `addr` 呢!你或许已经猜到秘密就在 `ADDR``ADDR` 是一个定义在同一个头文件中的宏,它展开为一个包含给定地址和 `+m` 约束的字符串:
@@ -171,7 +171,7 @@ set_bit(long nr, volatile unsigned long *addr)
`第 9 位` 将会被置位。LCTT 译注:这里的 9 是从 0 开始计数的比如0010按照作者的意思其中的 1 是第 1 位)
注意,所有这些操作使用 `LOCK_PREFIX` 标记,其展开为 [lock](http://x86.renejeschke.de/html/file_module_x86_id_159.html) 指令,保证该操作的原子性。
注意,所有这些操作使用 `LOCK_PREFIX` 标记,其展开为 [lock](https://x86.hust.openatom.club/html/file_module_x86_id_159.html) 指令,保证该操作的原子性。
正如我们所知,除了 `set_bit``__set_bit` 操作之外Linux 内核还提供了两个功能相反的函数,在原子性和非原子性的上下文中清位。它们是 `clear_bit``__clear_bit`。这两个函数都定义于同一个[头文件](https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/bitops.h) 并且使用相同的参数集合。不仅参数相似,一般而言,这些函数与 `set_bit``__set_bit` 也非常相似。让我们查看非原子性 `__clear_bit` 的实现吧:
@@ -182,7 +182,7 @@ static inline void __clear_bit(long nr, volatile unsigned long *addr)
}
```
没错,正如我们所见,`__clear_bit` 使用相同的参数集合,并包含极其相似的内联汇编代码块。它只是使用 [btr](http://x86.renejeschke.de/html/file_module_x86_id_24.html) 指令替换了 `bts`。正如我们从函数名所理解的一样,通过给定地址,它清除了给定的位。`btr` 指令表现得像 `bts`LCTT 译注:原文这里为 btr可能为笔误修正为 bts。该指令选出第一操作数所指定的位存储它的值到 `CF` 标志寄存器,并且清除第二操作数指定的位数组中的对应位。
没错,正如我们所见,`__clear_bit` 使用相同的参数集合,并包含极其相似的内联汇编代码块。它只是使用 [btr](https://x86.hust.openatom.club/html/file_module_x86_id_24.html) 指令替换了 `bts`。正如我们从函数名所理解的一样,通过给定地址,它清除了给定的位。`btr` 指令表现得像 `bts`LCTT 译注:原文这里为 btr可能为笔误修正为 bts。该指令选出第一操作数所指定的位存储它的值到 `CF` 标志寄存器,并且清除第二操作数指定的位数组中的对应位。
`__clear_bit` 的原子性变体为 `clear_bit`
@@ -231,7 +231,7 @@ static inline int variable_test_bit(long nr, volatile const unsigned long *addr)
}
```
`variable_test_bit` 函数使用了与 `set_bit` 及其他函数使用的相似的参数集合。我们也可以看到执行 [bt](http://x86.renejeschke.de/html/file_module_x86_id_22.html) 和 [sbb](http://x86.renejeschke.de/html/file_module_x86_id_286.html) 指令的内联汇编代码。`bt` (或称 `bit test`)指令从第二操作数指定的位数组选出第一操作数指定的一个指定位,并且将该位的值存进标志寄存器的 [CF](https://en.wikipedia.org/wiki/FLAGS_register) 位。第二个指令 `sbb` 从第二操作数中减去第一操作数,再减去 `CF` 的值。因此,这里将一个从给定位数组中的给定位号的值写进标志寄存器的 `CF` 位,并且执行 `sbb` 指令计算: `00000000 - CF`,并将结果写进 `oldbit` 变量。
`variable_test_bit` 函数使用了与 `set_bit` 及其他函数使用的相似的参数集合。我们也可以看到执行 [bt](https://x86.hust.openatom.club/html/file_module_x86_id_22.html) 和 [sbb](https://x86.hust.openatom.club/html/file_module_x86_id_286.html) 指令的内联汇编代码。`bt` (或称 `bit test`)指令从第二操作数指定的位数组选出第一操作数指定的一个指定位,并且将该位的值存进标志寄存器的 [CF](https://en.wikipedia.org/wiki/FLAGS_register) 位。第二个指令 `sbb` 从第二操作数中减去第一操作数,再减去 `CF` 的值。因此,这里将一个从给定位数组中的给定位号的值写进标志寄存器的 `CF` 位,并且执行 `sbb` 指令计算: `00000000 - CF`,并将结果写进 `oldbit` 变量。
`constant_test_bit` 函数做了和我们在 `set_bit` 所看到的一样的事:
@@ -259,7 +259,7 @@ static inline void __change_bit(long nr, volatile unsigned long *addr)
}
```
相当简单,不是吗? `__change_bit` 的实现和 `__set_bit` 一样,只是我们使用 [btc](http://x86.renejeschke.de/html/file_module_x86_id_23.html) 替换 `bts` 指令而已。 该指令从一个给定位数组中选出一个给定位,将该为位的值存进 `CF` 并使用求反操作改变它的值,因此值为 `1` 的位将变为 `0`,反之亦然:
相当简单,不是吗? `__change_bit` 的实现和 `__set_bit` 一样,只是我们使用 [btc](https://x86.hust.openatom.club/html/file_module_x86_id_23.html) 替换 `bts` 指令而已。 该指令从一个给定位数组中选出一个给定位,将该为位的值存进 `CF` 并使用求反操作改变它的值,因此值为 `1` 的位将变为 `0`,反之亦然:
```python
>>> int(not 1)
@@ -373,14 +373,14 @@ static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
* [IRQs](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29)
* [API](https://en.wikipedia.org/wiki/Application_programming_interface)
* [atomic operations](https://en.wikipedia.org/wiki/Linearizability)
* [xchg instruction](http://x86.renejeschke.de/html/file_module_x86_id_328.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)
* [bts instruction](http://x86.renejeschke.de/html/file_module_x86_id_25.html)
* [btr instruction](http://x86.renejeschke.de/html/file_module_x86_id_24.html)
* [bt instruction](http://x86.renejeschke.de/html/file_module_x86_id_22.html)
* [sbb instruction](http://x86.renejeschke.de/html/file_module_x86_id_286.html)
* [btc instruction](http://x86.renejeschke.de/html/file_module_x86_id_23.html)
* [xchg instruction](https://x86.hust.openatom.club/html/file_module_x86_id_328.html)
* [cmpxchg instruction](https://x86.hust.openatom.club/html/file_module_x86_id_41.html)
* [lock instruction](https://x86.hust.openatom.club/html/file_module_x86_id_159.html)
* [bts instruction](https://x86.hust.openatom.club/html/file_module_x86_id_25.html)
* [btr instruction](https://x86.hust.openatom.club/html/file_module_x86_id_24.html)
* [bt instruction](https://x86.hust.openatom.club/html/file_module_x86_id_22.html)
* [sbb instruction](https://x86.hust.openatom.club/html/file_module_x86_id_286.html)
* [btc instruction](https://x86.hust.openatom.club/html/file_module_x86_id_23.html)
* [man memcpy](https://man7.org/linux/man-pages/man3/memcpy.3.html)
* [man memset](https://man7.org/linux/man-pages/man3/memset.3.html)
* [CF](https://en.wikipedia.org/wiki/FLAGS_register)

View File

@@ -234,7 +234,7 @@ set_intr_gate(X86_TRAP_NM, device_not_available);
Here we can see:
* `#OF` or `Overflow` exception. This exception indicates that an overflow trap occurred when an special [INTO](http://x86.renejeschke.de/html/file_module_x86_id_142.html) instruction was executed;
* `#OF` or `Overflow` exception. This exception indicates that an overflow trap occurred when an special [INTO](https://x86.hust.openatom.club/html/file_module_x86_id_142.html) instruction was executed;
* `#BR` or `BOUND Range exceeded` exception. This exception indicates that a `BOUND-range-exceed` fault occurred when a [BOUND](http://pdos.csail.mit.edu/6.828/2005/readings/i386/BOUND.htm) instruction was executed;
* `#UD` or `Invalid Opcode` exception. Occurs when a processor attempted to execute invalid or reserved [opcode](https://en.wikipedia.org/?title=Opcode), processor attempted to execute instruction with invalid operand(s) and etc;
* `#NM` or `Device Not Available` exception. Occurs when the processor tries to execute `x87 FPU` floating point instruction while `EM` flag in the [control register](https://en.wikipedia.org/wiki/Control_register#CR0) `cr0` was set.
@@ -452,7 +452,7 @@ Links
* [Fix-Mapped Addresses and ioremap](https://0xax.gitbook.io/linux-insides/summary/mm/linux-mm-2)
* [Extended Industry Standard Architecture](https://en.wikipedia.org/wiki/Extended_Industry_Standard_Architecture)
* [INT isntruction](https://en.wikipedia.org/wiki/INT_%28x86_instruction%29)
* [INTO](http://x86.renejeschke.de/html/file_module_x86_id_142.html)
* [INTO](https://x86.hust.openatom.club/html/file_module_x86_id_142.html)
* [BOUND](http://pdos.csail.mit.edu/6.828/2005/readings/i386/BOUND.htm)
* [opcode](https://en.wikipedia.org/?title=Opcode)
* [control register](https://en.wikipedia.org/wiki/Control_register#CR0)

View File

@@ -37,7 +37,7 @@ END(\sym)
.endm
```
After an exception handler will finish its work, the `idtentry` macro restores stack and general purpose registers of an interrupted task and executes [iret](http://x86.renejeschke.de/html/file_module_x86_id_145.html) instruction:
After an exception handler will finish its work, the `idtentry` macro restores stack and general purpose registers of an interrupted task and executes [iret](https://x86.hust.openatom.club/html/file_module_x86_id_145.html) instruction:
```assembly
ENTRY(paranoid_exit)
@@ -473,7 +473,7 @@ Links
--------------------------------------------------------------------------------
* [Interrupt descriptor Table](https://en.wikipedia.org/wiki/Interrupt_descriptor_table)
* [iret instruction](http://x86.renejeschke.de/html/file_module_x86_id_145.html)
* [iret instruction](https://x86.hust.openatom.club/html/file_module_x86_id_145.html)
* [GCC macro Concatenation](https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html#Concatenation)
* [kernel panic](https://en.wikipedia.org/wiki/Kernel_panic)
* [kernel oops](https://en.wikipedia.org/wiki/Linux_kernel_oops)

View File

@@ -356,7 +356,7 @@ out:
#define __TICKET_LOCK_INC 1
```
`inc``lock->tickets` 的下一行执行 [xadd](http://x86.renejeschke.de/html/file_module_x86_id_327.html) 操作。这个操作之后 `inc`将存储给定`标签 (tickets)` 的值,然后 `tickets.tail` 将增加 `inc``1``尾部`值增加 `1` 意味着一个程序开始尝试持有锁。下一步做检查,检查`头部``尾部`是否有相同的值。如果值相等,这意味着没有程序持有锁并且我们去到了 `out` 标签。在 `arch_spin_lock` 函数的最后,我们可能了解了 `barrier` 宏表示 `屏障指令 (barrier instruction)`,该指令保证了编译器将不更改进入内存操作的顺序(更多关于内存屏障的知识可以阅读内核[文档 (documentation)](https://www.kernel.org/doc/Documentation/memory-barriers.txt))。
`inc``lock->tickets` 的下一行执行 [xadd](https://x86.hust.openatom.club/html/file_module_x86_id_327.html) 操作。这个操作之后 `inc`将存储给定`标签 (tickets)` 的值,然后 `tickets.tail` 将增加 `inc``1``尾部`值增加 `1` 意味着一个程序开始尝试持有锁。下一步做检查,检查`头部``尾部`是否有相同的值。如果值相等,这意味着没有程序持有锁并且我们去到了 `out` 标签。在 `arch_spin_lock` 函数的最后,我们可能了解了 `barrier` 宏表示 `屏障指令 (barrier instruction)`,该指令保证了编译器将不更改进入内存操作的顺序(更多关于内存屏障的知识可以阅读内核[文档 (documentation)](https://www.kernel.org/doc/Documentation/memory-barriers.txt))。
如果前一个程序持有锁而第二个程序开始执行 `arch_spin_lock` 函数,那么 `头部`将不会`等于``尾部`,因为`尾部``头部``1`。这样,程序将循环发生。在每次循坏迭代的时候`头部``尾部`的值进行比较。如果值不相等,`cpu_relax` ,也就是 [NOP](https://en.wikipedia.org/wiki/NOP) 指令将会被调用:
@@ -419,7 +419,7 @@ head | 7 | - - - | 7 | tail
* [Preemption](https://en.wikipedia.org/wiki/Preemption_%28computing%29)
* [Linux kernel lock validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
* [Sparse](https://en.wikipedia.org/wiki/Sparse)
* [xadd instruction](http://x86.renejeschke.de/html/file_module_x86_id_327.html)
* [xadd instruction](https://x86.hust.openatom.club/html/file_module_x86_id_327.html)
* [NOP](https://en.wikipedia.org/wiki/NOP)
* [Memory barriers](https://www.kernel.org/doc/Documentation/memory-barriers.txt)
* [Previous chapter](/Timers/)

View File

@@ -268,7 +268,7 @@ static __always_inline void queued_spin_lock(struct qspinlock *lock)
}
```
看起来很简单,除了 `queued_spin_lock_slowpath` 函数,我们可能发现它只有一个参数。在我们的例子中这个参数代表 `队列自旋锁` 被上锁。让我们考虑`队列`锁为空,现在第一个线程想要获取锁的情况。正如我们可能了解的 `queued_spin_lock` 函数从调用 `atomic_cmpxchg_acquire` 宏开始。就像你们可能从宏的名字猜到的那样,它执行原子的 [CMPXCHG](http://x86.renejeschke.de/html/file_module_x86_id_41.html) 指令,使用第一个参数(当前给定自旋锁的状态)比较第二个参数(在我们的例子为零)的值,如果他们相等,那么第二个参数在存储位置保存 `_Q_LOCKED_VAL` 的值,该存储位置通过 `&lock->val` 指向并且返回这个存储位置的初始值。
看起来很简单,除了 `queued_spin_lock_slowpath` 函数,我们可能发现它只有一个参数。在我们的例子中这个参数代表 `队列自旋锁` 被上锁。让我们考虑`队列`锁为空,现在第一个线程想要获取锁的情况。正如我们可能了解的 `queued_spin_lock` 函数从调用 `atomic_cmpxchg_acquire` 宏开始。就像你们可能从宏的名字猜到的那样,它执行原子的 [CMPXCHG](https://x86.hust.openatom.club/html/file_module_x86_id_41.html) 指令,使用第一个参数(当前给定自旋锁的状态)比较第二个参数(在我们的例子为零)的值,如果他们相等,那么第二个参数在存储位置保存 `_Q_LOCKED_VAL` 的值,该存储位置通过 `&lock->val` 指向并且返回这个存储位置的初始值。
`atomic_cmpxchg_acquire` 宏定义在 [include/linux/atomic.h](https://github.com/torvalds/linux/blob/master/include/linux/atomic.h) 头文件中并且扩展了 `atomic_cmpxchg` 函数的调用:
@@ -294,7 +294,7 @@ static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new)
__raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
```
就像我们可能了解的那样,`cmpxchg` 宏使用几乎相同的参数集合扩展了 `__cpmxchg` 宏。新添加的参数是原子值的大小。`__cpmxchg` 宏添加了 `LOCK_PREFIX`,还扩展了 `__raw_cmpxchg` 宏中 `LOCK_PREFIX`的 [LOCK](http://x86.renejeschke.de/html/file_module_x86_id_159.html)指令。毕竟 `__raw_cmpxchg` 对我们来说做了所有的的工作:
就像我们可能了解的那样,`cmpxchg` 宏使用几乎相同的参数集合扩展了 `__cpmxchg` 宏。新添加的参数是原子值的大小。`__cpmxchg` 宏添加了 `LOCK_PREFIX`,还扩展了 `__raw_cmpxchg` 宏中 `LOCK_PREFIX`的 [LOCK](https://x86.hust.openatom.club/html/file_module_x86_id_159.html)指令。毕竟 `__raw_cmpxchg` 对我们来说做了所有的的工作:
```C
#define __raw_cmpxchg(ptr, old, new, size, lock) \
@@ -475,8 +475,8 @@ smp_cond_acquire(!((val = atomic_read(&lock->val)) & _Q_LOCKED_PENDING_MASK));
* [MCS](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf)
* [per-cpu variables](/Concepts/linux-cpu-1.md)
* [atomic instruction](https://en.wikipedia.org/wiki/Linearizability)
* [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)
* [CMPXCHG instruction](https://x86.hust.openatom.club/html/file_module_x86_id_41.html)
* [LOCK instruction](https://x86.hust.openatom.club/html/file_module_x86_id_159.html)
* [NOP instruction](https://en.wikipedia.org/wiki/NOP)
* [PREFETCHW instruction](https://www.felixcloutier.com/x86/PREFETCHW.html)
* [x86_64](https://en.wikipedia.org/wiki/X86-64)

View File

@@ -192,7 +192,7 @@ asm_volatile_goto(LOCK_PREFIX " decl %0\n"
#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0)
```
第一个汇编包含 `goto` 特性,而第二个空的内联汇编是 [屏障 (barrier)](https://en.wikipedia.org/wiki/Memory_barrier)。现在回去看看我们的内联汇编。正如我们所看到的,它从被 `LOCK前缀` 的宏定义开始,该宏仅是扩展 [lock](http://x86.renejeschke.de/html/file_module_x86_id_159.html) 指令:
第一个汇编包含 `goto` 特性,而第二个空的内联汇编是 [屏障 (barrier)](https://en.wikipedia.org/wiki/Memory_barrier)。现在回去看看我们的内联汇编。正如我们所看到的,它从被 `LOCK前缀` 的宏定义开始,该宏仅是扩展 [lock](https://x86.hust.openatom.club/html/file_module_x86_id_159.html) 指令:
```C
#define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
@@ -430,7 +430,7 @@ if (!list_empty(&lock->wait_list)) {
* [x86_64](https://en.wikipedia.org/wiki/X86-64)
* [Inline assembly](/Theory/linux-theory-3.md)
* [Memory barrier](https://en.wikipedia.org/wiki/Memory_barrier)
* [Lock instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html)
* [Lock instruction](https://x86.hust.openatom.club/html/file_module_x86_id_159.html)
* [JNS instruction](http://unixwiz.net/techtips/x86-jumps.html)
* [preemption](https://en.wikipedia.org/wiki/Preemption_%28computing%29)
* [Unix signals](https://en.wikipedia.org/wiki/Unix_signal)

View File

@@ -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](/Theory/linux-theory-3.md) 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](/Theory/linux-theory-3.md) 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](https://x86.hust.openatom.club/html/file_module_x86_id_159.html) instruction as we already know. The next [xadd](https://x86.hust.openatom.club/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
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
@@ -428,6 +428,6 @@ Links
* [Linux kernel lock validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
* [Atomic operations](https://en.wikipedia.org/wiki/Linearizability)
* [Inline assembly](/Theory/linux-theory-3.md)
* [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)
* [XADD instruction](https://x86.hust.openatom.club/html/file_module_x86_id_327.html)
* [LOCK instruction](https://x86.hust.openatom.club/html/file_module_x86_id_159.html)
* [Previous part](/Syncprim/linux-sync-4.md)

View File

@@ -110,7 +110,7 @@ $ gcc test.c -o test
a + b = 15
```
Ok, great. It works. Now let's look at this example in detail. Here we see a simple `C` program which calculates the sum of two variables placing the result into the `sum` variable and in the end we print the result. This example consists of three parts. The first is the assembly statement with the [add](http://x86.renejeschke.de/html/file_module_x86_id_5.html) instruction. It adds the value of the source operand together with the value of the destination operand and stores the result in the destination operand. In our case:
Ok, great. It works. Now let's look at this example in detail. Here we see a simple `C` program which calculates the sum of two variables placing the result into the `sum` variable and in the end we print the result. This example consists of three parts. The first is the assembly statement with the [add](https://x86.hust.openatom.club/html/file_module_x86_id_5.html) instruction. It adds the value of the source operand together with the value of the destination operand and stores the result in the destination operand. In our case:
```assembly
addq %1, %2
@@ -469,7 +469,7 @@ Links
* [GNU extension](https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html)
* [Global Descriptor Table](https://en.wikipedia.org/wiki/Global_Descriptor_Table)
* [Processor registers](https://en.wikipedia.org/wiki/Processor_register)
* [add instruction](http://x86.renejeschke.de/html/file_module_x86_id_5.html)
* [add instruction](https://x86.hust.openatom.club/html/file_module_x86_id_5.html)
* [flags register](https://en.wikipedia.org/wiki/FLAGS_register)
* [x86_64](https://en.wikipedia.org/wiki/X86-64)
* [constraints](https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints)